TowardsDataScience-博客中文翻译-2020-八十一-
TowardsDataScience 博客中文翻译 2020(八十一)
为 MAPE 疯狂?
或者使用哪些预测准确性指标?

在新冠肺炎疫情期间,世界各地的许多 CPG 品牌将专注于记录他们的销售和需求数字。在我的上一篇文章中,我谈到了在这些测试时期做营销组合建模的要点。
这些品牌可能已经预测了 2020 年前 3-4 个月的销售或需求。但他们的预测可能遗漏了新冠肺炎的影响。
随着销量的增长被许多品牌报道,预测的销量将会大大偏离目标,并且预测的销量将会与实际情况有巨大的差异。
这种情况要求检验模型的预测准确性。
在本文中,我将讨论不同的预测准确性指标,以及如何评估这些预测准确性指标中哪一个是理想的选择。
让我们从这些指标的简要概述开始:
- MAD/MAE: 通过从预测销售额中减去实际销售额来计算。然后将误差项转换为绝对误差,并计算整个时间序列的绝对误差平均值。

这种预测测量取决于尺度,误差项也具有与数据相同的单位。例如,如果销售量以千克为单位,那么误差项也将以千克为单位。
这种方法不能用于在具有不同单位的时间序列之间进行比较,例如销售量(千克)误差不能与销售额(美元)进行比较。
这种精度测量的缺点是它平均了整个系列的误差,不能给出非常精确的结果。
当销售额为 2000 时,500 个单位的误差可能看起来很大,但是如果实际销售额为 20,000,同样的误差可能很小。
2。RMSE: 均方根误差是平均平方误差的平方根。

像 MAE 一样,这种方法依赖于尺度,不能用来比较不同尺度上的序列。并且误差项也具有与数据相同的单位。
3。MAPE: 平均绝对百分比误差是检验预测准确性最广泛使用的方法。它属于与尺度无关的百分比误差,可用于比较不同尺度上的序列。

其中,eᵢ是误差项,yᵢ是时间 I 的实际数据
MAPE 的缺点是,对于数据中的任何观察值,如果实际数值为 0,它就变得不确定。
4。MASE: 平均绝对标度误差是无标度误差。
基本上,MASE 只不过是测试数据的 MAE 除以在训练集上使用一步简单预测方法的 MAE 的比值。

在哪里,

这里,Q 是根据训练数据计算的简单预测。MAE 是根据测试数据计算的,而 Q 是根据训练数据计算的。
如果 MASE 小于 1,这意味着在训练数据上预测优于一步朴素方法。如果它大于 1,则意味着该预测方法比在训练数据上使用一步简单预测方法的预测差。
为了更好地理解这一点,下面是正确解释该公式的几个链接:
在链接的博客文章中,Rob Hyndman 呼吁参加旅游预测竞赛。本质上…
stats.stackexchange.com](https://stats.stackexchange.com/questions/124365/interpretation-of-mean-absolute-scaled-error-mase)
https://robjhyndman.com/papers/foresight.pdf
现在我们已经介绍了误差指标,让我们来看看这些预测指标在哪些方面做得更好或更差。
场景 1:预测与实际相差很大

新冠肺炎之前被视为训练数据,新冠肺炎之后(3 月 20 日至 2020 年 5 月)被视为测试数据。

在这种情况下,MAPE 可以作为一个很好的准确性措施,因为它是独立的规模,可用于比较不同的序列或预测场景。
场景 2:实际值骤降为零
下图没有让你想起最近的新闻吗?….如果你猜是“原油”,那你就猜对了!!


在这种情况下,不幸的是,实际价格暴跌至零(非常意外的情况)。这种情况对于原油等行业来说是真实的,西德克萨斯中质油(WTI)价格基准暴跌至负,对于汽车行业来说也是如此,最近几个月的销售额为零。
对于这种情况,MAPE 不是一个好的衡量标准,因为它变得不确定。
MAE 或 RMSE 可以用来比较这里的预测准确性。MASE 似乎也不是一个好的 KPI,因为它大于 1。当 MASE 大于 1 时,意味着用于预测的方法比所用的原始方法更差。
场景 3:理想场景(回到正常场景)


在这种情况下,没有新冠肺炎的干涉(哦,我们多么希望那些正常的日子)。模特们表现正常。在这种情况下,可以使用任何措施。
参考文献:
- https://robjhyndman.com/papers/forecast-accuracy.pdf
- https://robjhyndman.com/papers/foresight.pdf
- https://qz . com/1841668/油价首次为负/
你可以和我联系:
LinkedIn: Ridhima Kumar
推特: @kumar_ridhima
举例说明 Python 中的神奇方法
在我们的类设计中使用魔法方法

图片由克里斯蒂安·埃斯科瓦尔通过 Unsplash 提供
使用魔法改变内置行为
魔术方法是特殊的方法,你可以定义它来给你的类添加“魔术”。它们总是被双下划线包围,例如 init 和 str magic 方法。神奇的方法可以通过让我们访问 Python 的内置语法特性来丰富我们的类设计。
Python 让我们的类从内置类继承。内置的继承子类共享所有相同的属性,包括内置的方法。我们可以利用核心的内置功能,但是通过使用魔法方法来定制选择的操作。
在本教程中,我将把这两个想法结合在一起,展示我们如何从内置列表类和中继承,并在我们的类设计中使用神奇的方法。我将修改控制列表索引的三个神奇方法。通过结合这些特性,我们可以构建一个简单易用的类,并且我们可以给我们想要的方法添加行为。所有 Python 开发人员都熟悉内置行为;反过来,这使得我们的继承类易于学习。
最后,将演示两个更广泛的例子,说明如何在广播操作中使用魔法方法以及如何改变实例的状态。所有附带的代码都可以通过 GitHub 获得。
示例 1:列表索引
可以操纵神奇的方法来修改列表索引。MyCustomList 类继承自内置列表类型。这意味着通过 MyCustomList 类创建的任何对象都将像列表一样工作,除非我们选择有选择地自定义方法。
getitem、setitem 和 delitem 是在我们访问列表索引时调用的神奇方法。这些神奇方法的行为是可以修改的。
在下面的例子中,我们放弃了从第 0 个索引开始的列表索引的想法。如果用户试图使用第零个索引访问列表中的元素,将会引发 ValueError 异常,程序将会终止。如果用户输入一个大于一的列表索引,这些方法会将索引减一,然后用这个索引调用父类列表。
要展示如何使用 MyCustomList 类中定义的这些方法,请参见 Python 交互式提示中的以下内容。

该示例显示了如何调用 getitem、setitem 和 delitem。魔术方法可以被隐式调用。对于 getitem,要访问第一个索引,只需在方括号中写下对象的名称,后跟索引位置。
最有趣的是,当我们请求索引位置 1 的元素时,返回的是整数值 1,尽管 1 是第个第 0 个元素。我们这里有一个列表,它从 1 开始索引。事实上,它弥补了我们第一次学习列表索引时的困惑。
现在,让我们将列表中的整数值 1 改为 100。为此,我们需要调用 setitem。为此,我们只需写下对象的名称,后跟方括号和赋值。再次,为了改变列表中的第一个元素,我们使用索引位置 1。当我们再次输出列表时,我们可以清楚地看到第一个元素从 1 变成了 100。
最后,要从列表中删除一个元素,可以定义 delitem。当我们使用解析为 delitem 方法调用的 del python 关键字时,调用 delitem magic 方法。为了进一步构建我们的列表索引示例,让我们删除索引中的第一个元素,即整数值 100。当我们调用 del 时,后面是对象和我们要删除的元素的索引位置,在这个例子中,是列表 100 中的第一个元素,我们现在可以看到 100 实际上已经被删除了!
神奇的方法提供了修改默认行为的机会。最重要的是,不需要学习新的方法名或新的接口,因此可以直观地实现这些方法。下表给出了使用 MyCustomList 中实现的这些神奇方法的指南。

如何调用神奇的方法,getitem,setitem 和 delitem

示例 2:mul 魔术方法
我们也可以在我们的类设计中使用乘法运算符。因为我们继承了内置的 List 类,所以我们可以将两个 MyCustomList 对象压缩在一起(因为它们的行为类似于 list 对象)并遍历 zip 对象。在迭代过程中,我们可以用广播的方式将每个列表中的元素乘以另一个列表中相应的元素(参见下面的 mul magic method 代码片段)。这种广播行为类似于在数据分析包(如 Pandas 和 Numpy)中发现的行为。
该示例显示,我们可以使用*符号将两个 MyCustomList 对象放在一起。如果我们在一个名为 list_three 的变量中捕获返回值,并打印 list_three,就会输出一个新的列表。这个列表是另外两个列表中的元素相乘的结果。

mul 是 MyCustomList 类中的一个方法。在这里,它是孤立显示的。

乘法运算符*解析为 mul magic 方法调用,我们可以对其进行定制以返回我们想要的行为。
本例中使用的类 MyCustomList 的完整源代码如下所示:
示例奖励:call 魔术方法
最后,我将说明如何调用 Python 中的 call magic 方法。__call__在需要经常改变状态的类中特别有用。“调用”实例可以是改变对象状态的一种直观而优雅的方式。
考虑所示的例子。这里,类 MyClass 有一个 init 构造函数,它期望传递三个参数。这三个参数可以在 init 方法签名中传递,并作为属性分配给对象。
当我们想要改变一个实例的状态,而不需要实际创建一个新的实例时,call magic 方法非常有用。
当实例第一次初始化时,我传入整数 1、2 和 3,它们在实例中分别被赋值为属性 var_1、var_2 和 var_3。当我使用 print 语句显示实例 obj 的输出时,通过使用 dict 属性,我可以看到 var_1 被赋值为 1,var_2 被赋值为 2,var_3 被赋值为 3。
现在,让我们假设我想要更改这个实例的 var_1 和 var_2 属性值,同时保持 var_3 属性与最初构造实例时一样。
做到这一点很简单。我定义了一个调用魔术方法,它允许重新定义 var_1 和 var_2 属性。魔术方法可以隐式调用,这意味着我只需调用 obj(200,300),调用方法就会被调用。当然,也可以显式调用 call 方法,例如 obj。call(200,300),但第一种方法似乎更直观。最后,出于演示的目的,我打印了实例的 id 以明确显示我们操作了同一个对象。

调用方法可以用两种方式定义。参数可以直接传递给调用方法签名。或者,可以使用*vars 参数,它捕获传递的所有参数,并将它们存储在一个元组中,可以像上面所示的那样进行解包。

这个例子的源代码可以在下面找到。
摘要
神奇的方法可以让我们访问核心语法特性,从而丰富我们的类设计。在第一个例子中,我们拥有两个世界的精华。我们可以从内置的 list 类继承,并修改该类中的特定方法来定制行为。getitem、setitem 和 delitem 都被修改了,但是通过继承,我们仍然能够利用列表的内置 init 和 repr()方法。
我们可以非常容易地与其他开发人员交流对象的使用。在提供的例子中,我们需要告诉开发人员的是,我们的类像一个列表,只是有一点不同,这里我们放弃了第零个索引的想法。不需要学习新的方法名或新的接口。
此外,还演示了调用魔术的方法。调用实例可以是改变对象状态的一种直观而优雅的方式。
通过小代码片段实现 Python 中的神奇方法
了解如何使用神奇的方法来丰富您的代码设计

图片由 Artem Maltsev 通过 Unsplash 提供
Python 中的 Magic/Dunder 方法
Magic 或 dunder 方法是内置的方法,在一个类具体化后,用户可以自动使用。神奇的方法通常在方法名的两边都有双下划线。大家都知道最基本的魔法方法,__init__。这是我们定义对象初始化行为的方式。然而,还有更多神奇的方法。要找到您可用的神奇方法的目录,只需在您的类名上运行内置的 Python 函数dir()。
这里,当dir()函数在两个内置类dict和list.上运行时,属性目录,包括魔法方法,作为一个列表输出
为了帮助用户更好地理解魔术方法,我创建了一个简短的以示例为导向的指南,详细介绍了如何操作内置魔术方法的标准默认行为来选择有用的魔术方法。
然而,贯穿始终的例子都带有警告。如果您修改了一个神奇方法的行为,并且将您的代码打包到一个模块中供其他程序员使用,他们可能会合理地期待神奇方法的默认行为。因此,我的建议是,如果任何方法的默认行为被覆盖了,就要让受众清楚明白。
本教程的目的是提供一些简短的例子,说明如何有选择地定制魔术方法。给出的例子故意很短,以帮助展示内部工作原理。
餐馆类和魔术方法
1.__ 添加 _ _(自己,其他)
首先,我将创建一个基于餐馆的虚构示例。在这个例子中,我有一个类,用户可以将工作日的收入作为列表传递给 init 构造函数。传递的列表被设置为对象中的一个属性。
假设我们在两个城市有两家餐馆,我们想知道周一到周五每天的总收入。通过重写神奇的方法__add__(self, other),我们可以很容易地在我们的类中实现这种行为。
在 magic add 方法中,我们执行一个列表理解,其中我们将两个列表压缩在一起,迭代现在压缩的列表,并对压缩的元素求和以产生一周中每一天的单个数字整数。列表理解被分配给变量 retval。最后,该方法可以返回一个餐馆对象,并传递这个新列表(retval)。
为了得到我们想要的输出,我们现在必须实现另一个神奇的方法,即__str__(self)方法。此方法获取列表属性并将其返回。当 str 方法被调用时,这是我们打印一个对象时所发生的,新的列表将被显示,如下面的代码片段所示。
为了便于理解,当我们使用加号运算符时,对 add 方法的调用是在这里进行的__add__(self, other)., self 和 other 都表示餐馆类的对象。下面的例子很好地说明了这一点。我们可以显式调用 add 方法,如第 4 行所示,但是这似乎不太“神奇”。
2.iadd(自己,其他)
iadd method 方法也可以在 Restaurants 类中实现。为了演示 iadd 的用法,我们假设在同一个城市中有两家餐馆,我们希望这两家餐馆的收入是一个单一的数字整数。
我们可以重写 iadd 方法。我们可以使用内置的 Python sum 函数对两家餐馆第 1 周的条目求和,并将结果保存在名为 retval 的变量中,然后可以返回该变量。
现在,当我们在对象上调用赋值操作“+=时,这个调用将解析为方法调用 iadd。对于这个例子,可能有更简单的方法来获得所请求的答案,但是我想演示 iadd 方法的工作原理。
3.getitem(self,key)
我们还可以在餐馆类中定制索引。假设我们希望有两种情况,用户可以使用我们在对象创建时传递的列表的标准索引来索引工作日的收入,或者选择通过键入工作日的名称来索引工作日的晚上,以检索当天的收入。
为此,我们可以为 getitem 方法定义自定义行为。当一个容器被索引时,这个方法被调用。在 getitem 方法中,定义了一个字典,将一周中的日期作为键,将值作为相应的数字整数。
当 getitem 被调用时(这发生在我们索引我们的对象时,如图所示),如果传入的星期几与 weekday_dict 中的任何键匹配,我们从提供的 weekday 键中检索值。这将返回一个数字整数,可用于索引我们的原始收入列表。
如图所示,我们可以用“星期一”索引 wk1_city_1,并得到值 10。我们还可以选择通过包含所示的 else 语句来保留原始的索引方法。这样,我们通过多种索引方式为我们的类引入了更大的灵活性。
4.ge(自己,别人)和 le(自己,别人)
我们还可以在我们的类设计中实现大于或等于和小于或等于魔术方法。假设我们想确定城市 1 和城市 2 中哪家餐馆在收入方面表现更好。我们可以通过实现以下返回布尔值的方法来实现这一点:
__ge__(self, other)
定义大于或等于运算符>=的行为。
__le__(self, other)
定义小于或等于运算符<=的行为。
当我们使用这些操作符时,它们解析到相应的、ge/le 的魔法方法调用。
现在,我们可以在对象上使用大于、小于或等于运算符。如图所示,当对 wk1_city_2 调用操作符>=时,wk1_city_1 返回一个布尔值 False。
相等运算符==, __eq__(self, other)、不相等运算符!=, __ne__(self, other)以及小于运算符<, __lt__(self, other)和大于运算符>,__gt__(self, other)的工作方式与此处所示的示例完全相同。
5.setattr(自身,关键字,值)
当在对象中设置属性时,可以实现自定义行为。在我们在本教程中一直使用的虚构的餐馆示例中,我们合并到类中的神奇方法依赖于一个被传递并设置为对象中的属性的列表。此外,我们希望列表中的所有元素都是数字整数。这两个条件可以在神奇的 setattr 方法中定义。
首先,我们检查在 setattr 方法中传递给 value 参数的实参是否是一个使用内置 isinstance 方法的列表。如果用户传入任何其他对象,将引发一个 TypeError 异常,并用一条有用的消息通知用户打算如何使用该类。接下来,我们可以遍历列表,确保每个元素实际上都是整数或浮点数。这在衡量餐馆工作日收入的背景下是有意义的。
如果两个条件都满足,我们可以使用以下语法在对象字典中设置属性:
自我。dict[key] =值
如图所示,如果将一个元素(如 20)作为字符串“20”传递,将引发 valueError 异常,并提醒用户预期的输入应该是什么。

请注意如何调用 setattr。在下面的第一个例子中,object.attribute 语法将调用您已经使用的方法。在这种情况下,将会调用一个无限的递归循环。
6.getattr(self,name)
当用户试图访问一个不存在的属性(或者根本不存在,或者还不存在)时,可以调用自定义行为。这对于捕捉和重定向常见的拼写错误非常有用,可以给出关于使用不推荐使用的属性的警告。
这可以通过神奇的方法 getattr 来实现。在该示例中,当用户调用对象上正确命名的属性时,将返回对象属性的值。
如果他们在对象上调用的属性不存在,自定义 getattr 方法可以引发 AttributeError 异常,通知用户可以访问哪些属性。

7.repr(self)
repr 方法定义了在类的实例上调用 repr 时的行为。str 和 repr 魔术方法之间的主要区别在于目标受众。repr 旨在产生机器可读的输出,例如它可以是有效的 Python 代码,而 str 输出旨在是人类可读的。
在没有为 repr 定义自定义行为的情况下,当我们打印对象时,控制台输出通知用户该对象是一个餐馆对象,并用十六进制代码给出内存中的地址。这可以通过定制 repr 来构建更丰富的信息。可以返回类名,后跟列表。打印出来后,如下所示,我们现在有了有效的 Python 代码,相当于我们创建了一个餐馆类的实例。

摘要
魔法方法可以扩展我们类的功能,并且在某些情况下保留现有的默认行为。当使用 getitem 实现自定义行为来索引容器时,就采用了这种方法。
使用魔法方法时,有一点需要注意,用户可能会期望默认行为,所以你必须通过错误消息或自述文件来解释这一点。如果使用得当,魔术方法确实有直观的好处。例如,add 方法给出了用户可能期望的输出。此外,用户不需要学习新的方法名称。
本教程是演示如何使用魔法方法的入门书。这些例子的完整代码可以在这里找到。喜欢在你的类设计中使用魔法方法!
微积分的魔力:线性回归

人类行为拥有异常丰富的知识和技术储备。我们正试图从人脑中了解和产生尽可能多的东西。我觉得操纵人脑的一个突破是数据科学。数据科学是一个故事,是人类大脑、机器和直觉的进化。
为了开始这个故事,数据科学家所做的是用数学的基础来描绘猜测的行为。最基础的代数是从线性代数开始的,所以机器学习最基础的发电站就变成了线性回归。
在这篇文章中,我们将看到线性回归的基本直觉和发展,以及今天我们如何使用线性回归。当我阅读时,我发现它非常有趣,我相信你也会如此。
人类有线性直觉力吗?
这一切都始于观察,如果 1 公斤苹果成本卢比。100 那两公斤苹果要花卢比。200.但是如果我是一个很好的讨价还价者呢?我 100 卢比买了 1 斤,200 卢比买了 2 斤,450 卢比买了 5 斤,那 10 斤要多少钱?实际值可以是任何值,但我们的直觉告诉我们它可能在 Rs 左右。900 左右。
观察很清楚,当我们有一个精确的线性关系时,我们预测一个精确的值,当我们有一组非线性的点时,我们试图得出一个最适合给定点的线性方程。
最合适的,现在这个术语可以有很多意思和解释,有些人从这个术语中什么也看不懂。
“最佳匹配”仅仅意味着良好的直觉。如果我们举一个例子,考虑一组点,我们需要一条穿过大多数点或接近最大点数的线。

对于给定的一组问题,可以使用多行进行预测建模。
我想我们都能说出哪条线“最适合”给定的点集。这是第三个,也是我们的第一个直觉,满足标准— 接近最大点数。
这就是线性回归模型的作用。这是线性回归背后的基本直觉。然后是机器学习在起作用。通过人类的行为,我们可以创造一条生产线,而不是机器,并在这条生产线上改进。
直觉到智力
但是我们需要改进一些东西,那就是所谓的错误。因此,我们建立了一个度量标准来计算误差,然后我们试图将其最小化。简单地说,误差就是实际值和预测值之间的偏移或偏差。误差越小,现实和可预测性之间的偏差就越小。
我们简单地通过估计实际点和预测点之间的垂直差来计算误差。
现在我们可以将所有误差相加,我们可以将绝对误差相加,但我们要做的是找出误差平方和。选择这个错误模型并拒绝其他模型的背后有很多理论。
最基本的理论是矛盾论。每当我们发现一个漏洞或更好的技术,我们修改现有的技术。
考虑误差的总和,如果我们在数据集中有两个大小相同但符号相反的误差,净误差将为零。在这种情况下,我们没有正确估计模型的准确性。因此,我们建议取误差的绝对值,并将它们相加。增加绝对值可能是一个好的选择,但我们有一个更好的选择。
与其他误差分析相比,采用一些平方误差有两个重要的优势,一是不需要采用绝对值,因为它已经被平方了,二是当它表现出色时,即在异常值的情况下,它会惩罚模型。对大误差求平方将导致大的整体误差。
现在我们有了一个误差的度量,其中 y i 是实际值,a0 — a1x i 是输入为 x i 时的预测值,a0 和 a1 是线系数。

平方误差项
是时候改进模型了。我们希望将误差降至最低,误差是线路系数的函数。很简单,差异化。

偏导数最小化误差项
一旦我们得到了微分,我们就使它们等于零,以获得系数的值,从而使误差最小。

当我们把等式等于零时,神奇的事情发生了。所有的微分方程现在都被转换成一个线性方程,它的变量是线的系数。

因此,通过求解这些方程,我们可以获得系数的值,使得误差值最小,或者换句话说,我们获得了最佳拟合线


很少欣赏
这就是我们如何获得最佳拟合线。线性回归背后的数学很简单,但值得一提,因此我称之为数学的魔力。对于更高级的方法来说,这是一个很好的起点,事实上,许多新奇的统计学习技术可以被视为线性回归的扩展。因此,在进入更复杂的方法之前,理解这个简单的模型将建立一个良好的基础。
Sobel 算子的魔力
无监督贝叶斯推理(降低维度和挖掘特征)
使用边缘的低级特征检测

图片由朱利叶斯·德罗斯特在 T2 Unsplash 上拍摄
最后,你们一直在等待的时刻到了,这是我们无监督贝叶斯推理系列的下一步:我们对 Sobel 算子的深入研究。
一种真正神奇的边缘检测算法,它实现了低级特征提取和降维,从本质上降低了图像中的噪声。它在面部识别应用中特别有用。
1968 年 Irwin Sobel 和 Gary Feldman(斯坦福人工智能实验室)的爱子,该算法是许多现代边缘检测技术的灵感。通过在给定图像上卷积两个相对的核或掩模(例如,见左下)(每个都能够检测水平或垂直边缘),我们可以创建一个噪声更小、平滑的表示(见右下)。

图片由作者提供,使用 Scikit-Image 生成
Sobel 算子实现示例由 SciKit-Image 作者修改
作为用于图像强度函数的梯度近似计算的离散微分算子技术,用简单的英语来说,该算法通过对每个像素(锚像素)与其周围像素(基本上近似图像的导数)之间的差异进行微分来检测像素通道值(通常是亮度)的变化。
这导致平滑原始图像并产生较低维度的输出,其中可以更清楚地看到低级几何特征。然后,这些输出可以用作更复杂的分类算法的输入,或者作为通过 KLD(kull back-lei bler Divergence)进行无监督概率聚类的示例(T10)。
那么它是如何工作的呢?
生成低维输出需要我们对图像求导。首先,我们计算 x 和 y 方向的导数。我们创建两个 3×3 的内核(见矩阵),在相应轴的中心有 0,在垂直于中心 0 的中心正方形有 2,在每个角上有 1。每个非零值应该在零的顶部/右侧为正(取决于轴),在相应侧为负。这些内核被命名为 Gx 和 Gy。
这些以下列格式出现:
作者代码
然后,这些核将在我们的图像上进行卷积,将每个核的中心像素放置在图像中的每个像素上。对于每个内核,我们使用矩阵乘法来计算输出图像中新的对应像素的亮度值。因此,我们最终得到两个输出图像(每个笛卡尔方向一个)。
目的是找到图像中的像素和梯度矩阵(核)(Gx 和 Gy)中的所有像素之间的差异/变化。更精确地说,这可以表示为。
旁注:
严格来说我们没有召集任何人。虽然我们喜欢在人工智能和机器学习领域提到“卷积”,但卷积会涉及翻转原始图像。从数学上来说,当我们提到卷积时,我们实际上是在计算输入的每个 3×3 区域和每个像素的掩模之间的互相关。输出图像是遮罩和输入之间的总体协方差。这就是检测边缘的方法。
回到我们的索贝尔解释…
对掩码和输入的 3×3 部分之间的每个矩阵乘法的计算值求和,以产生输出图像中像素的最终值。这将生成一个新图像,该图像包含原始图像中存在的垂直和水平边缘的信息。这是原始图像的几何特征表示。此外,因为该算子保证每次产生相同的输出,所以该技术允许对图像分割任务进行稳定的边缘检测。
根据这些输出,我们可以计算任意给定像素(x,y)处的梯度幅度和梯度方向(使用反正切运算符):
作者代码
由此我们可以确定,那些具有大幅度的像素更可能是图像中的边缘,而方向通知我们关于边缘的方向(尽管方向对于生成我们的输出是不需要的)。
一个简单的实现:
下面是 Sobel 操作符在 python 中的一个简单实现(使用 NumPy ),让您对这个过程有一个大致的了解(对于所有初学编码的人来说)。
作者代码
该实现是 Wikipedia 伪代码示例的 python 变体,旨在展示如何实现该算法,同时演示该过程中的各个步骤。
我们为什么关心?
尽管该算子产生的梯度近似相对粗糙,但它确实提供了一种计算图像的边缘、角和其他几何特征的极其高效的计算方法。反过来,它为许多降维和特征提取技术铺平了道路,如局部二进制模式 ( )有关这种技术的更多详细信息,请参见我的另一篇博客 ) 。
仅依赖几何特征确实有在数据编码过程中丢失重要信息的风险,但是,这种权衡允许数据的快速预处理,进而允许快速训练。因此,这种技术在纹理和几何特征被认为对定义输入非常重要的情况下特别有用。这就是为什么使用 Sobel 算子可以以相对高的准确度完成面部识别。但是,如果试图对使用颜色作为主要区分因素的输入进行分类或分组,这种技术可能不是最佳选择。
在使用其他分类器或用于贝叶斯推理方法之前,这种方法对于获得几何特征的低维表示以及维数和噪声减少的极好起点仍然是非常有效的。
参考资料:
[1] D. Kroon,2009,短文大学特文特,基于核的图像导数的数值优化。
https://en.wikipedia.org/wiki/Sobel_operator
Power BI 中的魔表
您的 Power BI 报告中的表格不需要是老式的枯燥视觉效果。查看如何为用户创建令人惊讶的表格!

桌子,桌子,桌子…爱他们,或者恨他们,我们,Power BI 开发者,离不开他们。我们的用户也是。你有多少次听到你的用户,这样的一句话:嘿,那些图表很酷,这些颜色也很好看……但是,给我表格里我的数据。你知道,我是一个“Excel 人”,喜欢看到我的数据排成行和列 …
这完全没问题——当你收到这样的请求时,不要感到不安。然而,世卫组织说我们必须给我们的用户“正常”的表格。如果我们可以满足他们的要求,但只需要一点创意和魔法,同时将他们的桌面体验提升到一个全新的水平,会怎么样?
把我的桌子给我…
这是一个商业场景。我们有关于通过推荐计划注册我们服务的客户的数据。如果这些客户为我们的服务进行了第一次存款,我们也有数据,因此我们可以轻松跟踪客户注册但没有存款的情况,我们的客户支持部门可以联系他们,检查他们在注册后是否面临任何问题。

在我的例子中,数据来自 Excel 文件,但在现实生活中,它存储在 SQL Server 数据库中。
我们可以在 Power BI 中基于上图中看到的数字创建一系列可视化效果,但是我们的用户很固执,想要他的表。好了,这就对了:

如果你问我,那看起来比在 Excel 中稍微好一点,但是它仍然——丑陋!我的意思是,我们可以对表格应用一些格式并添加一些颜色,但它仍然是一个普通的旧表格。
阿布拉卡达布拉——让这张桌子闪闪发光!
正如我已经提到的,通过一些想象力和创造力,我们可以让这张桌子脱颖而出。所以,我们先给底层数据添加一些逻辑。我将打开超级查询编辑器,在“添加列”选项卡下,我将选择“自定义列”:

然后,由于我们已经学习了电力查询中的一些基本时间操作,我将编写下面的 M 公式来计算今天的日期与客户签约的日期之间的天数:
Duration.TotalDays(Date.From(DateTime.LocalNow())-[Signup Date])
此外,我想计算注册和首次存款之间的天数。这可以通过使用下面的 M 语句来完成:
Duration.TotalDays(Date.From([First Deposit])-[Signup Date])
现在,由于我已经用两个额外的列扩展了我的数据模型,我可以执行一系列不同的计算,例如注册日期和第一次存款日期之间的平均数。此外,我可以在我的报告中使用这些列作为切片器,例如,只检查那些在注册后 3-6 天内没有存款的客户!
现在让我们把重点放在增强我们原来的“丑陋”的表。为了让我们的表格更加“用户友好”,我们需要应用一些特定的格式,包括常规格式和条件格式。
我将首先创建一个列来保存自客户注册以来的天数的文本值:
Signup Text = IF(Signups[Days Signed] = 1,
"1 day ago",
Signups[Days Signed]&" days ago"
)
这个公式将帮助我们处理复数和单数文本定义。我将需要另一个计算列来跟踪客户-如果他存款或没有:
Signup vs Deposit = IF(Signups[Days Deposit] < 1 && Signups[Days Signed] < 3,
2,
IF(Signups[Days Signed] >= 3 && Signups[Days Deposit] < 1,0,1)
)
基本上,这个想法是有三个层次的标记:第一个是客户谁存款,不管什么时候。第二层是前 2 天报名,但还没有订金的客户。最后,最后一组是两天前注册但仍未存款的客户。而且这个群体应该很容易被我们的客户支持识别出来,这样他们就可以很快隔离那些客户并联系他们。
该公式将这三个级别分开,为每个级别分配一个数字(0,1,2),该数字将在以后用于条件格式。
第一步,在样式下设置稀疏,关闭垂直网格。这里有一个简短的声明:你可以按照你喜欢的方式格式化你的表格,你不需要遵循我选择的所有风格。

现在,最重要的部分是根据特定的值有条件地格式化我们的字段。首先,我将设置我的注册栏的格式,使用一些渐变的颜色,这样当客户注册时就可以立即看到:

下面是我的表现在的样子:

它已经看起来更好了,自从客户注册以来,这种颜色渐变为我们的桌子增加了额外的质量。
现在,最后的接触是标记“目标”客户。为了实现这一点,我们将再次使用条件格式,这一次是针对具有 0、1、2 值的列。打开图标,在“高级控制”下,定义每个特定值的图标:

最后,我们的表看起来像这样:

绿色符号表示该客户进行了存款。黄色感叹号表示该客户尚未存款,但他在前两天注册了。最后,我们的“目标”群体是一个带有红色符号的客户,他不久前注册了,但仍未存款。
正如您可能看到的,这仍然是一个表,但它比我们开始使用的那个表更友好。当然,我们可以通过让用户使用切片器来操作数据,为我们的报告添加一些额外的逻辑:

通过这种方式,我们的报告用户可以轻松地过滤掉不感兴趣的数据进行分析,并专注于他们的目标。
结论
正如你所看到的,桌子不一定需要是老式的无聊的视觉效果。通过一些小小的调整和对不同属性应用条件格式,您可以创建出引人注目的闪亮表格。更重要的是,它们肯定会丰富你的用户体验。
感谢阅读!
成为会员,阅读 Medium 上的每一个故事!
订阅这里获取更多有见地的数据文章!
魔术:聚会——在艺术指导中利用神经网络
鲁,迪伦·韦伯,鲁斯兰·阿斯克洛夫,埃里克·权,乐·迈克尔·宋

一. 简介
魔术:聚会(被称为“魔术”或“MTG”)是世界上最古老的交易纸牌游戏,其出版公司海岸巫师(WotC)是世界上最大的奇幻艺术专员之一。在过去的 26 年里,WotC 委托制作了数千件原创艺术品,这些艺术品在 20,000 多张独特的卡片中找到了归宿。每张卡可以有多种语言的多种印刷,这就创造了一个全球奇幻艺术生态系统。
魔法卡有与其游戏机制相关的总体分类器。主要的七种类型是神器、生物、结界、地、旅法师、瞬发和魔法。事实上,每一张印刷卡片都至少可以分为这些类型中的一种。凭借其 26 年的历史,魔术已经形成了一种独特的美学,使其有别于其他纸牌游戏。每张新卡都需要以某种方式适应这种审美,并捕捉卡的游戏性。当一个艺术家收到 WotC 的委托时,他们被指派为某个特定的卡片印刷创作艺术品。这项任务从设计概要开始,其中包括对卡的游戏性、提议的艺术描绘、调色板、以前的参考和卡类型的描述。艺术家有一定程度的创作自由,但通常被期望坚持设计大纲。一旦艺术家完成了他们的草图,他们将把草图发给艺术总监,征求反馈和修改意见。WoTC 提供的反馈越少,艺术家在印刷前就有越多的时间处理他们的作品,这通常会导致更高质量的作品。
为了帮助艺术家社区更好地满足 WotC 的要求,我们的目标是使用 CNN 模型将任何作品归类到上述七种类型之一。如果草稿图像属于简报类型(或任何类型)的可能性很低,则艺术家在等待 WotC 拒绝或接受他/她的作品之前会知道需要做更多的工作。换句话说,CNN 可以补充艺术家和艺术总监之间的第一接触点。如果在设计过程中的正确时间使用,图像分类可以导致反馈周期的减少,为艺术家提供更多的时间来创作高质量的魔术艺术
二。数据数据
a .图像分类
纵观 Magic 的历史,已经设计了许多工具来帮助社区成员分析卡片和建立卡片组。使用 Scryfall API ,我们能够拉出魔法卡的整个目录&对应的艺术。Scryfall 卡对象包括艺术重定向和类型标识。JPG 文件是我们解释变量的基础,而卡的类型是我们的响应变量。在将 JPG 卡文件组织成各自的类型后,我们使用 90:10 的分割将每种类型分割成训练集和测试集(表 1 )。从训练数据中删除了某些类型的卡片,包括拆分卡片和翻转卡片。这些卡片有两种类型的艺术,很难把它们归为一类。具有多个主要类别的牌,如神器生物,根据最合适的艺术指导,被重新标记为一个主要类别。举个例子,在神器生物双重类型中,美术指导会强调神器而非生物。
表 1
培训-测试拆分

b .LSTM 文本标签分类
使用 Scryfall API,我们使用牌名、甲骨文文本和风味文本作为解释变量,并使用与图像分类相同的生物类型。神谕文字解释了该卡的能力,如果有的话,而风味文字仅仅是为了增加建造世界的天赋。许多卡片没有甲骨文或风味文字,但每张卡片都有一个名字。甲骨文中经常提到卡的类型,但其方式并不总是表明卡的类型本身。该文本只进行了最低程度的预处理—所有输入标记都被转换为小写字母。
对于这个模型,我们在 20,000 张卡上进行训练,在 5,734 张卡上进行验证[链接到 Eric 的驱动器],验证集由游戏中最新发布的卡组成。
四。 方法和分析
a .图像分类
对于我们的 CNN 图像识别模型,我们决定选择迁移学习。这是因为我们可以处理的图像数量有限,而公开可用的模型(如 ImageNet)已经用数百万个数据点进行了训练。对于我们的第一个模型,我们在 VGG-16 (Simonyan,Karen & Zisserman,Andrew。(2014).用于大规模图像识别的非常深的卷积网络。arXiv 1409.1556。)我们尝试重新训练模型的最后四层,并决定重新训练产生最高准确度的最后两层。在 VGG 的顶部,我们添加了一个展平层,一个 relu 激活的密集层,一个 dropout 层,和另一个 softmax 激活的密集层用于分类。图像尺寸调整为 224 x 224 x 3,训练集和验证集的批量大小均为 16。
我们在 VGG 遇到的最大问题是训练速度。训练模型的一个时期大约需要三个小时。对于我们的第二个模型,我们决定采用 InceptionV3 (Szegedy,Vanhoucke,Ioffe,Schlens,Wojna,2015)。它产生了大致相同的精度,但时间从三个减少到一个时代一个小时。我们保持所有其他参数不变;我们重新训练了最后两层,增加了一个展平层,一个 relu 激活的密集层,一个 dropout 层,最后是另一个 softmax 激活的密集层。
b .T2【LSTM】模式
这里,我们使用一个具有两个 LSTM 层和一个学习嵌入层的模型,所有输出维度为 10。我们使用比率为 0.3 的辍学和经常性辍学,以及权重为 0.01 的核心 L2 正则化。这种轻量级模型架构训练速度非常快,100 个训练时期在 CPU 上耗时约 1-2 小时,在验证集上实现了 72%的预测准确率。LSTM 体系结构是从包括简单 RNN 在内的几个简单语言模型体系结构中挑选出来的,因为在 10 个时期的训练后具有最佳性能而被选中。
诉结果
****a .图像分类
我们的目标是让艺术家相信他们的草图符合 WotC 标准。我们通过考虑验证集和人类专业知识来分析我们的模型性能。在模型性能上,我们的第一个模型 VGG 产生了 55%的验证精度,这是第二个纪元以来的最高精度。有过度拟合的迹象,导致训练精度增加,而验证精度保持不变。初始模型产生了同样的 55%的验证准确性,但是,正如前面提到的,训练速度提高了三倍。两个模型都显示出非常明显的过度拟合的迹象。因此,我们决定实施正则化方法。我们使用 30%的辍学率和 L1 正则化。这些技术的实施有助于减少过拟合,但不能完全消除过拟合。我们让几个魔术师对以下四张卡片进行不同程度的分类。正如你所看到的,其中一些图像很难分类。

你能猜出这里显示的每张魔法卡的类型吗?(答案在底部)
为了与人类专家进行比较,我们将我们的模型性能与一位经验丰富的魔术师进行了比较。拒不合作的数据来自玩家和 CNN 都没有看到的即将到来的一集。基于表 2 所示的混淆矩阵,该模型的总体准确率为 59%,而人类分类的准确率为 76%(表 2 &表 3** )。模型未能正确识别单张卡片的一个方面是伪影。与此同时,玩家被观察到在所有潜在的类别中有更好的类型识别。**
表二
模型混淆矩阵

表 3
魔法玩家混淆矩阵

****b .LSTM 模式
经过 100 个时期的训练后,LSTM 模型达到了 73%的验证准确率。这个模型很难识别魔法,经常会在一瞬间混淆它们。同样,这个模型也受到了神器和魔法的挑战,经常把这两者都误认为是生物。关于验证集上最终 LSTM 模型的混淆矩阵,参见表 4** 。有关显示 LSTM 模型在 100 个训练时期的训练和验证准确性的图表,请参见图 1 。**
表 4
5700 张最新卡片验证集上 LSTM 模型的混淆矩阵

图 1
LSTM 模特培训历史

六。结论结论****
我们观察到,我们的模型可以合理地识别生物艺术,但对其他类型的牌却没有表现出类似的表现。考虑到我们训练的数据,这是意料之中的。42%的魔法卡属于生物分类器。我们将为未来的模型考虑的可能性是故意减少生物样本,训练一个没有任何生物的模型,或者增加非生物类型的训练数据。我们希望提高非生物的分类精度,这将从整体上提高模型的性能。近期的目标是达到 70-75%的准确率,我们发现这是我们测试的所有有经验的魔术玩家的范围。
这篇文章来自我们在弗吉尼亚大学数据科学学院的机器学习项目。
****魔法卡类型答案:
左上角:即时
右上:魅力
左下角:生物
右下角:土地
参考文献
法洛米尔、佐伊、莱多·穆塞罗斯·卡韦多、伊斯梅尔·桑斯和路易斯·冈萨雷斯·阿布里尔。"根据定性的颜色描述符、定量的全局特征和机器学习(QArt-Learn)对绘画进行艺术风格分类."专家系统。97(2018):83–94。
齐利奥、费利佩、马塞洛·普拉特斯和路易斯·兰姆。"分析魔术的神经网络模型:收集卡片." ICONIP (2018)。
克里斯蒂安·塞格迪,文森特·万霍克,谢尔盖·约菲,黄邦贤·施伦斯,兹比格涅夫·沃伊纳。重新思考计算机视觉的初始架构(2015)
神奇地拉出 PySpark UDFs 和 Pandas 函数的参数
在不替换参数的情况下更改函数

让参数名流动起来https://pix abay . com/photos/prairie-river-stream-curved-sunset-679014/
PySpark 用户定义函数(UDF)允许您使用 python 函数,并将其应用于 PySpark 数据帧的行。当您使用的功能变化很大时,必须更新功能和使用位置可能会很烦人。这篇文章将解释给定函数如何自动提取参数。该方法也适用于将 Pandas 系列作为输入的函数(见本文末尾)。
设置
让我们从一些设置开始:导入我们将会用到的东西,并创建一个玩具数据集。假设我们的数据包含关于价格、销售量、从客户那里收集的运输成本以及其他成本的列表的信息。我们将制作一些简单的 UDF 来从这些数字中计算收入和利润。

UDF 税务局
假设我们想要创建一个简单的 UDF,它使用price 和revenue列来创建一个新的revenue_wo_ship列。

变更 UDF 收入
在许多情况下,当前的需求可能会发生变化。例如,假设我们更改了收入的定义,不仅包括商品的价格,还包括我们从客户那里收取的运费。这需要两个变化
- 调整函数以将运输成本添加到收入计算中
- 调整
withColumn调用以更改参数

用移除第二步 T4
在这种情况下,额外的信息已经存在于我们的数据框架中,不得不进行这两种代码更改是很烦人的。我们应该能够改变函数,让参数通过名称自动提取。
为此,我采取了以下策略:
- 从函数开始。当它的定义改变时,我们应该能够自动改变要拉取的参数。
- 对函数参数进行循环。
A.如果参数是传入字典中的键,则使用该键的值。否则,
B.如果 spark 数据框中的任何列的名称与参数名称相匹配,则使用它们作为参数。否则,
C.如果参数有函数指定的默认值,则使用它。否则,
D.抛出一个异常,因为我们不知道该为参数使用什么值。
该策略通过循环函数的参数名来实现。这就是inspect的用武之地:它允许我们获取函数的参数名和默认值。

放在一起:功能
现在,我们可以将所有这些放入一个函数中,来为我们处理这个策略。注释可以在整个代码中为您提供指导。
我们从一个助手函数开始,它将常量值作为参数输入到 UDF 中,以处理上述策略中的 2A 和 2C。
然后,真正的魔术:
看到它在行动
现在,我们可以对这个函数进行简单的调用,而无需改变我们向 UDF 输入内容的方式:

它也适用于列表输入。例如,如果我们想将利润定义为价格和数量的乘积与成本列之和之间的差值:

这就是了。魔法

扩展:熊猫
请注意,这种方法同样适用于熊猫:

R 中的马氏距离和多元异常检测
寻找破坏线性的异常值
马哈拉诺比斯距离(MD)是一种有效的距离度量,用于计算点和分布之间的距离(参见)。它对多元数据非常有效。MD 之所以对多元数据有效,是因为它利用变量之间的协方差来求两点的距离。换句话说,Mahalanobis 通过考虑标准差(P1 离 P2 有多少标准差)来计算“P1”点和“P2”点之间的距离。当异常值被认为是多元的时,MD 也给出可靠的结果。为了通过 MD 发现离群点,计算 n 维数据中每个点与中心的距离,并通过考虑这些距离来发现离群点。

目录
- 马氏距离和欧氏距离
- 用 MD 求两点间的距离
- 利用 R 中的马氏距离发现异常值
- 结论
如果您对如何使用 Python 中的 Mahalanobis 距离来检测异常值感兴趣,您可以查看我下面的另一篇文章。
Python 中的多元异常值和马氏距离
towardsdatascience.com](/multivariate-outlier-detection-in-python-e946cfc843b3)
马氏距离和欧氏距离
欧几里德距离也通常用于寻找 2 维或 2 维以上空间中两点之间的距离。但是,与欧几里得不同,MD 使用协方差矩阵。正因为如此,当两个或多个变量高度相关时,即使它们的尺度不同,MD 也能很好地工作。但是,当两个或多个变量不在同一尺度上时,欧几里得距离结果可能会误导。因此,在找到这些点之间的距离之前,必须计算变量的 Z 得分。此外,如果变量高度相关,欧几里得就不够好。
让我们检查欧几里得和 MD 公式,

n 维欧氏距离公式

马氏距离公式
从公式中可以看出,与欧几里得不同,MD 使用协方差矩阵(位于 C ^(-1 的中间)。在欧几里得公式中,p 和 q 代表要计算距离的点。“n”代表多元数据中变量的个数。
通过 MD 寻找两点间的距离
假设我们有 5 行 2 列数据。正如您所猜测的,数据中的每一行都代表二维空间中的一个点。
V1 V2
----- -----
P1 5 7
P2 6 8
P3 5 6
P4 3 2
P5 9 11
让我们画一个 V1 和 V2 的散点图,

V1 和 V2 散点图
橙色点表示这两个变量的中心(平均值),黑点表示数据框中的每一行。现在,让我们试着找出 P2 和 P5 之间的马氏距离;

根据上面的计算,P2 和 P5 之间的距离为 4.08。
利用 R 中的马氏距离发现异常值
如前所述,MD 对于发现多元数据的异常值非常有效。特别是,如果变量之间存在线性关系,MD 可以计算出哪些观察值破坏了线性关系。与另一个例子不同,为了找到异常值,我们需要找到每个点和中心之间的距离。中心点可以表示为多元数据中每个变量的平均值。
在这个例子中,我们可以使用 R 中预定义的数据,称为“空气质量”。我们将“温度”和“臭氧”值作为我们的变量。这是我们需要遵循的步骤列表;
- 找到“臭氧”和“温度”的中心点。
- 计算“臭氧”和“温度”的协方差矩阵。
- 求各点到中心的马氏距离。
- 从卡方分布中寻找临界值
- 选择小于截止值的距离(这些值不是异常值)。
这是计算中心和协方差矩阵的代码;
在计算距离之前,让我们绘制数据,并通过考虑中心点和协方差矩阵绘制一个椭圆。我们可以通过使用“car”包中的椭圆函数来找到椭圆坐标。“椭圆”函数有 3 个重要参数;中心、形状和半径。中心代表变量的平均值,形状代表协方差矩阵,半径应该是具有 2 个自由度和 0.95 概率的卡方值的平方根。我们采用概率值 0.95,因为超出 0.95 将被视为异常值,自由度为 2,因为我们有两个变量“臭氧”和“温度”。
找到我们的椭圆坐标后,我们可以用“ggplot2”包创建我们的散点图;
上面,代码片段将返回散点图下方;

臭氧和风变量散点图
图上的蓝点表示中心点。黑点是臭氧——风变量的观测值。如您所见,点 30、62、117 和 99 位于橙色椭圆之外。这意味着这些点可能是异常值。如果我们认为这个椭圆是在协方差、中心和半径上绘制的,我们可以说我们可能已经找到了与 Mahalanobis 距离的异常值相同的点。在多维中,我们不画椭圆,但是我们计算每个点和中心之间的距离。找到距离后,我们使用卡方值作为截止值,以识别异常值(与上面示例中的椭圆半径相同)。
stats 包中 R 附带的“mahalanobis”函数返回每个点和给定中心点之间的距离。这个函数也有 3 个参数“x”、“center”和“cov”。你可以猜到,“x”是多元数据(矩阵或数据框),“center”是变量中心点的向量,“cov”是数据的协方差矩阵。这一次,在获得卡方截止值时,我们不应该求平方根。因为,MD 已经返回了 D(平方)距离(从 MD 公式可以看出)。
终于!我们已经确定了多元数据中的异常值。发现异常值 30。62.99.117.观察值(行)与散点图中椭圆外的点相同。
结论
在这篇文章中,我们讨论了从理论到实践的“马哈拉诺比斯距离”。除了从公式计算两点之间的距离,我们还学习了如何使用它来发现 r 中的异常值。虽然 MD 在机器学习中不太常用,但它在定义多元异常值时非常有用。
如果您有任何问题,请随时留下您的意见。但是,您可能会对我的另一篇文章感兴趣,这篇文章讲述了如何从头开始使用 Python 中的 Mahalonobis 距离来检测异常值。
Python 中的多元异常值和马氏距离
towardsdatascience.com](/multivariate-outlier-detection-in-python-e946cfc843b3)
图像分类的主要挑战
什么是图像分类,我们在图像分类中面临的主要问题是什么?

塞巴斯蒂安·赫尔曼在 Unsplash 上的照片
图像分类是根据图像的类型(类别)给图像分配标签的过程。
假设我们有以下几类图像:猫和狗
因此,当我们向图像分类系统提供给定类别的图像时,系统会根据类别给图像分配标签。
例如,如果我们将下面给出的图像提供给“图像分类系统”。系统应该将标签“狗”分配给图像。

照片由 Unsplash 上的 Jamie Street 拍摄
图像分类的挑战:
图像分类面临以下主要挑战:
1。类内变异
2。标度变化
3。视点变化
4。遮挡
5。照明
6。背景杂乱
让我们分别看看图像分类中的这些挑战。
- 类内变异
类内变化是同一类图像之间的变化。类内变化的例子是在我们的数据集中有多种类型的椅子。椅子可以是“办公椅”、“舒适椅”、“餐桌椅”、“装饰椅”等。

图片来源(语义学者
在上图中,我们有不同类型的椅子。所以我们的图像分类系统应该能够解决类内变异的问题。
2。标度变化
这个问题在图像分类中很常见。尺度变化实际上是同一物体的图像具有多种尺寸。
下图显示的是同一物体 __ 勺子的尺度变化,但它们都是不同尺寸的勺子。

照片由 Dstudio Bcn 在 Unsplash 上拍摄
3。视点变化
我们有视点变化,其中对象可以相对于如何在图像中拍摄和捕捉对象而在多个维度上定向/旋转。无论我们从哪个角度捕捉椅子的图像,它仍然是一把椅子。

费德里卡·坎帕纳罗在 Unsplash 上的照片
4。遮挡
在图像中有很多我们想要分类的物体是不能被完全观察到的。大部分藏在其他物体后面。

Tatianaаzatskaya 摄于 Pexels
给定的是猫的图像,但请注意它是如何在封面下休息的,从我们的视野中被遮挡。这意味着它不是完全可见的,但我们的图像分类系统应该能够检测到它并将其归类为猫。
5。照明
我们的图像分类还应该能够处理光照的变化。

作者图片
这两个图像是同一个杯子,但是像素的强度水平不同。我们的图像分类系统应该能够处理光照的变化。因此,当我们将任何具有不同亮度级别(照度)的相同物体的图片提供给我们的图像分类系统时,系统应该能够给它们分配相同的标签。
6。背景杂乱
这意味着图像中有很多物体,对于观察者来说,很难找到特定的物体。这些图像非常“嘈杂”。
但是我们只对图像中的一个特定对象感兴趣;然而,由于所有的“噪音”,不容易挑出特定的对象。
对于人类来说这是非常困难的任务,所以想象一下对于一台对图像没有语义理解的计算机来说有多难。

乔尔·莫特在 Unsplash 上拍摄的照片
但是在某些情况下,图像中存在某个目标,但该目标的外观与背景非常相似,因此图像分类系统很难对该目标进行分类。

美国国家海洋和大气管理局在 Unsplash 拍摄的照片
在某些情况下,即使图像中没有物体,例如如果我们向图像分类系统显示只有冰的图像,系统也会将其标记为熊。这是因为图像分类系统在训练过程中已经学习了图像中的模式,并且有白熊和没有熊的冰的模式非常相似。
所以我们的图像分类系统也应该能够解决背景混乱的问题。
这就是图像分类系统面临的挑战。我希望现在你对这些挑战有了更好的理解。感谢阅读!
如果你想阅读更多的文章,可以考虑使用我的推荐链接成为媒体会员。你将有机会接触到所有的媒体文章,每月只需 5 美元。我会赚它的一小部分作为佣金,没有额外的费用给你。快乐阅读!
保持良好的“彩票因素”
确保没有单一的人为故障点

克里斯蒂娜@ wocintechchat.com 在 Unsplash 上的照片
彩票因素是什么?
彩票因素,通常被称为公共汽车因素,是一个数字,代表有多少人不再参与某个项目会使该项目处于危险之中。它源于这样一个概念,即如果项目中的特定人员中了彩票并离开了(或被公共汽车撞了),剩下的人将没有足够的知识来继续项目。因此,低彩票系数是不好的,因为人们确实会因为许多原因离开项目,而让一个项目依赖于一两个关键人物是有风险的。这个概念适用于许多行业和学科的项目,但我在这里的重点是软件工程。
除了由于人员离开而使项目面临风险之外,如果某些领域的工作只能由可能已经在其他地方忙碌的特定人员来完成,那么低的抽签系数还会减缓项目的开发。
因此,作为经理和/或项目领导,确保项目在继续进行所需的知识和技能方面有冗余是很重要的。无论是继续建设、运营还是维护项目。我在以前的文章中详细介绍了如何建立一个好的彩票因素,但是如何保持一个好的彩票因素呢?
确保没有单一的人为故障点
medium.com](https://medium.com/dev-genius/building-a-good-lottery-factor-bf67f7de04d8)
如何保持良好的因子
建立一个好的彩票因素所需要的一切也是维持它所需要的。随着团队的发展和项目的变化,这些努力应该是连续的。一旦一个好的彩票因素已经实现,它将不可避免地随着时间的推移而减少。这可能是由于人员流失,或者仅仅是团队专注于一个项目或新项目的新方面。然而,作为一个团队,你可以做一些事情来减缓彩票因素的下降。
“对于必须处理现场事故的人来说,了解最近发生的变化是至关重要的。”
拉式请求(PRs)/代码审查
为了使共享的项目知识与正在进行的变更保持同步,让团队成员参与 PRs 的评审( Pull Requests 或代码评审)是非常重要的。在代码投入生产之前,让多个工程师批准代码变更有很多好处,知识共享是其中之一。
除了给其他人提供对项目即将发生的变化的反馈的机会之外,PRs 还让那些待命的人洞察到正在发生的变化。对于必须处理现场事故的人来说,了解最近发生的变化是至关重要的。SME ( 主题专家)和待命人员都不希望由于缺乏知识而导致问题升级。
最后,PRs 为可能在项目的其他领域工作的团队成员提供了一种方法,让他们可以在闲暇时看到其他地方发生了什么变化。而不需要将他们实时包括在每个会议或讨论中。
“PRs 有助于保持详细的低级知识流动,协作、反馈和设计评审有助于高级知识的传播。”
设计协作
确保新功能的设计是以协作的方式完成的,让项目中的其他人参与进来,有助于从一开始就分享新的全局知识。PRs 有助于保持详细的低级知识的流动,协作、反馈和设计评审有助于高级知识的传播。接受和促进对设计和计划的反馈也鼓励了项目中其他人的参与,这促进了共享所有权和责任。这些方面有助于随着事情的发展保持团队知识的更新,从而避免重新构建你的彩票因素的需要。
这不仅适用于系统架构设计,也适用于任何计划的项目。无论是用户体验提案、流程变更、业务方向变更还是营销活动。在它们付诸行动之前,开放它们进行更广泛的讨论和反馈,是开始播种最终需要分享的新知识的好方法。在早期获得不同的反馈当然比太迟了要好。
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@royherrod/membership)
“让工程团队中的人员围绕团队负责的多个领域进行轮换是一个好主意。”
工作区域的轮换
虽然让专门的中小型企业长期负责某个项目的特定领域确实有一些好处,但这也增加了他们成为有能力管理一个领域的人的风险。可怕的彩票因素之一。为了帮助缓解这种情况,让一个工程团队中的人围绕一个团队负责的多个领域进行轮换是一个好主意。这种轮换不应该只是小的、无足轻重的工作,它应该给人们机会真正投资于一个领域,并交付有意义的东西。但是,知道工作将被传递,知识将被分享,这又一次鼓励了信息的公开,并强化了记录的需要。
有些情况下,专业的、非常深入的知识是必不可少的,为了建立这种知识,人们需要长时间专注于某个特定的领域。这没关系。让工程师轮换的目的不需要适用于每个工程师。事实上,如果某个领域最有知识的人专注于其他领域,那么过多的变动会使工程师很难进入新的领域。让轮岗集中在初级工程师身上实际上有很多额外的好处。这是一个很好的方式,让他们获得更广泛的经验,并帮助他们找出自己的优势和激情所在,同时也建立对各个领域的运作的理解。
在这种情况下,知识的主要来源在一个人身上是可以接受的。但是,为了保持一个良好的彩票因素,这种知识也应该在许多其他人之间进行分段复制。这意味着在主要 SME 离开的情况下,没有立即的单一替代,但是知识确实存在,并且需要从许多其他工程师组合。在这种情况下,需要决定一个单一的替代 SME 整理所有知识成为替代是否是期望的结果。或者,新常态是否应该让它分散成片段,并确保每个片段在多人之间复制,以保持彩票因素。这里的正确选择将取决于项目的状态及其未来发展的计划。
为了保护你的团队和项目,保持一个良好的抽奖因素是一个持续的练习。它需要一个平衡的团队,既有新成员,也有老成员。这需要在团队中培养知识共享和协作的文化。这是一个整个团队都需要经历的旅程,而不是一个经理可以决定的。
维护 GitHub 统计数据超过 14 天

用于维护 Github 克隆和视图统计数据超过 14 天的 Python 代码。
GitHub 是一个帮助开发人员存储和管理代码的伟大平台。目前,GitHub 仅提供最近 14 天的统计数据。这些统计数据包括视图、唯一视图、克隆和唯一克隆的数量。作为一名开发人员,我发现看不到我的 GitHub 库的终生统计数据有点令人不安。这些终身统计将帮助开发人员了解他们的存储库的重要性。基于流量,开发人员可以给予某些存储库更多的关注。此外,有时开发人员可能希望在他们的网站上显示这些统计数据。
在本文中,我将详细介绍如何维护超过 14 天的存储库的 GitHub 统计数据,并显示网站的这些图表。完整的代码可以在这里找到。
StatTheGit
StatTheGit 是一个基于 python 的工具,用于获取、维护和显示 GitHub 克隆和视图统计数据。该存储库可用于维护存储库统计信息的本地副本。
步骤 1 —克隆存储库
git clone [https://github.com/aqeelanwar/StatTheGit.git](https://github.com/aqeelanwar/StatTheGit.git)
步骤 2 —安装所需的软件包
cd StatTheGit
pip install -r requirements.txt
步骤 3 —获取统计数据
python fetch_stats.py \
--GitToken <GitToken> \
--username <GitHub Username> \
--RepoNames <Repository name>

python 文件 fetch_the_stats.py 的参数详细信息
gitToken: GitToken 是一个 40 个字符的十六进制 Git 访问令牌,用来代替密码来执行 Git 操作。要从 GitHub 帐户获取统计数据,您需要创建一个 Git 访问令牌。关于如何从你的个人资料中创建一个的细节可以在 GitHub 网站的这里找到。
用户名:这是您的 GitHub 用户名。
RepoNames: 可用于限制您要获取统计数据的存储库。要获取多个存储库的统计数据,只需用空格将它们分隔开,如下例所示
python fetch_stats.py \
--username <username> \
--GitToken <GitToken-here> \
--RepoNames reponame1 reponame2 reponame3
运行 fetch_stats.py 将在父目录中创建一个文件夹 repo_stats/
# Generic
|-- repo_stats
| |-- <username>
| | |-- <repository 1>.txt
| | |-- <repository 2>.txt
| | |-- <repository 3>.txt# Example
|-- repo_stats
| |-- aqeelanwar
| | |-- PEDRA.txt
| | |-- SocialDistancingAI.txt

存储库统计信息的示例文本文件—socialdinstancingai . txt
步骤 4 —显示统计数据
StatTheGit 可以用来创建和更新 GitHub 库的离线图和在线图,然后可以显示在你的网站上,就像这个。Plotly 被用作图形库,主要是因为它支持在线图形,可以嵌入到您的网站。
离线图形:基于图形的交互式图形,可以在本地机器上查看。
python display_stats.py \
--stat_folder repo_stats \
--display_type 'offline'
这将为考虑中的每个存储库打开一个浏览器选项卡,并显示存储库克隆和视图统计的交互式图形

在线图表:要在你的网站上显示这些图表,你需要把它们放在你的 Plotly 账户上。可以采取以下步骤
- 在这里创建 Plotly 账户(Plotly-用户名)
- 在这里生成 API Key(plotly-API _ Key)
一旦您有了用户名和 API 密钥,您就可以使用以下命令来创建在线图表,然后可以在网站上共享。
python display_stats.py \
--stat_folder repo_stats \
--display_type 'online' \
--username <plotly-username> \
--api_key <plotly-api-key
运行此命令将在 web 浏览器中打开每个考虑的存储库的图形。要在您的网站上显示这些图表,您可以复制 iframe 或 HTML 代码(基于您的网站设计)并在您的网站上使用它。

重新运行该命令时,链接不会改变,网站上显示的图形会自动更新,因此无需再次复制粘贴链接。
第 5 步—更新统计数据:
从现在开始,每当你需要更新你的网站上显示的 GitHub 统计数据时,你只需要运行 fetch_stats 和 display_stats
**# Step 1:**python fetch_stats.py \
--GitToken <GitToken> \
--username <GitHub Username> \
--RepoNames <Repository name>**#Step 2:**python display_stats.py \
--stat_folder repo_stats \
--display_type 'online' \
--username <plotly-username> \
--api_key <plotly-api-key
这将自动更新图表。
总结:
StatTheGit 可用于维护并自动更新您网站上 GitHub 存储库的终生统计数据。
如果这篇文章对你有帮助,请随意鼓掌、分享和回复。如果你想了解更多关于机器学习和数据科学的知识,请关注我@Aqeel an war或者在LinkedIn上与我联系。
使用 R & Python 代码的主要数据框操作—第 1 部分

当谈到数据分析时,数据争论的知识或以正确的形式和格式放置可用数据集与数据分析的实际操作一样必要。
通常,数据不会以我们想要的形式出现,因此知道如何做到这一点变得至关重要。尽管我们有很多软件工具来处理数据,但在本文中,我将向您展示如何使用 R 和 Python 来完成这项工作。
将要讨论的主要操作有:
- 数据帧子集化
- 对行和列应用函数
- 分组和应用聚合函数
- 数据框旋转
- 数据帧熔化
- 将多个数据框连接/合并在一起
所用数据:泰坦尼克号数据集
使用的 Python 包:熊猫
使用的 r 库: Dplyr,reshape2
设置环境和导入数据
分析任何数据的第一步是将数据导入到您想要用于分析的环境中。因为我将在整篇文章中讨论 R & Python 的两种变体,所以让我们先导入数据和所需的库。您可以使用 Python 的 R 或 Sci-kit learn 包中内置的 titanic 数据集,但更方便的方法是通过使用下面代码中提到的 URL 来使用我在 Github 帐户上托管的数据。
R —版本:
library(dplyr)library(reshape2)titanic <- read.csv(‘https://raw.githubusercontent.com/hurratanvir/algo-trade/master/titanic.csv')
Python —版本:
import pandas as pdtitanic = pd.read_csv(‘https://raw.githubusercontent.com/hurratanvir/algo-trade/master/titanic.csv')
现在,由于我们手里有 titanic variable 中的数据,让我们跳到分析部分,但在此之前,让我们尝试理解数据(至少我们将使用的几列)。直接在任意 Python IDE 中运行数据框变量的名称,在 R Studio 中运行 View(titanic) ,就可以在 Python 中查看数据框。
泰坦尼克号的数据集包含了乘客的数据(姓名,票价等。以及他们是否幸存)谁在 1912 年登上了著名的泰坦尼克号。数据框中的各列如下:
PassengerId :认为是数据记录的序列号。在数据帧中,每个乘客都有一个唯一的 id。
生还: 0 表示没有生还,1 表示乘客生还
Pclass :乘客等级(1-一等,2-二等,3-三等)
性别:乘客的性别
年龄:乘客的年龄
票价:乘客支付的票价
1。 数据帧子集化
在数据分析中经常需要数据帧子集化。举个例子,在泰坦尼克号的数据框中,假设你想只使用男性乘客的数据,或者那些幸存的乘客的数据,或者那些支付了高于某个特定金额的票价的乘客的数据。如果在所有数据集中,您只想使用姓名列或票价列等,该怎么办?上面提到的所有情况都要求您根据给定的条件对数据进行子集划分。所以让我们看看它是如何在 R 和 Python 中实现的
R —版本:
在 R 中,您可以使用已经导入的 dplyr 库来完成这项工作。这个库中有两个主要函数在这种情况下会很有用, select() 和 filter() 。现在让我们看看它们是如何使用的:
#Selecting only PassengerId and Name columnsselect(titanic, c(PassengerId, Name))#Selecting only those records where sex is malefilter(titanic, Sex == ‘male’)#Selecting the record of only those males who survivedfilter(titanic, Sex == ‘male’ & Survived == 1)
Python —版本:
在 Python 中,您可以使用已经作为 pd 导入的 Pandas 包来为您完成任务。
#selecting only PassengerId and Name column#simply pass the list containing column names as data frame indextitanic[[‘PassengerId’, ‘Name’]]
在 python 中,基于特定条件过滤行是通过布尔屏蔽完成的。首先生成一系列真、假值,然后将该系列作为原始数据框的索引进行传递。
#Selecting only those records where sex is maletitanic[titanic[‘Sex’] == ‘male’]
注意在上面代码行 titanic['Sex'] == 'male '首先生成一系列真-假值。当满足条件时,输出值为 True,否则为 False(尝试单独运行此命令)。然后,该序列作为索引传递给 titanic 数据帧以获得结果。
#Selecting the record of only those males who survivedtitanic[(titanic[‘Sex’] == ‘male’) & (titanic[‘Survived’]==1)]
注意每个条件周围的普通括号。
2。 对行和列应用函数
除非您学会通过某种数学或逻辑运算将值放入数据框中,否则您无法通过浏览数据框或仅取出数据框的一部分来从数据框中提取大量信息。数据框中的数据是按行和列排列的,当要对其执行某些操作或应用任何函数时,通常只在这两个维度上完成。简而言之,我们可以在行方向或列方向对数据帧应用函数。我们将尝试在泰坦尼克号数据框架的背景下回答几个问题,以使其更加清晰。假设我们有两列,年龄和费用来自我们的整个 titanic 数据集,我们希望首先按行检查值的总和,然后按列检查,如下所示:

来源:Self
虽然结果没有太多的实际用途,但可以很好地证明我们正在学习的任务。此外,为简化起见,仅显示了每个变量下的前 10 个值。现在让我们看看上面的过程是如何在 R 和 Python 中完成的
R —版本
在 R 中,任何函数都可以通过使用 apply() 函数应用于数据帧,该函数是 R 基础包的一部分。 apply() 函数的语法是: apply(数据帧,边距,函数)。第一个参数是我们希望对其应用函数的数据帧或数据帧子集。Margin 控制函数是按行还是按列应用,Margin = 1 表示按行操作,Margin = 2 表示按列操作。让我们看看 apply()函数的运行情况:
# calculating sum of Age and Fare column (Column wise)apply(select(titanic, Age, Fare), 2, sum, na.rm = TRUE)# calculating sum of Age and Fare column (Row wise)apply(select(titanic, Age, Fare), 1, sum, na.rm = TRUE)
我们首先使用 select() 函数从 titanic 数据集中取出 Age 和 Fare 列,然后使用 apply() 函数,将 sum 函数作为数据的第三个参数,首先按列(Margin = 2),然后按行(Margin = 1)。na.rm = TRUE 的参数用于告诉 apply() 函数忽略任何遇到的 na 值。
Python —版本
在熊猫中,我们有一个类似的函数叫做 apply() 来完成任务。我们将看到它的运行,但在此之前,让我们了解它的论点。我们必须将想要应用于数据框和轴信息的函数作为参数传递给 apply() 函数。Axis = 0 表示按行操作,axis = 1 表示按列操作。
# calculating sum of Age and Fare column (Column wise)titanic[[‘Fare’, ‘Age’]].apply(‘sum’, axis = 1)# calculating sum of Age and Fare column (Row wise)titanic[[‘Fare’, ‘Age’]].apply(‘sum’, axis = 0)
引号中的第一个参数“sum”告诉 pandas 执行 sum 操作。虽然,你可以使用任何你选择的功能,除了熊猫已经提供的功能。
3。 分组并应用聚合函数
在回答某些值/每个分类变量值等问题时,对数据框进行分组变得至关重要。在 titanic 数据集的情况下,如果我们被问及每种性别的平均票价是多少,那么我们需要首先根据性别对数据进行分组,然后执行 Fare 列中每个相应值的平均值计算操作。这个问题可以如下图所示:

来源:Self
为了简化,上述过程考虑了 titanic 数据集的性别和票价列的前 10 个值。我们首先根据某个分类变量的值(在当前情况下为性别)进行分组,然后计算总值(平均值、总和、最大值、最小值等。)的一些其他变量,票价在当前情况下。
此外,上面显示了 Fare 列,因为我们计划以后使用它,但是您可以按照相同的分组过程用男性和女性值来可视化每个其他列。到目前为止,分组和在每个组上使用聚合函数的过程必须是清楚的。现在让我们看看这一切是如何在 R 和 Python 中完成的。
R —版本:
在 R 中,我们将首先使用 group_by() 函数对数据进行分组,然后使用summary()函数对票价列应用平均值聚合函数,这两个函数都是 dplyr 包的一部分。
titanic %>% group_by(Sex) %>% summarise(mean(Fare))
注意使用管线操作器, % > % 。这个操作符极大地简化了 R 代码。它被称为管道是有原因的,管道顶部的输出被输入到管道底部的函数。作为实例 titanic % > % group_by(..)表示将 titanic 传递给 group_by 函数。
Python —版本:
在 python 中,我们将使用 groupby() 函数,该函数是 pandas 包的一部分,用于对性别列上的数据帧进行分组。在我们将数据分组后,我们将对其使用 apply() 函数来计算 Fare 列的平均值。
g = titanic.groupby(‘Sex’)g[[‘Fare’]].apply(‘mean’)
Pandas 的默认特征是将分组后的列作为分组数据框的索引。您应该运行以上两个命令,以了解这有多有用。
4。 数据框旋转
旋转数据框对于从中提取信息非常有用。为了理解旋转,让我们尝试回答一个与泰坦尼克号数据框相关的问题。
乘坐三等舱的男性乘客中有多少人幸存?
解决这个问题的一种方法是,首先按性别对数据进行分组,然后按 Pclass 进行另一轮分组,然后计算包含 Pclass 组 3 的男性组中 1 的数量。如下图所示:

来源:Self
你现在可以很容易地回答这个问题,通过找出对应于 Pclass = 3 的幸存列(= 0)下的 1 的数量,对应于性别=男性。为了简化,上面只考虑了 20 个记录。
因为在组内分组的过程可以回答我们的问题,但是有一个更简单的方法来解决这样的问题,通过旋转。相同的数据如果进行透视,看起来应该是这样的:

来源:Self
上表显示了在不同的性别和性别值下 1 的数量。旋转既方便又容易解释。所以让我们看看 R & Python 中的旋转是如何完成的
R —版本:
在 R 中,为了制作数据透视表,我们将使用 reshape2 库中的函数以及 dplyr 中的函数。在 R 中制作像 excel 一样的数据透视表有点棘手,让我们看看如何制作一个
x <- select(titanic, Sex, Pclass, Survived)y <- x %>% group_by(Sex, Pclass) %>% summarise(sum(Survived))pt <- dcast(y, Sex~Pclass)
我们首先在性别列上对数据进行分组&再次在 Pclass 列上。在分组数据上,我们使用 sum() 函数来计算幸存列的总和(因为 0 代表未幸存,1 代表幸存,所以总和将给出幸存人员的总数)。一旦数据被分组,我们将使用 reshape2 库的 dcast() 函数将数据框转换成典型的数据透视表的形状。
Python 版本:
在 Python (Pandas)中,从数据生成数据透视表比 R 相对容易。可以使用的函数是 Pandas.pivot_table() 。调整该表需要一些参数,但我们将在 titanic data frame 上使用其中的 4 个参数来生成我们想要的数据透视表。这些论点是:
数据:要使用的数据集,索引:将在数据透视表中用作索引的列名,列:其值将在数据透视表中用作列名的列名,值:将用于计算数据透视表的值的列名, aggfunc :对值列的值使用的聚合函数
现在让我们从 Sex,Pclass & Survived 列创建一个数据透视表:
pt = pd.pivot_table(titanic, index = ‘Sex’, columns = ‘Pclass’, values = ‘Survived’, aggfunc = ‘sum’)
正如我所说的,这比 R 版创建数据透视表相对容易。
5。 数据帧融化
数据帧融合可以被视为旋转的相反过程。随着旋转向数据框添加更多列并减少行数,数据框的融合意味着在减少列数的同时添加更多行。作为一个例子,我们上面创建的数据透视表在融化时可以是这样的:

来源:Self
Melting 只是选取了列名&用它们制作了一个单独的列,保持了所有信息的完整性。现在让我们看看数据帧是如何在 R 和 Python 中融合的
R —版本:
在 R 中我们可以使用 reshape2 库的 melt() 函数来一次性融化一个数据帧。假设我们上面创建的数据透视表被分配给变量 pt,我们将使用这个 pt 来演示熔化
melt(pt, variable.name = ‘Pclass’)
variable.name 参数将是新创建的列的名称,其中的值是从现有的列名中选取的。
Python 版本:
在 python 中,pandas 包的 melt()函数用于融合透视数据框,如下所示:
pd.melt(pt, ignore_index=False)
ignore_index 默认为 True &我们必须将其设置为 False,因为在我们之前创建的数据透视表中,性别列被视为索引。
6。 将多个数据帧合并在一起
当信息分布在不同的数据帧中时,我们需要将两个或更多的数据帧合并在一起,并且我们需要将它们组合在单个数据帧中以进行数据分析。为了更清楚地理解这一点,假设我们想在 titanic 数据框中添加另一列,该数据框包含有关旅行等级的信息,如下图数据框所示:

来源:Self
我在下面贴了一部分泰坦尼克号的数据框,让问题更清晰。我们有 PassengerId、Name 和 Pclass 列,我们希望向其中添加另一列,其中 Pclass 被转换为基于上表的类名。

来源:Self
简而言之,我们想要一个如下所示的新数据框:

来源:Self
到目前为止,合并的好处肯定是显而易见的,同时,您可能已经猜对了,为了合并两个数据框,它们必须至少有一个公共列。如下所述,可以更清楚地理解合并过程:
- 我们有两个数据框共享一个公共列(您可以称之为关键列)
- 左数据框中的关键字与右数据框中的关键字一一匹配
- 在每次匹配时,根据正在执行的合并/连接过程的类型返回结果。
在开始编码练习之前,让我们先了解不同类型的合并/连接过程:
- 左连接:在左连接中,即使没有找到匹配,也会返回左数据框的行。左列中所有与右列不匹配的值将在右数据框的列下获得 Nan 或 Null 值,如下所示:

来源:Self
2.右连接:在右连接中,即使右数据框中的行在左数据框中没有匹配项,也会返回右数据框中的行。右数据框中所有与左数据框不匹配的值将在左数据框的列下获得 Nan/Null 值,如下所示:

来源:Self
3.内连接:内连接是最常用的连接技术。仅返回找到匹配项的行,如下所示:

来源:Self
4.外部/完全连接:在外部连接中,无论是否找到匹配,都返回两个数据帧的所有行。特定数据框中与另一个数据框不匹配的所有行在另一个数据框的列下都为 Nan 或 Null,如下所示:

来源:Self
现在我们知道了连接的含义和它的不同类型,让我们看看所有这些是如何在 Python 和 R 中完成的
R —版本:
在 R 中,我们在基础包中提供了 merge() 函数,其主要参数如下:
x :左数据框, y :右数据框, by :要进行合并的列(必须为两个数据框所共有),all.x:如果我们想要左数据框中的所有行(左连接),则设置为 TRUE, all.y :如果我们想要右数据框中的所有行(右连接),则设置为 TRUE。
注意:默认情况下, merge() 将执行内部连接,如果我们想要外部连接,我们需要将 all.x 和 all.y 都设置为 TRUE。
#We will first create the other data frame that we will merge with the titanic data framey = data.frame(Pclass = c(1,2,4), Class = c(‘1st Class’, ‘2nd Class’, ‘4th Class’))#Left Join:merge(titanic, y, by = ‘Pclass’, all.x = TRUE)#Right Join:merge(titanic, y, by = ‘Pclass’, all.y = TRUE)#Inner Join:merge(titanic, y, by = ‘Pclass’)#Outer/Full Join:merge(titanic, y, by = ‘Pclass’, all.x = TRUE, all.y = TRUE)
Python —版本:
在 Pandas 中,我们有一个 Pandas.merge() 函数来处理所有的合并需求。主要论点是:
on :需要合并的列(必须为两个数据框所共有), how :合并类型,可以是“左”、“右”、“内”或“外”。
现在让我们看看如何使用它
#We will first create the other data frame that we will merge with the titanic data framey = pd.DataFrame({‘Pclass’:[1,2,4], ‘Class’:[‘1st Class’, ‘2nd Class’, ‘4th Class’]})#Left Join:pd.merge(titanic, y, on=’Pclass’, how = ‘left’)#Right Join:pd.merge(titanic, y, on=’Pclass’, how = ‘right’)#Inner Join:pd.merge(titanic, y, on=’Pclass’, how = ‘inner’)#Outer/Full Join:pd.merge(titanic, y, on=’Pclass’, how = ‘outer’)
结论:
尽管除了强调各种数据转换技术之外,这个主题并不需要一个结论,但是本文在数据转换方面对 R 和 Python 进行了比较。虽然我们只讨论了 6 种数据框架转换技术,对其做出判断是不公平的,但有一点我们可以肯定,Python 和 R 都足够强大,可以非常轻松地处理任何复杂的数据转换任务。到目前为止,我的个人观点是,对于数据分析和可视化,R 比 Python 容易得多,当谈到机器学习时,Python 占了上风。但是,这也是我个人的观点,也是可以争论的。
你需要知道的渗透测试的主要限制
开发经理最大的恐惧之一是在攻击者发现之前,不能识别他们的 web 应用程序中的漏洞。

在 Unsplash 上 Sai Kiran Anagani 拍摄的照片
渗透测试可能涉及尝试破坏应用系统,如前端/后端服务器和应用协议接口(API)。这种有针对性的安全漏洞有助于暴露易受安全漏洞(例如,代码注入攻击)攻击的漏洞,例如未经排序的输入。
在 web 应用程序安全的背景下,pen 测试经常被用来渗透应用程序,并试图避开任何 web 应用程序防火墙(WAF)。
pen 测试揭示了安全测试中可能缺少的不同方面,例如适当的安全策略,例如缺少强密码策略或多因素身份验证。pen 测试提供了处理安全漏洞或入侵的模拟体验。它类似于消防演习,在此期间,员工接受培训,以警惕安全攻击和威胁的可能性。
下面是渗透测试的一些主要好处:
- 发现您的应用程序、配置、网络基础设施和系统等中存在的弱点。
- 测试您应对网络攻击者和恶意活动的网络防御能力
- 它对企业的运营有很大的影响,因为它暴露了可能导致可访问性丧失或停机的潜在威胁
- 维护利益相关者的信誉和信任
所有这些好处似乎证明了组织投入渗透测试的努力是正确的。此外,许多公司进行笔测试,以遵守支付卡行业(PCI)安全标准委员会制定的准则,从而符合 PCI。
渗透测试有一系列的好处,可以帮助识别任何潜在的漏洞,但是,它本身并不能防止数据泄露。事实上,即使是经过最仔细测试和分析的基础设施或应用程序也可能成为安全漏洞或攻击的受害者。
渗透测试的局限性
随着现有的网络威胁环境随着威胁的不断发展而增加,以及错误部署和简单错误配置的机会性利用,光靠 pen 测试是不够的。
尽管渗透测试提供了一系列的好处,但是它也有一些主要的局限性,这些局限性会对您的业务产生巨大的影响。
下面是您应该知道的渗透测试的一些主要限制:
时间限制
通常,渗透测试是作为需要在预定义的时间段内完成的限时评估来执行的。测试团队必须识别潜在的威胁和漏洞,并在指定的时间内产生结果。
渗透测试人员还必须在测试结束时创建一份报告,其中包括对已发现的漏洞、使用的方法以及执行摘要的描述。他们还必须定期拍摄相关的截图,并在测试完成后将其添加到最终报告中。
相比之下,攻击者不受时间限制,他们可以有足够的时间来识别和利用更多的漏洞。因此,像渗透测试这样的限时评估让攻击者比渗透测试人员更有优势,让他们有更多的时间来利用应用程序。
因此,除了渗透测试之外,我们推荐白盒评估,这是一种评估软件和网络的内部结构、编码和设计的测试方法,基本上,测试人员可以完全了解网络、应用程序是如何设计的。它有助于识别内部安全漏洞以及编码过程或网络配置中的中断或结构不正确的流。它还单独测试每个函数、对象和语句。
范围的限制
一些组织有选择地执行安全测试,这意味着他们不会测试所有的东西。这可能是由于缺乏资源、预算限制、糟糕的安全策略或其他因素。
类似地,渗透测试人员的范围有限,由于这些限制,他们经常不得不离开系统的许多部分。
例如,很多时候,利用依赖于系统的交互。因此,如果 pen 测试的范围仅限于一个系统,那么系统交互中出现的漏洞就不会被发现。
这导致了不充分和质量差的渗透测试,可能在以后的阶段对您的组织造成损害。
访问限制
在 pen 测试中,测试团队通常会限制对目标环境的访问。
例如,网络通常被划分为多个网段,渗透测试只能访问那些拥有服务器或可以从 internet 访问的特定网段,这样团队就可以模拟真实的攻击。
但是,这种访问受限的 pen 测试将无法揭示整个网络上的配置问题和潜在漏洞。
检测漏洞的一个有效方法是进行白盒测试和渗透测试。这样,测试人员将获得关于网络、应用程序源代码、运行它的服务器、它的详细网络基础设施以及所涉及的 IP 地址的完整信息。
白盒网络漏洞评估通过从不同角度攻击网络来帮助暴露安全威胁。对于应用程序,您可以进行代码审查,这将帮助您发现动态测试中可能不明显的安全威胁和弱点,如加密算法、密码如何存储等。
方法的局限性
进行渗透测试的目的是利用系统,通常是以系统无法处理的方式做事情。
在渗透测试期间,目标基础设施或系统可能会崩溃。因此渗透测试团队被限制只能使用一组特定的方法来避免停机或系统崩溃。
例如,通过使用另一种攻击方法来创建分布式拒绝服务(DDoS)洪流以转移网络或系统管理员,这通常是攻击者搞垮组织的理想方式。
然而,团队可能会避免使用这种方法进行渗透测试,因为它们会导致系统停机。
其他时候,自动化技术是禁区,这可能会使系统暴露于易受攻击者攻击的漏洞,例如等待在互联网可访问系统中利用这种自动化的脚本小子(skiddies)。
这些攻击者是不熟练的个人,他们不断寻找利用计算机系统中众所周知且容易找到的弱点来获取对它们的访问,而不理解后果。
渗透测试人员的技能限制
渗透测试的成功和质量与渗透测试团队的经验和技能成正比。每个渗透测试可以分为三大类:系统、网络和应用程序渗透测试。
在网络渗透测试方面经验丰富的渗透测试人员可能无法成功执行应用程序渗透测试。随着技术的不断发展和升级,找到能够进行高质量渗透测试的熟练人员变得越来越困难。
与此同时,有时间的更熟练的攻击者可能会对系统造成很大的破坏。
虽然测试人员可能对 Apache web 服务器有深入的了解,但是他们可能对 Internet 信息服务(IIS)服务器缺乏经验。拥有相同技术的经验对于渗透测试的成功至关重要。
自定义漏洞的限制
通常,渗透测试团队需要跳出框框思考,并创建自定义的漏洞。例如,在一些高度安全的环境中,普通的笔测试工具和框架用处不大。
因此,渗透团队必须构建在安全环境中也有效的自定义漏洞。创建自定义漏洞还需要手动编写脚本来定义入侵的路径,以到达进行 pen 测试的目标。
这可能非常耗时,并且不是进行常规安全测试的有效方式。此外,它不是大多数渗透测试人员的技能集的一部分。手动编写脚本和创建自定义漏洞利用代码会极大地影响进行测试所需的预算和时间。
实验的局限性
渗透测试人员只允许使用客户认可的开发框架和工具。由于不是每个工具都是一体化的,它们可能缺少一些特性或者错过测试的一些部分,测试团队将不得不寻找替代方法来有效地执行测试。
此外,来自客户和高层管理人员的严格指示会限制渗透团队在批准的范围内进行实验的能力。另一方面,攻击者可以自由地绕过安全测试,创造新的攻击途径。
外卖食品
渗透测试在发现安全漏洞方面起着重要的作用。但是,您应该意识到它的局限性,因为它们会对您的组织产生巨大的影响。消除渗透测试并不是一个理想的解决方案,但是您总是可以将它与其他有效的安全方法和过程相结合来执行适当的测试。
关于作者:
Steve Kosten 是 Cypress Data Defense 的首席安全顾问,也是“Java/JEE 中的 SANS DEV541 安全编码:开发可防御应用程序”课程的讲师。
用 Python 制作几行漂亮的散点图,让你的报告出类拔萃
由 Pyechart 库支持
每个人都知道散点图是什么样子——几个点分散在具有水平轴和垂直轴的平面上。散点图是说明趋势的有用数据可视化工具。
我在本教程中将要介绍的散点图比普通的散点图更吸引人。它是动态的,每个点都有涟漪效应,你可以滑动滚动条来过滤数据。下面的图表是我们要做的。要创建这个图表,您只需要几行 Python 代码。

在编写这几行代码之前,您需要安装名为 Pyechart 的可视化软件包。这是一个 Python echarts 绘图库。它提供了 30 多种图表。最新版本是 1.7.1,发布于 2020 年 3 月 12 日。你可以 pip 安装它。
pip install pyecharts==1.7.1
安装完库后,我们可以开始构建漂亮的条形图:
#import libraries
from pyecharts.charts import Bar
from pyecharts import options as opts#create dataset for the chart, v1 is the revenue of Shopify in million dollars, x is the year
v1 = [24,50,105,205,389,673,1073,1578]
x = [“2012”, “2013”, “2014”, “2015”, “2016”, “2017”,”2018",”2019"]from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts import options as optsc = (
EffectScatter()
.add_xaxis(x)
.add_yaxis(“Shopify”, v1,is_selected = True,symbol_size = 20, symbol=SymbolType.DIAMOND)
)
c.render_notebook()
只用三行代码,你就会得到这样一个图表,

您可以添加另一系列数据来比较两家公司的收入表现。我准备再加一个电商——阿里巴巴。
v1 = [24,50,105,205,389,673,1073,1578] @Shopify revenue
v2 = [3,5,8,12,16,23,40,56,72]. #Alibaba revenue
x = [“2012”, “2013”, “2014”, “2015”, “2016”, “2017”,”2018",”2019"]from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts import options as optsc = (
EffectScatter()
.add_xaxis(x)
.add_yaxis(“Shopify”, v1,is_selected = True,symbol_size = 20, symbol=SymbolType.DIAMOND)
.add_yaxis(“Alibaba”, v2,is_selected = True,symbol_size = 20)
)
c.render_notebook()

Pyechart 库提供了许多种形状,如“圆形”、“矩形”、“圆形矩形”、“三角形”、“菱形”、“大头针”、“箭头”和“无”。您需要使用大写字母将这些值传递给参数,例如 SymbolType.DIAMOND。
现在让我们添加标题和副标题来完成图表。
v1 = [24,50,105,205,389,673,1073,1578]
v2 = [3,5,8,12,16,23,40,56,72]x = [“2012”, “2013”, “2014”, “2015”, “2016”, “2017”,”2018",”2019"]from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts import options as opts
c = (
EffectScatter(opts.InitOpts(width = ‘900px’,height = ‘500px’))
.add_xaxis(x)
.add_yaxis(“Shopify”, v1,is_selected = True,symbol_size = 20, symbol=SymbolType.DIAMOND)
.add_yaxis(“Alibaba”, v2,is_selected = True,symbol_size = 20)
.set_global_opts(
title_opts=opts.TitleOpts(title=”Revenue ($M) between year 2012 and 2019", subtitle=”Shopify vs Alibaba”,pos_left=”left”),
)
)
c.render_notebook()

我们可以进一步美化图表,让图表更具互动性。我们将添加一个滑动条。
要添加滑动条,我们需要添加选项。全局选项设置中的 VisualMapopts 函数。
v1 = [24,50,105,205,389,673,1073,1578]
v2 = [3,5,8,12,16,23,40,56,72]
x = [“2012”, “2013”, “2014”, “2015”, “2016”, “2017”,”2018",”2019"]from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts import options as optsc = (
EffectScatter(opts.InitOpts(width = ‘900px’,height = ‘500px’))
.add_xaxis(x)
.add_yaxis(“Shopify”, v1,is_selected = True,symbol_size = 20, symbol=SymbolType.DIAMOND)
.add_yaxis(“Alibaba”, v2,is_selected = True,symbol_size = 20)
.set_global_opts(
title_opts=opts.TitleOpts(title=”Revenue between year 2012 and 2019", subtitle=”Shopify vs Alibaba”,pos_left=”left”),
**visualmap_opts=opts.VisualMapOpts(pos_left=”right”,type_=”color”, max_=2000, min_=0, pos_bottom=50)**
)
)
c.render_notebook()
pos_left 是定义滑动条的位置。
类型是定义滑动条的类型,可以是“颜色”或“大小”。
max_ 和 min_ 限制滑动条的最大值和最小值。
pos_bottom 用于定义到底部的距离。

Pyechart 提供了美化标签和涟漪效果的选项。
使用标签选项,您可以定义位置、字体、大小、粗细、颜色、对齐等。
使用效果选项,你可以改变笔刷类型,颜色,符号,符号大小等来获得你想要的动画效果。
我给标签和效果选项添加了一些参数,如下所示。
v1 = [24,50,105,205,389,673,1073,1578]
v2 = [3,5,8,12,16,23,40,56,72]
x = [“2012”, “2013”, “2014”, “2015”, “2016”, “2017”,”2018",”2019"]from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts import options as opts
c = (
EffectScatter()
.add_xaxis(x)
.add_yaxis(“Shopify”, v1,is_selected = True,symbol_size = 15, symbol=SymbolType.DIAMOND)
.add_yaxis(“Alibaba”, v2,is_selected = True,symbol_size = 15)
.set_global_opts(
title_opts=opts.TitleOpts(title=”Revenue between year 2012 and 2019", subtitle=”Shopify vs Alibaba”,pos_left=”left”),
visualmap_opts=opts.VisualMapOpts(pos_left=”right”,type_=”color”, max_=2000, min_=0,pos_bottom=50))
.set_series_opts(
**label_opts=opts.LabelOpts(is_show=True, #whether the label will be shown
position=’right’, #location of the label
font_style=’italic’), #font of the label
effect_opts = opts.EffectOpts(scale = 3, #scale of ripples
period=5, #period of the animation
brush_type=’fill’), #either ‘stroke’ or ‘fill’
)**
)
c.render_notebook()
你会有一个更加引人注目的图表。

有许多选项和参数,你可以探索和尝试,以美化你的图表。
如果你对制作其他类型的漂亮图表感兴趣,你可以看看我的其他帖子。
- 用 python 制作美丽的 Nightinggale 玫瑰图-可视化 covid19 死亡率
- 用 Python 用几行字做一个漂亮的水球图
- 用 Python 中的几行代码制作一个漂亮的条形图
- 用 Python 制作的动画泡泡图——灵感来自汉斯·罗斯林教授
- 用 Python 制作最可爱的图表——用手绘图表可视化你的数据
- 使用 Python 中的 Matplotlib 绘制一个独特的柱状图
在 Mapbox 中制作新冠肺炎地图
美国各州新冠肺炎比率的可视化

美国新冠肺炎确诊病例。(迭戈·乌尔塔多)
作者:迭戈·乌尔塔多
在地图上显示数据分布的一种方法是使用 choropleth,这是一种专题地图,其中的区域根据特定值进行着色。Choropleth 地图提供了一种简单的方法来直观显示某个地理区域内的测量值如何变化或显示某个区域内的可变性水平,是一种专题地图,其中各个区域按照代表每个区域内地理特征汇总的统计变量(如人口密度或新冠肺炎病例)的比例进行着色或图案化。在本指南中,您将使用 Mapbox Studio 和 Mapbox GL JS 制作显示新冠肺炎确诊病例密度的美国各州地图。

美国各州显示新冠肺炎确诊病例密度(迭戈·乌尔塔多)
入门
在本指南中,您将使用两种地图框工具:
- Mapbox Studio 添加您的数据并创建您的地图样式。
- Mapbox GL JS 为您的地图添加交互性,并将其发布到 web 上。
处理数据
首先,从美国新冠肺炎追踪 API、美国各州首府和 GeoJSON 表示美国空间(几何图形)的对象下载。根据 GeoJSON 规范(RFC 7946) :
GeoJSON 是一种用于编码各种地理数据结构的格式[…]。GeoJSON 对象可以表示一个空间区域(几何)、一个空间有界实体(要素)或一组要素(要素集合)。GeoJSON 支持以下几何类型:点、线串、面、多点、多线串、多面和 GeometryCollection。GeoJSON 中的要素包含几何对象和附加属性,FeatureCollection 包含要素列表。

美国空间几何 geoJson (Diego Hurtado)
我们甚至可以使用这些属性来设计我们的传单向量。这里有一个 GeoJSON 的例子:
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Alabama",
"density": 6270,
"geometry": { "type": "Polygon", "coordinates": []}
};
数据清理
下载文件后,过滤并清理数据。这个过程的某些部分是完全可选的,比如重命名或过滤字段。但是,过滤声明 API 没有信息(' AS ',' GU ',' MP ',' VI ')。过滤掉美国投影中未显示的不需要的要素,如关岛和其他美国领土。如果不像关岛那样对这些州进行过滤,重新投影后将会得到空的几何,这会给信息的索引带来问题。
清理数据后,用每个州的确认数据替换 geoJSON 的密度值。
for i in range(1,len(s_array)):
features = data_geo['features'][i]
features['properties']['density'] = int(s_array[i])
data_geo['features'][i]['properties']['density'] = int(confirmedCasesStates[i])
更新数据的示例:
data_geo['features'][Alabama]['properties'][6270] = int(confirmedCasesStates[6500])
在 Studio 中上传并设计风格
要学习重新投影您的数据以添加到您的投影中,请跟随我们的如何在 Mapbox Studio 中创建 choropleth 地图的操作视频,跟随本教程使用 map box Studio 创建 choropleth 地图,如果您错过了某些步骤。来源:地图框
要将 GeoJSON 文件上传到 Mapbox,将其直接拖放到 tileset dashboard 中,或者如果文件太大或几何图形需要简化,使用 Tippecanoe 将其平铺。
在您的 Tilesets 页面上,单击新建 tileset 按钮。选择文件 covidataStates.geojson并上传至您的账户。
上传完成后,单击文件名旁边的箭头打开其信息页面。

来源:地图框
创建新样式
检查完数据后,是时候创建新的样式了,这样您就可以将它放在地图上了!转到您的风格页面。点击新样式按钮。找到基础模板样式,点击自定义基础模板。

来源:地图框
添加新层
要添加人口密度数据并设置其样式,您需要向地图添加新图层:
- 如果造型面板显示组件选项卡,切换到层选项卡。
- 在图层面板的顶部,点击 + 按钮添加一个自定义图层。
在新图层面板中,在数据源列表中查找statedata源。单击 tileset,然后选择源图层作为此新样式图层的源。
默认的基本地图视图不以美国为中心。Mapbox Studio 识别出您上传的数据集中在不同的位置,因此它显示消息“此 tileset 在您的地图视图中不可用。”点击转到数据,地图视图将重新聚焦美国。
您的新图层将在 x 射线图上高亮显示。

来源:地图框
点击样式标签,地图将切换回样式模式显示你的新图层。您将在地图上看到默认样式的州数据(100%不透明度的黑色)。

设置图层样式
在 Mapbox Studio 样式编辑器中,您可以根据新冠肺炎确诊病例密度为每个州指定一种颜色。在statedata图层中点击样式链接。接下来,点击数据范围样式。
选择一个数字数据字段,选择density,因为您想要根据其新冠肺炎确诊病例密度设置每个州的样式。

变化率为线性。点击编辑并改为选择步骤。点击完成。由于您已将变化率设置为步长,因此停止点之间的每个密度范围的颜色将是一致的。

现在是时候开始添加停止和颜色了!您将创建几个停靠点,将各州分成具有相似新冠肺炎确诊病例密度的组。在第一个密度停止点点击编辑。第一站固定在 1.264 ,基于你上传的数据集中的信息。点击它,改变颜色为#FFEDA0。点击完成。
将下一站的密度改为 361,颜色也改为#FFEDA0。点击完成。

点击 +添加另一个停止点。将密度改为 361(数据最小值),将颜色改为#FED976。点击完成。
根据确诊病例的数量创建以下附加步骤示例:
341:#FED9761050:#FEB24C2000:#FD8D3C5911:#FC4E2A13319:#E31A1C288054:#BD0026

发布样式
现在你的地图看起来不错,是时候发布了!点击屏幕右上角的发布按钮,然后在下一个提示下再次点击发布。

网页
以下是您需要开始的内容:
下载模板:
- 一个访问令牌 。您可以在您的帐户页面上找到您的访问令牌。
- 样式 URL 为您的样式。从你的样式页面,点击你的人口密度样式旁边的菜单按钮,然后点击剪贴板图标复制样式 URL 。
- Mapbox GL JS 。用于构建 web 地图的 Mapbox JavaScript API。
- 一个文本编辑器。毕竟,您将编写 HTML、CSS 和 JavaScript。
现在,您已经为页面添加了结构,您可以开始编写一些 JavaScript 了!您需要做的第一件事是添加您的访问令牌。没有这一点,其余的代码将无法工作。注意:下面所有的代码都应该在 *script* 标签之间。:
mapboxgl.accessToken = 'pk.......';
现在您已经添加了页面的结构,您可以向map div 添加一个 map 对象。对于您在本指南第 1 部分中创建的样式,一定要用样式 URL 替换your-style-url——否则,代码将无法工作!
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'your-style-url' // replace this with your style URL
});
创建间隔和颜色数组
创建包含州数据的图层样式时使用的停靠点列表,将允许我们在后续步骤中向地图添加图例。
var layers = ['0-10', '10-20', '20-50', '50-100', '100-200', '200-500', '500-1000', '1000+'];
var colors = ['#FFEDA0', '#FED976', '#FEB24C', '#FD8D3C', '#FC4E2A', '#E31A1C', '#BD0026', '#800026'];
任务完成
您已经创建了一个交互式 choropleth 地图!

美国各州新冠肺炎比率的可视化(Diego Hurtado)
要学习重新投影您的数据以添加到您的投影中,请跟随我们的操作视频“如何在 Mapbox Studio 中创建 choropleth 地图”。
另一个例子是墨西哥各州新冠肺炎比率的可视化。

墨西哥新冠肺炎率的可视化
领英:【https://www.linkedin.com/in/diego-gustavo-hurtado-olivares/
五分钟做一个深度学习 iOS App
制作一个深度学习应用程序可能看起来令人生畏,但实际上并没有那么糟糕。

介绍
深度学习现在真的很热,人们似乎喜欢 iPhones。
放在一起吧:)。不久前还没有很多关于如何做这件事的教程,现在有很多了。我想用
增加一个最高效的最小工作示例。我们将建立一个深度学习 iOS 应用程序,它可以在五分钟内对 CIFAR10 进行分类。深度学习和 iOS 开发可能看起来很可怕,但一旦开始,它们并不那么糟糕。本教程结束时,您应该有一个工作的 iPhone 应用程序,您可以使用 Keras 训练的自定义模型在内置仿真器中运行。
如果你想看本教程的现场代码演示,请查看下面的视频,我现场编码本教程,并证明它真的只需要五分钟。
本教程的视频演示。
设置
按照本教程,你需要 Python3 和一台运行最新 XCode 的 MacBook。你可以通过购买一台 Mac 来获得 XCode,通过运行
安装必要的 Python3 库:
pip install keras coremltools
培训/准备模型
我们没有时间从头开始设计模型!我们只有 5 分钟了!让我们从 Keras 文档中偷一个。如果您熟悉 Keras,您会看到它只是加载到 CIFAR 数据集中,然后在其上训练一个简单的 CNN。为了快速完成本教程,我们需要做一些调整。首先,将第 19 行中的 epochs 数改为只有 1。这将使我们的模型在 Macbook Pro 上大约 3 分钟内完成训练。
接下来,将第 20 行的 data_augmentation 参数更改为 False。这将使它根据提供的数据进行训练,并且不会翻转或调整任何训练图像。这只是加快了一点速度,但在现实中,如果你想训练一个好的模型,你绝对应该离开这些设置。
最后,去掉第 121 行及以后的内容,我们不需要保存我们的模型,也不需要(想)知道有多好(坏?)是。我们只是需要一个模型快!
在我们开始培训之前,还有最后一件事,我们需要把这个经过培训的模型做成史蒂夫·乔布斯能够理解的形式。为此,我们向苹果寻求指导。在页面的底部,你会看到一个“转换你的模型”部分窃取了这些代码行,并将它们粘贴在我们窃取的 Python 脚本的底部。我们需要做一些小的改动,使它们能够与 Keras 模型一起工作,因为这些模型是为 Cafe 编写的。如下更新它们。基本上,我们只需要将转换器调用改为 Keras,而不是 Caffe。然后我们需要填充一些关于我们模型的信息。
将 Keras 模型转换为 CoreML 以用于 iOS。
这个 convert 方法有几个值得解开的字段。第一个参数是我们想要转换的模型,它应该是一个 Keras 模型。
- input_names 是可选名称,将在核心 ML 模型的接口中使用,以引用 Keras 模型的输入。对于这个例子,我把它们都叫做“图像”。
- image_input_names 是 Keras 模型的输入名称列表,这是上面 input_names 字段的子集。核心 ML 可以将这些名称视为图像
- class_labels 是模型将使用的类标签列表。对于 CIFAR10,该列表是飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车
构建一个 iOS 应用程序
当我们的模型正在酝酿时,让我们建立一个用于分类图像的 iOS 应用程序。我没有时间设计应用程序,所以我打算偷一个苹果认可的。此命令将下载一个使用图像分类模型的 iOS Xcode 项目。
wget [https://docs-assets.developer.apple.com/published/a6ab4bc7df/ClassifyingImagesWithVisionAndCoreML.zip](https://docs-assets.developer.apple.com/published/cdf821b12b/ClassifyingImagesWithVisionAndCoreML.zip)unzip ClassifyingImageswithVisionandCoreML.zip
人们似乎喜欢苹果,所以它不会太差,对不对?现在只要打开这个
花哨的新 Xcode 项目,我们就完成了我们的应用程序!
(注意,有时苹果喜欢毫无理由地更改他们链接的名称,所以如果上面的 wget 命令不起作用,你也可以在这里下载这个 Xcode 项目
修理坏掉的东西
有几件事不太适合这个应用程序,我们需要注意。
1.我们需要将新训练的模型添加到 Xcode 项目中,并更新代码以使用我们的模型。
2.CIFAR 中使用的图片大小与您的 iPhone 拍摄的图片大小不同。我们需要缩放图像。
添加模型
将我们刚刚用 Keras 训练的新模型复制到我们的应用程序项目中的文件夹,该文件夹位于Vision+ML Example/Model/cifar . ML Model下,并通过单击下图中概述的链接使用 Xcode 的构建阶段来链接它。

如何将训练好的 Keras 模型添加到 Xcode 项目中。
现在,我们已经将新训练的模型放在项目可以访问的地方,让我们更新 imageclassificationviewcontroller . swift 中的代码,以识别我们的新模型更改行 30(可能会更改)为:
let model = try VNCoreMLModel(for: CIFAR().model)
我们只是将模型名称从 MobileNet 更改为我们在上一步中所称的模型,在本例中,我们将其命名为 CIFAR。就这样,我们的模型现在在代码中链接起来了。最后一步是管理图像大小。
修复规模问题
我们的 Keras 模型期望图像是 64 x 64 x 3 的图像。我们需要让代码反映这一点。默认值为 224 x 224 x 3。您可以通过在 Xcode 中单击 MobileNet.mlmodel 模型文件来查看这一点。在预测下,您将看到预期的图像大小。

如何在默认机型上查看图像输入尺寸?
幸运的是 StackOverflow 在这里支持我们,我刚刚谷歌了一下“在 swift 中调整图像大小”,这个方便的解决方案就出现了,它确实做了我们需要的事情。将 Swift3 代码复制到第 20 行。
调整图像大小的 Swift 代码。
现在我们只需要在我们的应用程序中调用这个新功能。将 updateClassifications 的前几行改为:
这将在通过我们的模型运行之前调整所有图像的大小。现在只需点击播放按钮,享受你的应用程序!
结束了
我们完了!现在就建 app:)。你可以把任何简单的 Keras 型号
放到 iOS 应用程序中。试着把模型做的更好,或者把其他东西分类。希望这篇教程展示了在 iPhone 上部署深度学习模型是多么简单。
用 Python 制作一个简单的 NBA 投篮图
你曾经想制作一个好看的 NBA 投篮图表吗?比以往任何时候都简单!

在 Unsplash 上由 Tamarcus Brown 拍摄的照片
最近,我偶然发现了这个名为nba_api的精彩 Python 包,可以在这里找到,它作为一个非常简单的 API 客户端从www.nba.com检索统计数据。我个人一直想创建像网上一样的球员投篮图表,但收集投篮位置数据似乎是一项艰巨的任务。这就是nba_api来救援的地方!首先,让我们安装软件包:
pip install nba_api
现在我们已经安装了nba_api,我们现在可以导入所有需要的包来制作我们自己的拍摄图。
**# Import packages** from nba_api.stats.endpoints import shotchartdetail
import json
import requests
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
加载数据
要发出我们的 API 请求,我们需要一个球员 ID 号和球队 ID 号,这两个号码都用于检索投篮数据。为了方便地提取这些值,我们可以利用另一个 Github 库这里是。有两个 JSON 文件,team.json和players.json,包含了我们需要的所有球员和球队 ID 号。我们将使用 Python 将这些 JSON 文件加载到 dictionary 对象数组中。
**# Load teams file** teams = json.loads(requests.get('[https://raw.githubusercontent.com/bttmly/nba/master/data/teams.json').text](https://raw.githubusercontent.com/bttmly/nba/master/data/teams.json').text))**# Load players file** players = json.loads(requests.get('[https://raw.githubusercontent.com/bttmly/nba/master/data/players.json').text](https://raw.githubusercontent.com/bttmly/nba/master/data/players.json').text))
现在我们已经加载了所有的球员和球队数据,我们可以创建助手函数,它接受球队名称和球员名称的输入,并返回他们各自的 ID 号。在这两种情况下,如果找不到球员或球队名称,函数返回-1:
**# Get team ID based on team name**
def get_team_id(team):
for team in teams:
if team['teamName'] == team:
return team['teamId']
return -1**# Get player ID based on player name**
def get_player_id(first, last):
for player in players:
if player['firstName'] == first and player['lastName'] == last:
return player['playerId']
return -1
现在让我们来看看我们的功能:
**# Get the team ID number for the Knicks**
get_team_id('New York Knicks')
>>> 1610612752**# Get the player ID number for LeBron James**
get_player_id('LeBron', 'James')
>>> 2544
现在我们有了收集特定 NBA 球员投篮数据所需的所有数据。让我们现在做一个例子——作为一个湾区本地人和金州勇士队的球迷,我有兴趣为斯蒂芬·库里令人难以置信的 2015-16 年一致 MVP 赛季创建一个投篮图表。我们首先按如下方式构建我们的 JSON 请求:
**# Create JSON request** shot_json = shotchartdetail.ShotChartDetail(
team_id = get_team_id('Golden State Warriors'),
player_id = get_player_id('Stephen', 'Curry'),
context_measure_simple = 'PTS',
season_nullable = '2015-16',
season_type_all_star = 'Regular Season')
context_measure_simple —这决定了使用哪个“上下文”来搜索镜头。点数(PTS)是默认的,将导致所有投篮。如果你想要所有的尝试(成功的和失败的),你可以使用“FGA”作为你的上下文。
season_nullable —我们感兴趣的季节(2015–16)
season_type_all_star —我们对这个季节的哪个部分感兴趣(Pre Season、Regular Season、Playoffs、All Star)
ShotChartDetail()的文档可以在这里找到——正如你将看到的,我只涉及了你可以通过你的请求做的事情的一小部分,而可能性几乎是无穷无尽的!
现在我们可以将 JSON 数据加载到一个 dictionary 对象中:
**# Load data into a Python dictionary** shot_data = json.loads(shot_json.get_json())
我们的相关数据可以在resultSets键下找到,它本身就是一个数组——我们需要这个数组的第一个元素。
**# Get the relevant data from our dictionary** relevant_data = shot_data['resultSets'][0]
变量relevant_data本身是一个字典,键headers对应于列标题,rowSet对应于实际的数据行。
**# Get the headers and row data**
headers = relevant_data['headers']
rows = relevant_data['rowSet']
最后,我们可以将这些数据放入一个pandas数据帧中,如下所示:
**# Create pandas DataFrame**
curry_data = pd.DataFrame(rows)
curry_data.columns = headers
好了,现在我们可以看看在新创建的数据框架中我们可以访问哪些列了!
**# Print the columns of our DataFrame**
curry_data.columns
>>> Index(['GRID_TYPE', 'GAME_ID', 'GAME_EVENT_ID', 'PLAYER_ID', 'PLAYER_NAME', 'TEAM_ID', 'TEAM_NAME', 'PERIOD', 'MINUTES_REMAINING', 'SECONDS_REMAINING', 'EVENT_TYPE', 'ACTION_TYPE', 'SHOT_TYPE', 'SHOT_ZONE_BASIC', 'SHOT_ZONE_AREA', 'SHOT_ZONE_RANGE', 'SHOT_DISTANCE', 'LOC_X', 'LOC_Y', 'SHOT_ATTEMPTED_FLAG', 'SHOT_MADE_FLAG', 'GAME_DATE', 'HTM', 'VTM'], dtype='object')
由于数据帧中的所有行都对应于拍摄镜头,我们可以使用LOC_X和LOC_Y来绘制它们。通过检查数据,x 坐标从-250 到 250(每 1/10 英尺),y 坐标从 0 到 940(也是每 1/10 英尺)。我们可以利用这些信息在一个 NBA 球场的覆盖图上画出拍摄地点。但首先,让我们创建一个篮球场!
创建篮球场
为了创建我们的篮球场,我们将编写一个函数,它接受一个matplotlib轴对象和一种颜色(用于球场标记),并生成一个球场的绘图。我将快速浏览一遍,但它基本上是一种将 NBA 球场的真实世界尺寸映射到我们情节中的线条和形状的练习。我们从函数定义开始:
**# Function to draw basketball court** def create_court(ax, color):
我们现在继续绘制单个元素。首先,我们创建一条 22 英尺长的短角三分线,并向球场内延伸 14 英尺(请记住,我们将使用击球坐标,因此我们使用 1/10 英尺的单位)。
**# Short corner 3PT lines**
ax.plot([-220, -220], [0, 140], linewidth=2, color=color)
ax.plot([220, 220], [0, 140], linewidth=2, color=color)
现在,我们可以连接三点弧的其余部分,它距离篮筐中心 23.75 英尺。边缘本身在球场内 6 英尺,因为我们知道角落三分线延伸 14 英尺,我们可以创建一个从该点垂直延伸 15.75 英尺的弧线。
**# 3PT Arc**
ax.add_artist(mpl.patches.Arc((0, 140), 440, 315, theta1=0, theta2=180, facecolor='none', edgecolor=color, lw=2))
接下来是车道和钥匙顶端的圆圈。球道由两个长方形组成,一个宽 16 英尺,另一个宽 12 英尺,都延伸到球场内 19 英尺。钥匙顶部的圆圈半径为 6 英尺。
**# Lane and Key**
ax.plot([-80, -80], [0, 190], linewidth=2, color=color)
ax.plot([80, 80], [0, 190], linewidth=2, color=color)
ax.plot([-60, -60], [0, 190], linewidth=2, color=color)
ax.plot([60, 60], [0, 190], linewidth=2, color=color)
ax.plot([-80, 80], [190, 190], linewidth=2, color=color)
ax.add_artist(mpl.patches.Circle((0, 190), 60, facecolor='none', edgecolor=color, lw=2))
现在让我们添加篮框和篮板——篮板进入球场 4 英尺,篮框中心 6 英尺,半径 0.75 英尺。
**# Rim**
ax.add_artist(mpl.patches.Circle((0, 60), 15, facecolor='none', edgecolor=color, lw=2))
**# Backboard**
ax.plot([-30, 30], [40, 40], linewidth=2, color=color)
最后,我们移除刻度线并设置轴限制——在本例中,x 从[-250,250]开始,y 从[0,470]开始(球场的一半)。
**# Remove ticks**
ax.set_xticks([])
ax.set_yticks([])
**# Set axis limits** ax.set_xlim(-250, 250)
ax.set_ylim(0, 470)
现在,为了检查我们是否做得正确,我们可以创建一个空白图形,并在上面绘制我们的球场。为了保持真实的比例,我们设置了figsize,这样我们就有了正确的纵横比:
**# General plot parameters**
mpl.rcParams['font.family'] = 'Avenir'
mpl.rcParams['font.size'] = 18
mpl.rcParams['axes.linewidth'] = 2**# Draw basketball court**
fig = plt.figure(figsize=(4, 3.76))
ax = fig.add_axes([0, 0, 1, 1])
ax = create_court(ax, 'black')
plt.show()

创建拍摄图表
为了创建我们的拍摄图表,我们将使用一个名为hexbin的图,它内置了matplotlib。这个函数会根据位置将所有的镜头分入六边形的箱子中,然后根据每个箱子中物品的数量给它们上色。按照上面的方法画出球场后,我们使用下面的线来创建我们的 hexbin 图。我们在 y 坐标上加 60,因为数据集中的所有坐标都是相对于边缘中心的,我们知道边缘位于基线内 6 英尺处:
**# Plot hexbin of shots**
ax.hexbin(curry_data['LOC_X'], curry_data['LOC_Y'] + 60, gridsize=(30, 30), extent=(-300, 300, 0, 940), cmap='Blues')
gridsize —六边形箱子的尺寸(x 尺寸,y 尺寸)
extent — (xmin,xmax,ymin,ymax) —我们使用比轴限制更大的值来确保六边形一直到达我们绘制区域的边界(绘图区域之外的六边形被剪裁,因此我们看不到它们)

我们的 hexbin 图似乎工作得很好,但有太多的对比——即使三分球数很大(库里投了 400 多个),靠近篮筐的投篮支配了颜色。由于这个拍摄图纯粹是眼睛的指南(我们不能通过观看拍摄图来容易地做出定量的决定),我们可以使用对数宁滨来提高对比度。为此,我们使用以下代码行:
**# Plot hexbin of shots with logarithmic binning**
ax.hexbin(curry_data['LOC_X'], curry_data['LOC_Y'] + 60, gridsize=(30, 30), extent=(-300, 300, 0, 940), bins='log', cmap='Blues')

好多了!现在,我们可以做的最后一件事是在图表顶部添加带有球员姓名和赛季的文本注释:
**# Annotate player name and season**
ax.text(0, 1.05, 'Stephen Curry\n2015-16 Regular Season', transform=ax.transAxes, ha='left', va='baseline')

其他 MVP 拍摄图
我们可以对此进行延伸,绘制出库里 2015-16 赛季以来的 3 个 MVP 的投篮图表,供我们参考。
2017 —拉塞尔·维斯特布鲁克
**# JSON request for Russell Westbrook**
shot_json = shotchartdetail.ShotChartDetail(
team_id = get_team_id('Oklahoma City Thunder'),
player_id = get_player_id('Russell', 'Westbrook'),
context_measure_simple = 'PTS',
season_nullable = '2016-17',
season_type_all_star = 'Regular Season')

2018 —詹姆斯·哈登
**# JSON request for James Harden** shot_json = shotchartdetail.ShotChartDetail(
team_id = get_team_id('Houston Rockets'),
player_id = get_player_id('James', 'Harden'),
context_measure_simple = 'PTS',
season_nullable = '2017-18',
season_type_all_star = 'Regular Season')

2019 —扬尼斯·阿德托昆博
**# JSON request for Giannis Antetokounmpo** shot_json = shotchartdetail.ShotChartDetail(
team_id = get_team_id('Milwaukee Bucks'),
player_id = get_player_id('Giannis', 'Antetokounmpo'),
context_measure_simple = 'PTS',
season_nullable = '2018-19',
season_type_all_star = 'Regular Season')

结束语
感谢您的阅读!本文的所有分析都可以在这个 Github 库中找到。我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系以获取更多更新和文章。
用 Python 制作一个漂亮的夜莺玫瑰图
设想新冠肺炎的死亡率
南丁格尔的玫瑰图,也被称为“极区图”或“鸡冠图”,是一个圆形图,结合了雷达图和柱形图的元素。这张特殊的图表是以护士、统计学家和改革家弗洛伦斯·南丁格尔的名字命名的。她发明了一种彩色统计图表,名为“东部军队的死亡原因图表”,生动地描述了在第二次世界大战(1954-1956)期间英国军队医院中不必要死亡的程度。图表显示,在战争过程中,流行病造成的英国人死亡比战场上受伤的多。
在本教程中,我们将使用 Pyechart 库用 Python 创建一个南丁格尔玫瑰图。我们甚至不需要导入数据!只需要几个步骤,你就会有一个这样的玫瑰图!

夜莺玫瑰图
步骤 1:导入库
import numpy as np
import pandas as pd
from pyecharts.charts import Pie
from pyecharts import options as opts
第二步:打开网站,通过剪贴板功能获取数据
import webbrowser
website = ‘[https://www.worldometers.info/coronavirus/'](https://www.worldometers.info/coronavirus/')
webbrowser.open(website)
Worldmeters 每天都以良好的格式更新新冠肺炎信息,因此本教程的数据来自该网站。Pandas 中的 read_clipboard()可以读取、复制、粘贴表格数据,并将其解析到一个数据框中。如果你想在小数据集上练习,这是一个非常有用的函数。其中一个限制是它不能处理合并的单元格。

来自 worldmeters.info 的快照
当您从 Worldmeters 复制表格时,请不要包括第一行,它有列名。第一行中的每个单元格都是合并单元格,clipboard()无法处理它。它将返回错误。
在复制了除第一行以外的整个表之后,执行下面的代码
data = pd.read_clipboard()
data
你会得到一张这样的桌子

第三步:第一行将被正确的列名替换
data.columns = [‘Country’,’TotalCases’,’NewCases’,’TotalDeaths’,’NewDeaths’,’TotalRecovered’,’ActiveCases’,’CriticalCondition’,‘TotCasesPerMillion’,’DeathsPerMillion’,’TotalTests’,’TestsPerMillion’]
data
然后,数据帧看起来更好。

步骤 4:数据操作
# remove "," from the dataset
for x in range(1,len(data.columns)):
data[data.columns[x]] = data[data.columns[x]].str.replace(‘,’,’’) #replace NaNs with zeros
data = data.fillna(0)#change the datatype from object to integer
for i in range (1,len(data.columns)):
data[data.columns[i]] = data[data.columns[i]].astype(float).astype(int)#create a column 'Death Rate'
data['DeathRate'] = data['TotalDeaths']/data['TotalCases']#sort the data frame by 'Death Rate' in descending order
data.sort_values(by=['DeathRate'], inplace=True, ascending=False)
步骤 5:选择死亡率最高的前 15 个国家
df=data[[‘Country’,’DeathRate’]].head(15) #select two columns and top 15 rowsdf[‘DeathRate’] = (df[‘DeathRate’]*100).round(1)
df
用于进一步可视化的数据框已准备就绪。

步骤 6:可视化数据
c = df[‘Country’].values.tolist()
d = df[‘DeathRate’].values.tolist()#create the color_series for the rosechart
color_series = [‘#802200’,’#B33000',’#FF4500',’#FAA327',’#9ECB3C’,
‘#6DBC49’,’#37B44E’,’#14ADCF’,’#209AC9',’#1E91CA’,
‘#2C6BA0’,’#2B55A1',’#2D3D8E’,’#44388E’,’#6A368B’,
‘#D02C2A’,’#D44C2D’,’#F57A34',’#FA8F2F’,’#D99D21']rosechart = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
# set the color
rosechart.set_colors(color_series)
# add the data to the rosechart
rosechart.add("", [list(z) for z in zip(c, d)],
radius=["20%", "95%"], # 20% inside radius,95% ourside radius
center=["30%", "60%"], # center of the chart
rosetype="area")# set the global options for the chart
rosechart.set_global_opts(title_opts=opts.TitleOpts(title='Nightingale Rose Chart',subtitle="Covid-19 Death Rate"),
legend_opts=opts.LegendOpts(is_show=False),
toolbox_opts=opts.ToolboxOpts())# set the series options
rosechart.set_series_opts(label_opts=opts.LabelOpts(is_show=True, position="inside", font_size=12,formatter="{b}:{c}%", font_style="italic",font_weight="bold", font_family="Century"),)
rosechart.render_notebook()
最后生成美丽的夜莺玫瑰图!

从图表中很容易看出,MS Zaandam 号游轮的死亡率最高。旁边是布隆迪、巴哈马和苏丹。据《纽约时报》报道,前 15 个国家的死亡率都超过了 10%,大大高于普通季节性流感的死亡率,美国的死亡率通常在 0.1%左右。
所以,呆在家里享受学习数据可视化吧!
如果你对制作其他类型的漂亮图表感兴趣,你可以看看我的其他帖子。
- 用 Python 用几行字做一个漂亮的水球图
- 用 Python 制作一个只有几行的漂亮条形图
- 用 Python 制作几行漂亮的散点图,让你的报告出类拔萃
- 用 Python 语言 Plotly 制作令人印象深刻的动画泡泡图——灵感来自汉斯·罗斯林教授
- 用 Python 制作最可爱的图表——用手绘图表可视化你的数据
将因果关系作为你下一个数据科学项目的目标
货币与利率的案例研究

莎伦·麦卡琴在 Unsplash 上的照片
序文
预测是大多数数据科学项目的目标。
虽然这导致了一些有趣的工作,但也导致了抑制因素:
- 理解机器学习模型背后的数学原理,
- 充分理解数据分析过程的各个方面;而且,
- 建立可理解的模型
这篇文章的目的是鼓励更多有抱负的(和当前的)数据科学家完成以因果关系为既定目标的项目。
为什么?
因为说服读者在 X 和 Y 之间存在因果关系通常比说服读者某个 ML 模型具有强大的预测能力更困难,后者通常是通过最小化(或在某些情况下最大化)一个不透明的度量来实现的。
数据科学家必须证明以下几点,以说服读者两个变量有因果关系:
- 建立一个的时间顺序。也就是说,如果 X 导致 Y ,那么 X 必须在 Y 之前。
- 建立变量之间的关系 。我们的变量必须是相关的。这种关系一定不是由第三个混淆变量造成的。
- 建立因果理论 。数据科学家必须解释与现有(或新)理论的因果关系。
满足这些条件在几个方面有利于数据科学家的教育:
- 他们迫使数据科学家理解其模型背后的数学原理。你不能把随机的模型拼凑在一起,直到你得到你想要的结果。你必须解释你的模型将如何回答你的研究问题。
- 他们提高了数据科学家的沟通技巧。
- 他们激励数据科学家获取领域知识。很多时候,雇主要求求职者除了技术技能 之外,还要有特定行业的知识 。
在本文的剩余部分,我将(尝试)证明利率和货币供应量之间的因果关系。
具体来说,我测试了两个假设:
1.对一个国家货币供应的积极冲击会降低利率
2.较低的利率在短期内会扩张经济
这里的希望是,我试图证明货币供应和利率之间的因果关系,这将向你展示如何构建你的下一个“以因果关系为重点”的数据科学项目。
文章的其余部分分为以下几个部分:
- 货币供应量和利率之间的关系
- 模型的解释
- 数据的解释
- 分析
- 结果
- 结论
请随意跳到你觉得最有趣的部分。
货币供应量和利率之间的关系
凯恩斯认为,消费者需求的货币数量取决于当前的利率。具体来说,较低的利率意味着消费者会要求更多的钱

作者图片
两种效应改变了货币需求:一种是收入效应,另一种是价格水平效应。
收入效应表明,当消费者财富增加时,货币需求也会增加。也就是说,当人们拥有更高的净值时,他们想买更多的东西;他们要求更多的现金来购买这些东西。
收入效应导致物价水平* 效应。当支出增加时,价格就会上涨(通货膨胀)。因此,人们需要更多的钱来维持他们在价格上涨前的购买力。*
注意,货币供给曲线是一条垂直线。竖线表示货币供给是外生。
换句话说,货币供应不受货币市场变动的影响。
该理论认为,当货币供应量增加时,利率就会下降(在上图中向右移动)。
为什么?
如果货币供应量增加,那么经济中的货币就会过剩。消费者将多余的钱投资到债券市场(那里是安全的)。这增加了对债券的需求,从而提高了债券的价格。当债券价格上涨时,该债券的利率(或收益率)就会下降。

作者图片
因此,货币供应量的增加导致债券市场利率下降。这种现象被称为 流动性效应。
我们可以将经济产出建模为:

作者图片
当利率下降时,债务变得更便宜。因此,消费、投资和政府支出都会增加,从而增加经济产出。
模型
为了证明上述理论,我需要首先检验几个变量(货币供给、利率和经济产出)之间的关系,其次证明一个变量(货币供给冲击)先于其他变量(利率和经济产出变化)。
因此,我使用的模型必须显示多个变量和之间的相互作用,它必须考虑到动态行为(动态行为是指模型允许以前时间段的值影响未来时间段的值)。
向量自回归(VAR)模型非常适合这一点!
增值转销公司
我们的风险值模型看起来像这样:

作者图片
在哪里
- yt 是因变量的向量
- Ai 是一个系数矩阵
- X_(t-k) 是自变量的向量,包括因变量的滞后阶
- ut 是误差向量
- k 是滞后订单的长度
VAR 模型是对我们正在研究的每个变量进行的线性回归模型。一个线性回归模型中的每个自变量都会成为另一个线性回归模型中的因变量。
因此,VAR:
- 向我们展示了变量之间的多重关系;而且,
- 允许滞后运算符的动态行为
完美!
数据
我将重点放在加拿大进行分析。请随意尝试不同的国家。
我使用加拿大统计局和圣路易斯联邦储备银行 1970 年至 2019 年的季度数据。有 200 个观察值。
感兴趣的变量有:
- M1 的增长率(M1 是货币供应量的狭义定义,包括活期存款和支票账户中的货币量)
- 三个月期国库券的收益率(通常用于模拟利率)
- 实际国内生产总值的增长率
我控制:
- 消费者价格指数
- 通货膨胀率
所有增长率均以同比百分比变化计算。季度 CPI 和三个月期国库券的收益率是通过对加拿大统计局的月度数据进行季度平均计算得出的。
分析
在深入研究 VAR 之前,让我们先了解一些数据可视化。
具体来说,我们想知道:
货币供应量的变化发生在利率变化之前还是之后?
*library(readxl)
library(ggplot2)
library(zoo)data <- read_excel(file.choose(), sheet = 'Data')# Set the time variable
data$qrtr <- as.yearqtr(1970 + seq(0,199)/4)# Make a new theme for ggplot to use.
new_theme <- theme_classic() + theme(text = element_text(color = "darkred")) + theme(legend.position="top") + theme(legend.title = element_text(color = "black"), legend.text = element_text(color = "black"))
theme_set(new_theme)# Create the graph
p <- ggplot(data, aes(x = qrtr)) + ylim(-5, 30) + geom_line(aes(y = narrowmg, color = "M1 Growth Rate")) + geom_line(aes(y = stir, color = "Interest Rate")) + labs(x = "Quarter", y = "Growth Rate (%)", title = "Was Keynes Right?", subtitle = "1970 - 2019", caption = "Source: Statistics Canada")
p + theme(legend.title = element_blank())*

作者图片
在 20 世纪 80 年代中期之前,货币供应量的变化和利率的变化之间的关系是一致的。当然,这种关系是不完美的,这意味着其他变量也会影响利率。
至少从 2000 年开始,货币供应量的变化似乎对利率没有什么影响。事实上,尽管这一时期货币供应量波动很大,但利率仍保持负斜率。
GDP 增长率和利率之间的关系如何?

作者图片
在整个研究期间,这种关系似乎比利率和货币供应量之间的关系更加一致。一般来说,利率下降会导致 GDP 增长率上升,反之亦然。
上述形象化的观点对货币供应量的变化是否先于利率的变化产生了相当大的怀疑(事实上,相反的情况可能是正确的)。然而,利率的变化确实出现在经济增长率变化之前。
此外,我们已经为变量之间的关系建立了一个理论解释。
最后,我们必须确定我们的变量是相关的。更具体地说,我们必须确认这种关系不是第三个混淆变量的结果。
这是最难满足的条件。
我发现所有变量在一阶差分后都是稳定的。
*library(VARS)
library(tseries)
library(lmtest)# Use VARselect to find the optimal lag length for which to test for stationarity.VARselect(data$stir, lag.max = 20, type = "const")
VARselect(data$gdpg, lag.max = 20, type = "const")
VARselect(data$narrowmg, lag.max = 20, type = "const")
VARselect(data$inf, lag.max = 20, type = "const")# Run Adjusted Dickey-Fuller to test for stationarity. We find that # some of our variables are non-stationary. However, our variables
# are stationary after first-differencing.adf.test(data$stir, alternative = "stationary", k = 2)
adf.test(data$gdpg, k = 14, alternative = "stationary")
adf.test(data$narrowmg, k = 18, alternative = "stationary")
adf.test(data$inf, k = 10, alternative = "stationary")
*# Find optimal lag length again.*
VARselect(diff(data$stir), lag.max = 20, type = "const")
VARselect(diff(data$gdpg), lag.max = 20, type = "const")
VARselect(diff(data$narrowmg), lag.max = 20, type = "const")
VARselect(diff(data$inf), lag.max = 20, type = "const")
VARselect(diff(data$xrusd), lag.max = 20, type = "const")
*# Conduct ADF test again.*
adf.test(diff(data$stir), k = 1, alternative = "stationary")
adf.test(diff(data$gdpg), k = 13, alternative = "stationary")
adf.test(diff(data$narrowmg), k = 16, alternative = "stationary")
adf.test(diff(data$inf), k = 9, alternative = "stationary")*
接下来,我们创建一个保存静态变量的新数据框。然后,我们将该数据帧传递给 VARselect 函数,以获得 VAR 的最佳滞后长度。
最后,我们将新的数据框架和最佳滞后长度传递到 VAR 函数中。
*newdata <- data.frame(diff(data$gdpg), diff(data$narrowmg), diff(data$inf), diff(data$stir), diff(data$xrusd))
VARselect(newdata, lag.max = 20, type = "const") # Find optimal lag
varmodel <- VAR(newdata, p = 4, type = "const") # optimal lag is 4*
结果
回想一下我们的假设。
首先,我们想测试货币供应量的增加是否会降低利率。
查看以利率( stir )为因变量的系数:

Narrowmg 是 M1 的增长率。L1…L4 是滞后长度。只有滞后 2 和滞后 4 与利率负相关;此外,滞后 4 在统计上并不显著。
然而,我们想知道滞后长度是否共同具有统计显著性。
我们可以用格兰杰因果检验来检验联合统计的显著性。零假设是变量没有联合显著性;另一种假设是,他们是。
*causality(varmodel, cause = "diff.data.narrowmg.")$Granger*

根据格兰杰因果关系检验,我们不能拒绝零假设,即货币供应量的变化对利率(或其他变量)的变化没有预测能力。
以下是以 GDP 增长率为因变量的线性模型的结果:

作者图片
滞后 2 到 4 为利率变量(拨* ) 有负系数。因此,利率的提高会降低经济增长。*
检查利率滞后是否共同显著:
*causality(varmodel, cause = "diff.data.stir.")$Granger*

作者图片
我们可以拒绝零假设,即利率的变化不会导致经济增长或其他变量的变化。
有趣的是,因为利率的变化也预示着货币供应量的变化,我们不能否认利率的变化先于货币供应量的变化。
然而,我们应该小心假设检验;p 值并不完美。
为什么我不在乎你的 p 值小于 0.05
towardsdatascience.com](/youre-probably-misusing-the-p-value-fef44d665955)
然而,由于早期的数据可视化表明货币供应的变化对利率的影响为零,至少在 2000 年后,我们可以假设格兰杰因果检验是准确的。
结论
诚然,上述项目存在一些问题。一方面,M1 可能不是货币供应量的准确指标;同样,VAR 可能不是检验两个均衡变量(利率和货币供应量)之间关系的最佳模型。
那很好。本文的目的是向您展示它对您的数据科学发展的好处。
希望你也学到了一些关于货币和利率的有趣的东西!*
加快大型交叉连接火花数据帧的计算速度
减少输入数据帧上的分区数量,以加快交叉连接数据帧的计算速度。

Apache Spark 将数据分割成分区,并在这些分区上并行执行任务,使您的计算并行运行。分区的数量对 Spark 计算的运行时间有直接影响。
Spark 计算通常涉及交叉连接两个 Spark 数据帧,即创建一个新的数据帧,包含两个输入数据帧中每一行的组合。当交叉连接大型数据帧时,Spark 会成倍增加输入数据帧的分区数量。这可能导致交叉连接数据帧中的分区数量显著增加。因此,由于管理分区上许多小任务的额外开销,在该数据帧上运行计算会非常慢。
让我们考虑两个场景来理解交叉连接数据帧时分区是如何工作的:
场景 1:较小的数据帧
如果输入数据帧的大小较小,那么交叉连接数据帧的分区数将等于输入数据帧的分区数。
scala> val xDF = (1 to 1000).toList.toDF("x")
scala> xDF.rdd.partitions.size
res11: Int = 2scala> val yDF = (1 to 1000).toList.toDF("y")
scala> yDF.rdd.partitions.size
res12: Int = 2scala> val crossJoinDF = xDF.crossJoin(yDF)
scala> crossJoinDF.rdd.partitions.size
res13: Int = 2
在这种情况下,
xDF 的分区= = yDF 的分区= = crossJoinDF 的分区
如果输入数据帧的分区,即 xDF 或 yDF 不相等,那么交叉连接的数据帧的分区将等于输入数据帧之一。
场景 2:更大的数据框架
如果我们增加输入数据帧的数据大小,交叉连接数据帧上的分区行为会发生变化。
在以下示例中,我将输入数据帧中的行数从 1000 增加到 1,000,000
scala> val xDF = (1 to 1000000).toList.toDF("x")
scala> xDF.rdd.partitions.size
res15: Int = 2scala> val yDF = (1 to 1000000).toList.toDF("y")
scala> yDF.rdd.partitions.size
res16: Int = 2scala> val crossJoinDF = xDF.crossJoin(yDF)
scala> crossJoinDF.rdd.partitions.size
res17: Int = 4
在这种情况下,交叉连接的数据帧的分区大小等于输入数据帧分区
的乘积 crossJoinDF =(xDF 的分区)yDF 的分区)。
如果您的输入数据帧有更多的列或更大的数据类型,您也能够在只有几千行的数据帧上复制这种行为。
一个数据帧的确切分区数量因硬件而异,但交叉连接大型数据帧时分区的交叉乘法在所有类型的硬件上都是一致的。
那么,如果 Spark 将大输入数据帧的分区相乘来为交叉连接的数据帧创建分区,会有什么问题呢?
如果您的输入数据帧包含几百个分区(大约 100 个),这是处理大数据时的典型情况,那么交叉连接的数据帧将包含大约 10,000 个分区。
数据帧分区的数量对计算的运行时间有影响:
- 如果分区太少,您的计算将无法利用集群中所有可用的并行性。
- 如果你有太多的分区,在管理许多小任务时会有过多的开销,使得你的计算运行起来非常慢。
交叉连接具有不到 100 个分区的大型数据帧属于后一种情况,这会导致数据帧具有 10,000 个数量级的太多分区。这使得对交叉连接数据帧的任何操作都非常慢。在具有大量分区的交叉连接数据帧上运行操作时,您可能会遇到以下异常:
org.apache.spark.SparkException Job aborted due to stage failure:
Total size of serialized results of 147936 tasks (1024.0 MB) is bigger than
spark.driver.maxResultSize (1024.0 MB)
这是因为 Spark 将每个任务的状态数据发送回驱动程序。由于有许多分区(或任务),这些数据经常会超过默认的 1024 MB 的限制。
增加 Spark 配置Spark . driver . max resultsize的值将使您的计算运行时不会抛出上述异常,但不会使它更快。大量分区的固有问题仍然存在。
你如何使计算更快?
要加快计算速度,请在交叉连接之前减少输入数据帧的分区数量,以便交叉连接后的数据帧不会有太多分区。
作为一个真实世界的例子,我需要交叉连接两个数据帧 df1 和 df2,以计算两个数据帧的行的每个组合之间的余弦相似性。两个数据帧都由文本和长度为 500 的双精度数组组成,表示文本嵌入。数据帧 df1 由大约 60,000 行组成,数据帧 df2 由 130,000 行组成。使用 40 名 G.1X 型工人在 AWS 胶水上对交叉连接的数据帧进行连续计数需要大约 6 个小时。在交叉连接之前将 df1 和 df2 重新划分为更少的分区,将交叉连接数据帧的计算时间减少到 40 分钟!
为了便于说明,我将从 df1 和 df2 数据帧中抽取少量样本。将包含 17,000 行和 200 个分区的 df1 与包含 15,000 行和 200 个分区的 df2 交叉连接,可创建包含 40,000 个分区的交叉连接数据帧。对交叉连接的数据帧进行计数需要 285,163,427,988 ns,即 4.75 分钟。
以下代码是在 AWS Glue 上执行的,有 40 名 G1 类型的工人。x 使用 Spark 2.4
scala> df1.count()
res73: Long = 17000scala> df1.show(4)
+---------------------------+--------------------+
| text| text_embedding|
+---------------------------+--------------------+
|eiffel tower location |[0.4, 0.02, 0.1, ...|
|pounds kilogram conversion |[0.01, 0.2, 0.1, ...|
|capital of spain |[0.05, 0.2, 0.2, ...|
|mount everest height |[0.07, 0.1, 0.1, ...|
+---------------------------+--------------------+scala> df1.rdd.partitions.size
res74: Int = 200scala> df2.count()
res75: Long = 15000scala> df2.rdd.partitions.size
res76: Int = 200scala> df2.show(4)
+------------------------------+--------------------+
| text| text_embedding|
+------------------------------+--------------------+
|where is eiffel tower located |[0.3, 0.01, 0.1, ...|
|how many pounds in a kilogram |[0.02, 0.2, 0.1, ...|
|what is the capital of spain |[0.03, 0.2, 0.2, ...|
|how tall is mount everest |[0.06, 0.1, 0.1, ...|
+------------------------------+--------------------+scala> val finalDF = df1.crossJoin(df2)scala> finalDF.rdd.partitions.size
res77: Int = 40000scala> time {finalDF.count()}
Elapsed time: 285163427988ns
res78: Long = 255000000
如果我们在执行交叉连接之前将 df1 和 df2 上的分区数量减少到 40,那么在交叉连接的数据帧上运行计数的时间将减少到 47,178,149,994 ns,即 47 秒!我们选择了 40 个分区来利用 40 个工作集群中所有可用的并行性。
scala> val df1 = df1.repartition(40)
scala> df1.rdd.partitions.size
res80: Int = 40scala> val df2 = df2.repartition(40)
scala> df2.rdd.partitions.size
res81: Int = 40scala> val finalDF = df1.crossJoin(df2)
scala> finalDF.rdd.partitions.size
res82: Int = 1600scala> time {finalDF.count()}
Elapsed time: 47178149994ns
res86: Long = 255000000
在交叉连接数据帧之前减少分区数量,可以将计算交叉连接数据帧的时间减少 6 倍!
外卖
下次在执行交叉连接后发现 Spark 计算变慢时,一定要检查交叉连接数据帧上的分区数量。如果分区太多,请减少输入数据帧上的分区数量,以加快对结果交叉连接数据帧的操作。
加速您的探索性数据分析(EDA)
Python 的 exploretransform 包简介

由 Unsplash 上的 Element5 数码拍摄
总结:
- 数据科学家花 60%的时间清理和组织数据。收集数据集排在第二位,占他们时间的 19%,这意味着数据科学家花费大约 80%的时间来准备和管理用于分析的数据
- 76%的数据科学家认为数据准备是他们工作中最不愉快的部分
在本文中,我将展示 Python 的 exploretransform 包。它可以节省数据探索和转换的时间,并有望使您的数据准备更愉快!
概述:
我最初开发 exploretransform 是为了在我自己的项目中使用,但我认为它可能对其他人有用。我的意图是创建一组简单的函数和类,以常见的 Python 数据格式返回结果。这将使从业者能够容易地利用输出或扩展原始功能,作为其工作流程的一部分。
如何使用 exploretransform:
安装和导入
!pip install exploretransformimport exploretransform as et
让我们从加载波士顿校正数据集开始。
df, X, y = et.loadboston()
在这个阶段,我喜欢检查数据类型是否与数据字典和前五个观察值一致。此外,lvl 的数量可以指示潜在的分类特征或具有高基数的特征。这里还可以检测到任何需要重新格式化的日期或其他数据。我们可以在这里使用 peek()。
et.peek(X)

分析完数据类型后,我们可以使用 explore()来识别缺失值、零值和无穷大值。
et.explore(X)

前面,我们看到城镇可能是一个具有高基数的分类特征。我们可以使用 freq()来分析分类或顺序特征,提供每个级别的计数、百分比和累积百分比
t = et.freq(X['town'])t

为了可视化 freq()的结果,我们可以使用 plotfreq()。它生成一个条形图,以降序显示各个级别。
et.plotfreq(t)

为了与您通常检查的直方图配对,skewstats()返回每个数字特征的偏度统计数据和大小。当您有太多的特征而无法轻松绘制时,此功能会变得更加有用。
et.skewstats(N)

为了确定预测值和目标值之间的关联,ascores()计算 pearson、kendall、pearson、spearman、mic 和 dcor 统计值。这些分数的多样性是有用的,因为某些分数测量线性关联,而其他分数将检测非线性关系。
et.ascores(N,y)

一旦我们达到一定数量的特征,相关矩阵就会变得难以处理。虽然波士顿数据集远低于这个阈值,但可以想象,在处理高维数据时,表可能比矩阵更有用。Corrtable()返回所有成对相关的表,并使用中的行和列的平均相关来决定潜在的删除/筛选候选项。您可以使用任何您通常使用 pandas corr 函数的方法:
- 姓氏
- 肯德尔
- 枪兵
- 请求即付的
N = X.select_dtypes('number').copy()c = et.corrtable(N, cut = 0.5, full= True, methodx = 'pearson')c


根据 corrtable()的输出,calcdrop()确定应该删除哪些要素。
et.calcdrop(c)['age', 'indus', 'nox', 'dis', 'lstat', 'tax']
ColumnSelect()是一个自定义转换器,它为管道选择列
categorical_columns = ['rad', 'town']cs = et.ColumnSelect(categorical_columns).fit_transform(X)cs

CategoricalOtherLevel()是一个自定义转换器,它根据阈值在分类/序号数据中创建“其他”级别。这在具有高基数预测值的情况下以及未来数据中可能出现新类别的情况下非常有用。
co = et.CategoricalOtherLevel(colname = 'town', threshold = 0.015).fit_transform(cs)co.iloc[0:15, :]

CorrelationFilter()是一个自定义转换器,它根据成对相关性过滤数字要素。它使用 corrtable()和 calcdrop()来执行 drop 评估和计算。有关它如何工作的更多信息,请参见:您是否放弃了太多相关功能?
cf = et.CorrelationFilter(cut = 0.5).fit_transform(N)cf

结论:
在本文中,我展示了 exploretransform 包如何帮助您加速探索性数据分析。我很乐意听到任何改进的反馈或建议。请随时通过 LinkedIn 或 GitHub 联系我。
参考文献:
同上
简单点:神经网络
识别神经网络的基本组件
摘要
这篇文章将提供神经网络的概述。它将帮助有或没有数学背景的人在一个最有前途的研究领域应用他们的具体知识。
动机
我最初是作为一名政治科学家开始的,我很快对定性方法论产生了兴趣。所以本科毕业后,我决定学统计学。在攻读统计学硕士期间,我对数学知识产生了浓厚的兴趣。
大约在同一时间,我开始在一家大型德国研究所的软件管理领域工作。这是我第一次接触机器学习。在午休期间,我听到同事们谈论损失函数,比如均方差,作为一名统计学家,我更清楚这是一种衡量变异的方法。反复讨论引发了逼近方法,这显然是用于神经网络中函数的机器学习,但我知道它是用于逼近复杂分布的。
渐渐地,我鼓起了勇气,令我惊讶的是,我能够在讨论中提出一些当时软件开发人员没有考虑到的观点。因此,我决定花些时间去了解神经网络。我找到了许多带有具体数学推导的文章和书籍,这有助于我更好地进行自下而上的理解。然而,我无法在很长一段时间内捕捉到总体概念。
出于这个原因,我将提供一个主要是叙述性的神经网络概述,以便对整个概念有一个自上而下的视角,作为个体适应的有效起点。
术语

图 1(作者的图片)
我需要克服的一个主要问题是理解术语机器学习、深度学习、和神经网络(图 1)之间的实际差异。这些术语在文献中经常被不一致地使用,就像我在上一节中使用它们一样。然而,我认为有效的学习必须对特定的术语有一致的理解。我不会说我的定义是详尽无遗的,并且把所有可用的文献都结合起来了,但是如果有人问我这些术语的区别是什么,我能够给出一致的答案。

图 2(作者的图片)
我喜欢把定义想象成一个俄罗斯娃娃(图 2)。最大的娃娃代表了术语机器学习【1】,它概括了算法随着时间的推移而学习的能力。术语深度学习【2】由中间的娃娃代表。深度学习代表计算广泛的机器学习程序。而最小的娃娃可以被认为是术语神经网络【3】。神经网络是深度学习模型的架构。
神经网络的组件
通常,包括神经网络在内的机器学习算法有三个共同点:映射输入和输出的函数、测量信息损失的函数和最小化信息损失的函数[4]。第一种也称为链函数,第二种称为损失函数,最后一种称为优化算法。
现在我们知道神经网络是深度学习领域的架构,深度学习是机器学习的子领域,我们需要确定最初呈现的组件在神经网络的情况下是什么样子的。
- 连锁功能
类似于统计学,其中模型选择取决于用例,在机器学习中也存在大量不同的神经网络架构。在本教程中,我将重点介绍一种极其简化的全连接架构。

图 3(作者的图片)
图 3 的快速详细描述:神经网络通常由三种类型的层组成[5]。输入层在神经网络中处理矩阵、向量,甚至标量和输入数据。输出层返回具有预定义形状的输出值。隐藏层将两者连接起来。它们被称为隐藏层,因为通常它们没有预定义的输出。然而,一旦我们从数学上理解了每一层,我们就理解了每一层中的输出维度。圆点表示隐藏层可能有不确定的形状。通常,隐藏层的数量被称为网络的深度,而一层中的圈数代表网络的宽度。如果有人说深度神经网络,一是指有很多隐含层的神经网络。蓝色箭头称为权重,它们是网络的参数。
输入值和输出值通过隐藏层连接。每个隐藏层可以表示为一个函数。据此,链函数是来自隐藏层的所有函数的连接。
还有许多不同的功能可用。它们的共同点是都是矩阵或向量乘法。所以,这些隐藏层的每一层都可以用线性代数的基础知识来理解。
- 损失函数
假设现在我们在神经网络中走了一遍。我们将得到一个具有预定义形状的输出。但是这个输出会有多好呢?这个问题的答案正是损失函数的目的[6]。

图 4(作者的图片)
神经网络至少在所谓的监督学习过程中试图最小化它们的输出(图 4,第一列)和基本事实(图 4,第二列)之间的距离。
在我们能够考虑最小化目标之前,我们需要一个策略来测量偏差。还有各种不同的方法。一个简单的方法是均方误差,它将每一行的真实值和网络输出的平方差相加,然后将这个结果除以行数。在图 4 的例子中,平方差的和是 8。由于我们有 2 行,均方差将导致 4。
- 优化算法
我们现在知道,我们的神经网络只不过是矩阵或向量乘法的组合,而且通常是相当复杂的聚合。此外,我们知道我们需要损失函数来估计输出值和期望值之间的距离。现在我们正在寻找最小化估计距离的程序[7]。在我看来,这是神经网络中最复杂的一点,因为所用的优化算法通常非常复杂。冒着重复我自己的风险:有大量不同的优化算法可用。仅举两个常用的算法:随机梯度下降和 Adam 优化器。
所有这些优化算法都寻求调整权重,使得损失函数最小化。几乎所有的优化算法都是估计链函数中每个权重的梯度。在这一步中,我们反向遍历神经网络,如图 5 所示。

图 5(作者本人法师)
与图 3 中的线相比,图 5 中的反向线意味着我们估计了链函数的每个参数的梯度。每个优化算法然后提供关于如何使用该梯度信息来更新权重的指令。
结论
就是这样!这些是对神经网络基本组件的叙述性解释。重复通过神经网络首先向前然后向后并随后更新权重的整个过程,直到损失函数最小化。
请让我知道你如何喜欢将复杂的数学主题分解成简单的叙述性解释的想法。如果你有任何我应该在文章中使用的其他流行词汇,请告诉我,让它变得简单文章。
参考文献
[1] E. Alpaydin,《机器学习导论》(2014),第 3 版。剑桥,马萨诸塞州,伦敦,英国:麻省理工学院出版社,ISBN: 9780262325745
[2] Y. LeCun,Y. Bengio,和 G. Hinton,深度学习(2015),自然。第 521 卷,第 7553 号,第 436-444 页
[3] J. Schmidhuber,神经网络中的深度学习:概述(2014),arXiv: 1404.7828
[4] I .古德费勒、y .本吉奥和 a .库维尔,《深度学习》(2016),麻省理工学院出版社,中国。5.10
[5] I .古德费勒、y .本吉奥和 a .库维尔,《深度学习》(2016),麻省理工学院出版社,第 164 页及其后
[6] I .古德费勒、y .本吉奥和 a .库维尔,《深度学习》(2016),麻省理工学院出版社,第 80 页及其后
[7] I .古德费勒、y .本吉奥和 a .库维尔,《深度学习》(2016 年),麻省理工学院出版社,中国。8
用 20 行代码让 kNN 比 Scikit-learn 快 300 倍!
使用脸书·费斯库实现快速 kNN

我们可以通过 faiss 库(来源)更快地搜索最近邻居
简介
k 近邻(kNN)是一种简单的用于分类和回归的 ML 算法。Scikit-learn 以一个非常简单的 API 为两个版本的特点,使其在机器学习课程中很受欢迎。它有一个问题——太慢了!但是不要担心,我们可以通过脸书·费斯库让它适用于更大的数据集。
kNN 算法必须为被分类的样本在训练集中找到最近的邻居。随着数据维度(要素数量)的增加,查找最近邻所需的时间会迅速增加。为了加速预测,在训练阶段(.fit()方法),kNN 分类器创建数据结构,以更有组织的方式保持训练数据集,这将有助于最近邻搜索。
Scikit-learn vs faiss
在 Scikit-learn 中,默认的“自动”模式会根据训练数据的大小和结构自动选择算法。它要么是强力搜索(针对非常小的数据集),要么是最近邻查找的流行数据结构之一,k-d 树或球树。它们很简单,经常在计算几何课程中讲授,但是在 Scikit-learn 中实现它们的效率是值得怀疑的。例如,您可能已经在 kNN 教程中看到只选择 MNIST 数据集的一小部分,大约 10k 这是因为对于整个数据集(60k 图像)来说,这太慢了。今天,这甚至还没有接近“大数据”!
幸运的是,脸书人工智能研究所(FAIR)提出了最近邻搜索算法的优秀实现,可以在 faiss 库中找到。faiss 提供 CPU 和 GPU 支持,许多不同的指标,利用多个核心,GPU 和机器等等。有了它,我们可以实现比 Scikit-learn 的不是快几倍,而是快几个数量级的 k 近邻分类器!
用 faiss 实现 kNN 分类器
如果你对下面的 Github 要点有困难,代码也可以在我的 Github ( 链接)获得。
faiss 的一个很大的特点是它既有安装和构建说明(安装文档)又有一个优秀的带示例的文档(gettingstarted docs)。安装完成后,我们可以编写实际的分类器。代码非常简单,因为我们只是模仿了 Scikit-learn API。
这里有一些有趣的元素:
- 属性保存 faiss 创建的数据结构,以加速最近邻搜索
- 我们放入索引的数据是 Numpy float32 类型
- 我们这里用的
IndexFlatL2,是最简单的欧氏距离(L2 范数)的精确最近邻搜索,非常类似于默认的 Scikit-learnKNeighborsClassifier;您还可以使用其他指标(指标文档)和索引类型(索引文档),例如用于近似最近邻搜索 .search()方法返回到 k 个最近邻居的距离及其索引;我们只关心这里的索引,但是你可以用附加信息实现距离加权最近邻.search()返回的索引是 2D 矩阵,其中第 n 行包含 k 个最近邻的索引;使用self.y[indices],我们将这些索引转化为最近邻的类别,因此我们知道每个样本的投票数np.argmax(np.bincount(x))从 x 数组中返回最受欢迎的数字,即预测类;我们对每一行都这样做,也就是说,对我们必须分类的每个样本都这样做
时间对比
我选择了 Scikit-learn 中的一些流行数据集进行比较。比较训练时间和预测时间。为了便于阅读,我明确地写了基于 faiss 的分类器比 Scikit-learn 的快多少倍。
所有这些时间都是用time.process_time()函数测量的,该函数测量进程时间而不是挂钟时间,以获得更准确的结果。结果是 5 次运行的平均值。

火车时间(图片由作者提供)

预测时间(图片由作者提供)
训练平均快了差不多 300 倍,而预测平均快了 7.5 倍左右。另请注意,对于 MNIST 数据集,其大小与现代数据集相当,我们获得了 17 倍的加速,这是巨大的。10 分钟后我就准备放弃用 Scikit-learn 了,差不多花了 15 分钟 CPU 时间(挂钟更长)!
摘要
有了 20 行代码,我们用 faiss 库获得了 kNN 分类器的巨大速度提升。如果你需要,你可以用 GPU、多个 GPU、近似最近邻搜索等等做得更好,这在 faiss 文档中有很好的解释。
让 KubeFlow 成为您自己的数据科学工作空间
1.带上你自己的 Jupyter 图片

好的工作来自好的工作空间。
这种实践可能也适用于数据科学。
必需品;要素
- Jupyter;作为你的笔记本
Jupyter notebook 是数据科学写作事实上的标准工具。您可以创建一个 Python 程序,以图表的形式查看结果,并添加关于结果的注释。 - 数据管理;作为你的实验资源
数据科学离不开数据。数据应该存储在可扩展的数据存储中,比如 AWS S3、Azure BlobStore、Google 云存储、MINIO 等等。 - 工作室环境;作为你的书桌
你可以从一台笔记本切换到另一台笔记本。根据您的任务,您可以轻松选择您的工作空间。亚马逊 SageMaker 工作室,Azure 机器学习,谷歌数据实验室。KubeFlow 是一个新兴的 OSS 工具。
了解容器图像的重要性
在工作室中,多个 Jupyter 笔记本作为容器分别运行。容器是一种将计算机工作空间分成具有不同软件栈和独立计算机资源的多个工作空间的技术。在一个容器中,你可以运行 Jupyter notebook,用apt或yum命令安装一些需要的软件。在另一个容器中,您可以安装另一个版本的工具。它们没有被混淆或污染。你可以随意切换这些容器。
容器从图像运行。图像就像软件安装的压缩文件。当您从现有映像运行容器时,您需要的所有软件都已经安装。集装箱可以在几秒钟内启动。
所以集装箱图像就像你的瑞士军刀。当您需要软件时,您可以从您的容器映像运行容器。当你不再需要它的时候,你就把它扔掉。非常方便。
有用图像的例子
- 默认 Jupyter 图片
Jupyter 提供他们的容器图片。pip有资格安装许多软件包到 Jupyter 服务器。但是有一些限制;一个是唯一的用户账号jovyan没有访问 root 权限。另一个是 Jupyter 中的 python 环境是普通的,所以不需要安装额外的包。 - 定制启用
**sudo**无密码
与默认图像不同,我们可以使用这种图像执行sudo无密码。例如,mount命令可以运行为 @shakedko 提到的。在另一种情况下,您可以运行apt或yum命令按需安装新的库。 - 预安装一些
**pip**包和库 与默认映像不同,定制的容器允许您开始工作,而无需任何pip命令来安装所需的包。您可以将pip包预安装到映像中。例如,TensorFlow或Pandas可以预装安装。 - 更多随心定制
如果深度定制你的容器镜像,可以改变目录结构、环境变量、设备驱动等等。
自定义您的容器图像
如何准备自己的容器图像?别担心。很简单。
你所需要的只是一台安装了 docker 的笔记本电脑。
首先,您创建 Dockerfile 。Dockerfile 是一个用于创建容器图像的脚本。不需要从头开始。Dockerfile 允许导入现有图像作为开始行。您只需添加命令行进行区分。
本文档涵盖了构建高效映像的推荐最佳实践和方法。Docker 构建图像…
docs.docker.com](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
接下来,您用 docker 文件构建一个容器映像。你只要运行这个命令docker build。你将在你的 docker 里面有你的容器图像。并且你命名相同的图像名和标签像some-registry.io/hiroyukiosaki/jupyter-original:v1.0。
最后,您将容器映像上传到注册表。这种操作叫做“T4 推”。 Dockerhub 是公众中最著名的容器注册表。如果你需要自己的容器注册表,或者你可以试试 docker image registry 或者 harbor 。推送映像后,您可以将映像下载到任何容器环境中。为了在稍后描述的 KubeFlow 上使用您的图像,您必须将图像注册到注册表。
使用您自己的 Jupyter 图像到 KubeFlow
现在是时候准备你的工作室环境了。让我们使用您的容器图像来 KubeFlow。这一步允许您在 KubeFlow 上轻松运行容器。当您在 KubeFlow 上创建新的笔记本服务器时,会出现下面的对话框,您可以从中选择想要运行的容器映像。

通过勾选Custom Image,您可以在下面的文本框中输入您的图像名称和标签。

我之前的帖子展示了如何在只安装了 docker 的机器上准备 KubeFlow。
注意:如果 Jupyter 映像支持 KubeFlow 路径的环境值,则 KubeFlow 可以与您的 Jupyter 映像无缝集成。请参考 KubeFlow 官方文件。
更改默认图像列表
如果您是 KubeFlow 环境的管理员,您可以将一些图像添加到默认图像列表,如下所示。
- 编辑命名空间“kubeflow”中的配置映射“”
kubectl edit cm jupyter-web-app-config -n kubeflow
这样修改
data:
spawner_ui_config.yaml: |
# (ellipsis)
spawnerFormDefaults:
image:
# (ellipsis)
**options**:
- gcr.io/kubeflow-images-public/tensorflow-1.15.2-notebook-cpu:1.0.0
- gcr.io/kubeflow-images-public/tensorflow-1.15.2-notebook-gpu:1.0.0
- gcr.io/kubeflow-images-public/tensorflow-2.1.0-notebook-cpu:1.0.0
- gcr.io/kubeflow-images-public/tensorflow-2.1.0-notebook-gpu:1.0.0
# **you can add your image tag HERE like
-** some-registry.io/hiroyukiosaki/jupyter-original:v1.0
2.重新启动一个标有“app . kubernetes . io/name = jupyter-we B- app”的 pod,它会重新加载 1。配置。
kubectl delete po -l app.kubernetes.io/name=jupyter-web-app -n kubeflow
运行该命令后,请检查是否创建了一个新的 pod,并且它的状态正在变得Running。
kubectl get po -l app.kubernetes.io/name=jupyter-web-app -n kubeflow -w
NAME READY STATUS RESTARTS AGE
jupyter-web-app-deployment-679d5f5dc4-zzn7b 1/1 Running 0 3m
重新访问创建笔记本服务器的对话框,您将看到默认图像列表包括您刚刚添加的图像名称和标记。

您的图像已添加
摘要
对于数据科学家来说,为了加快他们的工作,准备他们自己的 Jupyter 环境和容器映像以便按需创建是很重要的。
使用 docker,您可以定制和构建自己的图像。注册表使您能够管理这些图像。而如果用 KubeFlow 做工作室,可以按需启动自己的镜像。为了方便使用,您可以在 KubeFlow 上编辑默认图像列表。
用这 5 个包让学习变得有趣
初学者友好的方式添加音乐,扫雷,和更多到您的项目。

图片:安东尼·福明/ Unsplash
有时候,学习编程很容易受挫。也许你已经在同一个概念上工作了一两个小时。也许你的进步很慢。也许这一切都发生在一个全球疫情的周五下午 6 点。我去过那里,我想我并不孤单。
幸运的是,对于 R 程序员来说,有一些软件包可以帮助他们将快乐带回到学习过程中。更重要的是,它们很容易理解,可以为娱乐项目增添趣味。
下面,我整理了五个我最喜欢的“只是为了好玩”的包。每个示例对初学者来说都非常友好,不过要确保在运行示例代码之前安装每个包。您可以通过为每个示例运行函数install.packages("packagenamehere")来做到这一点,将包名更改为下面列出的名称之一。
1.beepr
“ beepr 包只包含一个函数:beep。调用时会发出声音,并加载一些有趣的通知。如果你曾经想在脚本中听到威廉的尖叫或《塞尔达传说》中的“获得物品”的声音,这是给你的包。如果你给它一个有效的 URL,它还会播放来自互联网的. wav 文件的声音。只要用一个数字或有效的网址作为参数调用beep,它就会发出相应的声音。
library(beepr)
# Play Zelda treasure notification
beep(5)
# Play Wilhelm scream
beep(9)
与我下面提到的一些其他包不同,beepr 实际上在严肃的工作中非常有用。在运行需要很长时间才能执行的代码时,我经常在等待代码完成的同时做其他事情。在我的脚本末尾调用 beep 表示我的长进程已经完成。在一个长时间的分析或模拟结束时听到一些 8 位的大喇叭是非常令人满意的。
2.乐趣
名副其实的' fun '包是各种功能和游戏的集合。如果你需要另一个拖延的工具,这个包里就有。值得注意的包括一个整洁版本的扫雷,在 R 窗口运行,以及其他游戏,如滑动拼图,和' 5 在一排'。运行这些游戏很容易,只需要下面的代码。加载软件包后,条件语句根据您的操作系统打开正确的交互式图形设备。然后你可以通过调用它的函数来启动这个包中的任何游戏(比如滑动拼图)。
library(fun)
# Open the right interactive graphics device
if (.Platform$OS.type == "windows") {
x11()
} else {
x11(type = "Xlib")
}
# Start game of choice (sliding puzzle)
fun::sliding_puzzle()
这个包还包含一些其他杂项功能和演示。有没有想过在 R 里面画一只乌龟?老年痴呆症测试?关闭你的操作系统?这些都是你可以用‘乐趣’做的事情。虽然阻止你的操作系统可能不会带来笑声,但是这个包中的许多其他有趣的游戏和娱乐是很有趣的。
3.命运
福运是另一个功能单一的包;fortune。当在没有争论的情况下被调用时,它会从 R-help 论坛和其他 R 相关的站点中随机地抛出幽默和智慧的金块。要获得更具体的运气,可以在函数调用中添加一个字符串参数(例如fortune("divide"))。这经常会产生一些有趣的输出,下面是我最喜欢的一个:
科琳娜·施密特:我怎样才能把 0.285 除以 2 呢?我需要一个函数。
结果:0.285 / 2 = 0.1425
Gabor Csardi:嗯,我觉得
0.285 的一半<-function(){
0.1425
}
就可以了。Corinna Schmitt 和 Gabor Csardi R-help(2007 年 4 月)
作为一个额外的学习激励,随着你对 R 和它的社区了解的越来越多,许多引用变得越来越有趣。但是,无论你的技能水平如何,幸运之神选择幽默的旁白会让你从原本打算做的事情中分心。
4.考赛
一个简洁的软件包,它在控制台的文本输出中添加了字符,'[cow say【T16]'让您可以打印由 ASCII 字符绘制的动物所说的消息。想减轻警告信息的打击吗?用下面的代码让一只猫说出来。](https://www.rdocumentation.org/packages/cowsay/versions/0.8.0)
say(what = "Cannot index object of type 'cat food'.", by = "cat", type = "warning")

非常可爱的警告信息。
say 函数还可以处理未定义为警告的消息,默认情况下打印普通文本。它还集成了“财富”包;当运行say(what = "fortune")时,一个随机的命运将由一个动物来说。因为大家都想看一只鸭子哀叹 R 用户的愚蠢。
5.崇拜
最后,有时候接受一句赞美真好。“赞”套餐通过生成随机赞来促进这一点,让您在每次通话中都能获得新的鼓励。在使用${}语法指定要动态生成的词性时调用praise,会产生如下语句:
praise("${Exclamation}! Kind reader, you're ${adjective}!")

某种输出。
在我的例子中,我将感叹号大写,而出于语法目的,将形容词小写。动态生成的短语可以完全大写以获得额外的热情(例如${EXCLAMATION})。虽然我看不到这在许多严肃的生产级脚本中获得牵引力,但有时表扬自己的努力也是不错的。今天学了一个新的分析?干得好,冠军。
在我们当前的经济环境下,人们学习编程主要是为了职业发展。当前关注的是学习获得工作的技巧,而不是建设带来快乐的项目。我觉得这也不是完全没有道理。毕竟,大多数 R 程序员并不是为了让 ASCII 动物与用户对话而获得报酬的。他们靠分析数据获得报酬。
也就是说,我喜欢这些包,因为它们再次证明了我当初为什么被编程吸引。这很有趣,让我做出有趣的东西。当我第一次开始学习编程时,我并不是在寻找一份高强度的工作。我很高兴能创造出有趣的小规模项目来应用我的新技能。即使我现在在职业生涯中喜欢写代码,偶尔找回那种感觉也很好。
所以,本着好玩的精神:say(praise("Thanks for reading, and have fun ${creating} your own ${adjective} R code!"))
想阅读我所有关于编程、数据科学等方面的文章吗?在这个链接注册一个媒体会员,就可以完全访问我所有的作品和媒体上的所有其他故事。这也直接帮助了我,因为我从你的会员费中得到一小部分,而不需要你额外付费。
只要我通过在这里订阅,你就可以将我所有的新文章直接发送到你的收件箱。感谢阅读!
造还是买 AI?
从零开始构建人工智能或利用现有服务的决定对 2020 年的许多企业来说至关重要。让我们来看看这两种途径的注意事项。

人工智能、机器学习和数据科学已经成为大大小小众多企业的必备话题。随着模式识别、计算机视觉和自然语言处理的进步,可以优化的众多流程将推动下一代业务的发展。由于这个原因,许多组织都吵着要把他们的人工智能战略整合在一起。而数据科学家和软件工程师经常通过项目所需的任务来计算项目的难度;企业领导人必须权衡他们选择的许多人事和财务权衡。财务和会计中一个常用的流程是制造或购买决策。这是一个考虑内部开发或外包的所有当前和未来成本的过程。本文将解释这些决定的双方的考虑,因为它们与人工智能和数据科学工作有关。
在人工智能中做出购买决定
制造或购买决策:制造或购买决策是在内部制造产品或从外部供应商处购买产品之间做出选择的行为。[1]
制造/购买决策的定义是不言自明的,在人工智能的特定用例中,选项如下:
Make: 对个人收集的数据从头开始实施机器学习模型——这包括构建神经网络架构、编写定制算法、利用其他 ML 方法和构建 API 来服务结果。
购买:为使用现有 API 付费,编写最少的代码来预处理现有服务并与之交互,以实现公司目标——这包括但不限于微软 Azure 或亚马逊 AWS AI 服务,用于 CV、NLP 和许多其他任务。
每条路径的限制
制作
大公司和小公司的许多 IT 领导通常都精通当前的顶级技术。他们的好奇心和对技术社区的参与通常是他们走到这一步的原因。出于这个原因,他们经常会选择超出公司整体目标范围的尖端项目。在这些情况下,他们可能会推动人工智能工作,让高度复杂的项目从零开始构建可能已经存在的人工智能技术。虽然这对团队来说是令人兴奋的,但结果往往并不完美。
我见过的一个例子是一家小型医疗服务公司,他们希望从头开始构建自己的转录(语音到文本)人工智能系统,以便与更大的应用程序进行交互。任何有经验的数据科学家都会认识到,构建一个能够在复杂的医疗操作中工作的 NLP 系统需要大量的数据和时间,其性能优于当前的语音到文本系统。无论他们被建议如何尝试利用像AWS transcript这样的服务,IT 领导们继续要求在内部构建它。进一步细分,开发的最终成本可能包括 5+的员工,在计算其他成本之前,每月的工资消耗率为 20,000+美元。另一方面显示,现有的转录服务可以以低于 1 美元的价格获得许可!
不难看出,这种“制造”决策会如何受益于“购买”决策。相反,如果任务涉及复杂和独特的数据类型,那么花费就会合理得多。同样,如果企业希望将这种转录服务作为核心产品销售,他们也会从构建自己的知识产权中受益。当我为企业的人工智能战略提供建议时,我总是会提出这些观点。认识到像微软、谷歌或亚马逊这样的企业在开发他们的服务上投入的时间和人员是很重要的。一个核心关注点不是技术的企业不太可能取得同样的结果,更不用说降低成本了。
购买
如上所述,购买决策可以提供高质量的人工智能服务,其成本和时间只是内部开发的一小部分。对于希望在内部业务流程中利用人工智能的企业来说,这是一个很好的选择。事实是,大多数希望利用人工智能的公司本质上并不是技术公司,因此利用技术公司开发的模型比立即建立一个高技能的 IT 部门更有效。
然而,购买决定也有缺点。数据不兼容和缺乏数据都是这些服务的障碍。数据不兼容是指复杂的数据结构或复杂的预期输出。许多这样的服务期望完美组织的数据产生一个通用的输出。当需要高于语音转录或图像分类水平的任务时,它们通常变得无用。在这些情况下,数据科学家将需要做足够的预处理工作,以证明构建定制模型来适应任务的潜力。考虑系统在整个生命周期中的适应性也很重要。如果计划预计会超出能力(即边缘/物联网要求),则考虑内部构建以消除这种依赖性是很重要的。最后,数据法规经常会妨碍与第三方 API 的交互,这可能是导致倾向于“做出”决策的另一个要考虑的因素。
经验分析
在过去的几年里,我通过合同和自由职业者的工作,与许多公司合作实施人工智能系统并提供建议。我总是从这个问题开始:“您是想集成一个现有的服务还是自己构建一个?”让我们来看看结果。

礼貌智力建造者 AI
很明显,大多数人倾向于构建一个完全定制的系统。我不会深入到每一个具体的案例中,但是这些应用程序中的许多都是简单的 CV 和 NLP 任务,从头开始构建是重复的。有些人可能会问,但是他们不是雇你来开发这类应用吗?
答案是,他们正在雇用一名数据科学家来完成一个目标,而我的部分任务是建议最具产品和成本效益的路线。无论模型来自哪里,用任何工具构建管道的知识和理解是每个企业最终都在寻找的。

礼貌智力建造者 AI
正如我们所看到的,最终的结果与最初的要求大相径庭。在最初的对话中,我能够从错误中挽救一些客户,但其他人花费了大量的时间和金钱试图建立模型,这些模型将被现有的服务或预先训练的模型所取代。
几个“购买”选项
这里是一些可用服务的快速列表,这些服务可以很好地集成,以有效地满足许多数据科学的需求。
- 微软 Azure 人工智能(Microsoft Azure AI):Azure 基于云的人工智能套件为计算机视觉、自然语言处理和聚类领域的任务提供 API。大多数服务都是基于 REST API 的。也有工具来构建聊天机器人和许多其他常见的人工智能用例。
- AWS 机器学习:另一家公认的云提供商,拥有众多 API。除上述服务之外,还有文档文本理解、预测、HIPAA 认证转录和欺诈检测。
- H20 : H20 提供数据工作室“让你的公司成为 AI 公司”。它们提供多个软件套件,采用跨行业数据类型并完成常见任务。
这个列表可能会占用一整篇文章来解释每种方法提供的机会和细微差别。
总之,可以说将 AI 实施到任何生产系统中都需要数据科学家和机器学习工程师团队的深厚专业知识。虽然 it 部门建立自己的人工智能系统很诱人,但考虑已经存在的选项通常更有效。这有助于避免大量的成本和麻烦。另一方面,如果一个组织有时间、资源和人员来试验一个完全不同的系统,这可能有利于在这个垂直领域创造下一个大事件。我确信,10 年后将会有大量的案例研究详细说明这些决策中的对错。像汽车这样的老行业可能会发现,通过与更多以技术为导向的合作伙伴合作来填补这些空白,他们在 autonomy 内部建设的努力本可以加快。花时间考虑你的组织是否最适合制造或购买你的下一个人工智能应用程序,可能是这一代任何商业转型中最重要的决定。
想知道更多关于我在做什么的信息,请前往智力建造者 AI
参考文献
[1]https://www . investopedia . com/terms/m/make-or-buy-decision . ASP
【2】微软 Azure AI
[3] AWS 机器学习
[4] H20
让支持向量机完全按照你想要的方式工作
支持向量机的概念是如何工作的,以及如何用它来解决你的数据问题
在分类任务中,有几种方法可以做到这一点。可以通过用线性(直)线分隔类,或者用一棵树按照一定的阈值拆分属性直到达到期望的程度,或者计算事件属于哪个类的概率来解决。
支持向量机(Support Vector Machine)是一种非概率二元线性分类器,是一种通用的机器学习算法,可以执行分类和回归任务。SVM 的另一个优势是它能够解决线性和非线性数据集。
鉴于这些众多的好处,在 SVM 有许多概念和解决方案,我发现只有几篇文章/视频真正给出了容易理解的解释,特别是针对那些对 SVM 不熟悉的人。我希望这篇文章以最全面的方式到达你的手中。
原始概念
所有这一切都始于使用一条线(具有 2D 数据集)或一个超平面(超过 3D)将实例分成两类,并尝试最大化线和最近实例之间的距离。这个距离被表示为余量。下图说明了这一点。

为什么它需要最大化这个利润?原因是一个决策边界正好位于两个类之间比一个更靠近一个类要好得多。
然而,想象有一个橙色类的异常值,它比它自己更接近蓝色类。如果我们严格地将上面的概念强加于这个数据集,就会产生下图。现在,差额满足要求,但结果比上面的差额小得多。这被称为硬边界

如果有一个新的蓝色类数据落在这个橙色实例附近,则该新数据将被误分类为橙色,换句话说,这意味着模型在新数据上的性能比在训练 1 上的性能差(我们的模型中从来不希望有训练 1)。

软余量
有一种方法可以解决这个问题,即允许对训练集的异常值进行一些错误分类,以最大化其余训练数据的差值。这个概念被命名为软间隔或者换句话说,支持向量机。

一旦有新数据,就会被正确分类为蓝色。

于是,一个问题出现了。我们如何决定软利润?(我们如何知道哪些实例在训练中会被错误分类?).
其实这个没有完美的答案。你训练数据的几个值的差距决定使用最佳的一个为您的问题。超参数在 scikit-learn 的 VC 模型中控制这一点,表示为 C. 如果模型过度拟合,减少 C.
这也是因为 SVM 只使用一条直线或超平面来做分类工作,它是一个二元分类求解器。在多类问题的情况下,将采用一对所有(或一对其余)的策略。
因此,SVM 算法最重要的规则之一就是它试图在最大化边缘街道和限制边缘违规(误分类)之间找到一个好的平衡。
非线性数据集上的 SVM
但是,对于非线性可分数据,怎么用这一招呢?请看下图,我们需要 3 行来将数据分成 2 个类,对于更复杂的数据,我们需要更多。这在计算上是低效的。

然后,内核绝招来了。内核技巧将添加其他特性,如多项式特性,然后 SVM 将利用超平面将数据分成两类,而不是在 2D 数据上教授模型。添加 2 次多项式特征后的上述数据将如下所示:

在添加了二次特征之后,实例现在被明显地分成两类
让我们用数据来进一步理解这一点。
import random
np.random.seed(42)
m = 500
X1 = 2 * np.random.rand(m, 1)
X2 = (4 + 3 * X1**2 + np.random.randn(m, 1)).ravel()
X12 = np.column_stack((X1,X2))
y1 = np.zeros((500))
X3 = np.random.rand(m, 1)
X4 = (1 + X1**1 + 2*np.random.randn(m, 1)).ravel()
X34 = np.column_stack((X3,X4))
y2 = np.ones((500))
X = np.concatenate((X12, X34), axis=0)
y = np.concatenate((y1, y2), axis=0)def plot_dataset(X, y, axes):
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.axis(axes)
plt.grid(True, which='both')
plt.xlabel("Feature 1", fontsize=20)
plt.ylabel("Feature 2", fontsize=20, rotation=0)
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()

多项式内核
我在 scikit 中使用了 SVC 类——学习 3 次多项式核,其中 coef 超参数等于 1(它控制模型受高次和低次多项式影响的程度)。linear SVC(loss = " hinge ")具有先验的多项式 features(degree = 3)transformer 会做同样的把戏。
如果你有一个非常大的数据集,继续使用 LinearSVC ,因为它在处理大数据方面比 SVC 更快。
需要记住的一点是,在训练 SVM 之前,一定要缩放数据
poly_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=0.001))
])
poly_kernel_svm_clf.fit(X_train, y_train)
poly_kernel_svm_clf10 = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=10))
])
poly_kernel_svm_clf10.fit(X_train, y_train)# Plot the model overall prediction
def plot_predictions(model, axes):
"""
Vizualize the classification result of the model to see how it
corresponds to training data
"""
x0s = np.linspace(axes[0], axes[1], 1000)
x1s = np.linspace(axes[2], axes[3], 1000)
x0, x1 = np.meshgrid(x0s, x1s)
X = np.c_[x0.ravel(), x1.ravel()]
y_pred = model.predict(X).reshape(x0.shape)
y_decision = model.decision_function(X).reshape(x0.shape)
plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)
plt.contourf(x0, x1, y_decision, cmap=plt.cm.brg, alpha=0.1)fig, axes = plt.subplots(ncols=2, figsize=(10.5, 4), sharey=True)
plt.sca(axes[0])
plot_predictions(poly_kernel_svm_clf, [-0.25,2.25,-5,20])
plot_dataset(X_train, y_train)
plt.title(r"$degree=3, C=0.001$", fontsize=18)plt.sca(axes[1])
plot_predictions(poly_kernel_svm_clf10, [-0.25,2.25,-5,20])
plot_dataset(X_train, y_train)
plt.title(r"$degree=3, C=10$", fontsize=18)
plt.show()

C 值等于 10 的模型似乎很好地抓住了要点,让我们在测试集上测量它的性能。
from sklearn.metrics import f1_score
model_list = [rbf_kernel_svm_clf,rbf_kernel_svm_clf10]
for model in model_list:
y_pred = model.predict(X_test)
print(f1_score(y_test, y_pred, average='weighted'))0.6459770114942529
0.8542027171311809
高斯 RBF 核
现在,我想用这个数据尝试不同的核,我将使用高斯 RBF 核。这里是维基百科上对这个内核的解释https://en.wikipedia.org/wiki/Radial_basis_function_kernel
由于我的数据不是太大,高斯 RBF 核并不需要太多时间。但是,对于大型数据集,高斯 RBF 核会消耗你相当多的时间。
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)# Create pipeline for training
rbf_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="rbf", gamma=0.1, C=0.001))
])
rbf_kernel_svm_clf.fit(X_train, y_train)
rbf_kernel_svm_clf10 = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="rbf", gamma=5, C=10))
])
rbf_kernel_svm_clf10.fit(X_train, y_train)# Plot the model overall prediction
fig, axes = plt.subplots(ncols=2, figsize=(10.5, 4), sharey=True)
plt.sca(axes[0])
plot_predictions(rbf_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X_train, y_train)
plt.title(r"$gamma=5, C=0.001$", fontsize=18)plt.sca(axes[1])
plot_predictions(rbf_kernel_svm_clf10, [-1.5, 2.5, -1, 1.5])
plot_dataset(X_train, y_train)
plt.title(r"$gamma=5, C=10$", fontsize=18)
plt.show()

2 值的 C 似乎产生了一个类似的模型。让我们预测测试集,并用度量标准进行评估
from sklearn.metrics import f1_score
model_list = [rbf_kernel_svm_clf,rbf_kernel_svm_clf10]
for model in model_list:
y_pred = model.predict(X_test)
print(f1_score(y_test, y_pred, average='weighted'))0.8417207792207791
0.8544599213495534
正如所料,2 个模型的性能相当,C = 10 的值略高,也略高于上面的多项式核模型。
我们可以通过调整超参数、交叉验证、添加另一种类型的特征转换来改善这一点(希望如此)。我们自己试试吧。
用 Python 制作最可爱的图表
用手绘图表可视化您的数据
在本教程中,我要介绍一个非常酷的 Python 手绘风格可视化包:cutecharts。
与常见的图表如 Matplotlib 和 seaborn 不同,这个包可以用来生成以下几种看起来像手绘的图表,在某些场景下效果可能会更好。可爱的图表也是互动的,动态的。每当鼠标悬停在图表上时,数字就会显示出来。
要创建这个图表,您只需要几行 Python 代码。

目前,这个库支持五种图表——条形图、折线图、饼图、雷达图和散点图。它还支持图表的组合。让我们逐一探究。
在我们开始绘制可爱的图表之前,我们需要安装 cutechart 库。
$ pip install cutecharts
让我们用多伦多气温的数据集来画条形图和折线图。
#import library and dataimport cutecharts.charts as ctc
df=pd.DataFrame({
‘x’:[‘Sun.’,’Mon.’,’Tue.’,’Wed.’,’Thu.’,’Fri.’,’Sat.’],
‘y’:[14,15,17,20,22.3,23.7,24.8],
‘z’:[16,16.4,23.6,24.5,19.9,13.6,13.4]})
- 条形图
chart = ctc.Bar(‘Toronto Temperature’,width=’500px’,height=’400px’)
chart.set_options(
labels=list(df[‘x’]),
x_label='Days',
y_label='Temperature (Celsius)' ,
colors=[‘#1EAFAE’ for i in range(len(df))]
)
chart.add_series('This week',list(df[‘y’]))
chart.render_notebook()

在这个条形图中,所有的条形都有相同的颜色。如果你想定制每个条的颜色,你只需要改变代码中的一行。
chart = ctc.Bar(‘title’,width=’500px’,height=’400px’)
chart.set_options(
labels=list(df[‘x’]),
x_label=”Days”,
y_label=”Temperature (Celsius)” ,
colors=**[‘#FFF1C9’,’#F7B7A3',’#EA5F89',’#9B3192',’#57167E’,’#47B39C’,’#00529B’]**
)
chart.add_series(“This week”,list(df[‘y’]))
chart.render_notebook()

2。折线图
为我们的数据集绘制折线图更有意义,这样我们可以看到上周和本周的温度差异。
chart = ctc.Line(“Toronto Temperature”,width=’500px’,height=’400px’)
chart.set_options(
labels=list(df[‘x’]),
x_label=”Days”,
y_label=”Temperature (Celsius)” )
chart.add_series(“This Week”, list(df[‘y’]))
chart.add_series(“Last Week”, list(df[‘z’]))
chart.render_notebook()

当您将鼠标悬停在图表上时,图表会自动显示带有数字的标签,并且还会绘制一条虚线,以便更直观地显示本周和上周的气温差异。
3。雷达图
要将折线图更改为雷达图,只需将图表类型更改为 ctc.Radar 即可。
chart = **ctc.Radar**(‘Toronto Temperature’,width=’700px’,height=’600px’)
chart.set_options(
labels=list(df[‘x’]),
is_show_legend=True, #by default, it is true. You can turn it off.
legend_pos=’upRight’ #location of the legend
)
chart.add_series(‘This week’,list(df[‘y’]))
chart.add_series(“Last week”,list(df[‘z’]))
chart.render_notebook()

4。饼状图
我们需要另一个数据集来制作饼图和圆环图。
df=pd.DataFrame({‘x’:[‘Asia’, ‘Africa’, ‘Europe’, ‘North America’, ‘South America’, ‘Australia’],
‘y’:[59.69, 16, 9.94, 7.79, 5.68, 0.54]})
数据集包含各大洲的名称及其人口百分比。
chart = ctc.Pie(‘% of population by continent’,width=’500px’,height=’400px’)
chart.set_options(
labels=list(df[‘x’]),
inner_radius=0
)
chart.add_series(list(df[‘y’]))
chart.render_notebook()

您可以更改饼图中每个部分的颜色。

将饼图转换成圆环图也非常容易。你只需要改变内半径的参数。
df=pd.DataFrame({‘x’:[‘Asia’, ‘Africa’, ‘Europe’, ‘North America’, ‘South America’, ‘Australia’],
‘y’:[59.69, 16, 9.94, 7.79, 5.68, 0.54]})chart = ctc.Pie(‘% of population by continent’,width=’500px’,height=’400px’)
chart.set_options(
labels=list(df[‘x’]),
**inner_radius=0.6**
)
chart.add_series(list(df[‘y’]))
chart.render_notebook()

5。散点图
为了绘制散点图,我将创建一个新的数据集来绘制温度和冰淇淋销售额之间的关系。
Temperature = [14.2,16.4,11.9,15.2,18.5,22.1,19.4,25.1,23.4,18.1,22.6,17.2]
Sales = [215,325,185,332,406,522,412,614,544,421,445,408]
然后,我们可以创建散点图。
chart = ctc.Scatter(‘Ice Cream Sales vs Temperature’,width=’500px’,height=’600px’)
chart.set_options(
x_label=”Temperature (Celcius)”,
y_label=”Icecream Sales” ,
colors=[‘#1EAFAE’],
is_show_line = False,
dot_size=1)
chart.add_series(“Temperature”, [(z[0], z[1]) for z in zip(Temperature, Sales)])
chart.render_notebook()

我们很容易看出,天气变暖会带来更多的销售。
6。组合图表
您还可以将多个图表组合在一起。
chart1 = ctc.Line(“Toronto Temperature”,width=’500px’,height=’400px’)
chart1.set_options(
labels=list(df[‘x’]),
x_label=”Days”,
y_label=”Temperature (Celsius)” )
chart1.add_series(“This Week”, list(df[‘y’]))
chart1.add_series(“Last Week”, list(df[‘z’]))chart2 = ctc.Bar(‘Toronto Temperature’,width=’500px’,height=’400px’)
chart2.set_options(
labels=list(df[‘x’]),
x_label=”Days”,
y_label=”Temperature (Celsius)” ,
colors=[‘#1EAFAE’ for i in range(len(df))]
)
chart2.add_series(“This week”,list(df[‘y’]))
chart2.add_series(“Last week”,list(df[‘z’]))page = Page()
page.add(chart1, chart2)
page.render_notebook()

如您所见,cutechart 包确实可以提供令人印象深刻的可爱图表。这个软件包的限制是它只能生成五种不同的图表。
如果你对制作其他类型的漂亮图表感兴趣,你可以看看我的其他帖子。
- 用 python 制作美丽的 Nightinggale 玫瑰图——可视化 covid19 死亡率
- 用 Python 制作一个几行字的漂亮水球图
- 用 Python 用几行代码制作一个漂亮的条形图
- 用 Python 制作几行漂亮的散点图,让你的报告出类拔萃
- 受汉斯·罗斯林教授的启发,用 Python 语言 Plotly 制作令人印象深刻的动画泡泡图
- 使用 Python 中的 Matplotlib 绘制唯一的条形图
向 SQL 的伟大飞跃
一些需要了解的微妙之处,以提高您的 SQL 技能
当我试图弥补我的 SQL 技能从不稳定的中级到自信的数据专家之间的差距时,我发现中级学习者缺乏资源。大多数 SQL 书籍要么是为了让业务分析师编写他们的第一本SELECT *书,要么是为了让经验丰富的数据库管理员(DBA)编写 DDL 来建立和维护数据库。这根本不符合我的需求——数据科学家和数据分析师需要知道如何处理复杂的表连接,并且不需要更改模式或修改数据。
我自学了 SQL。我有必要查看我负责的报告后端的数据。通过这样做,我一头扎进了一个由连接、聚合等组成的复杂世界。很多。桌子。(如果您只学习了示例数据库中最多有 5 个表的 SQL 类,那么您还没有看到任何东西——相当确切地说。)
这篇文章总结了我最近获得的一些技巧、诀窍和微妙之处,并希望与其他希望跨越 SQL 平庸和伟大之间鸿沟的人分享。

实现 SQL 的飞跃。由亚历克斯·拉德里奇在 Unsplash 拍摄的照片
SQL 语法是温和的,令人沮丧的不同。了解不同之处。
ANSI SQL(美国国家标准协会)是事实上的“标准”,所有数据库管理系统(DBMS)在创建特定于 DBMS 的 SQL 时都遵循这一标准。然而,它们似乎是以最高级的、切向的方式排列的。我看到过关于堆栈溢出的回答,坚持认为不同变体之间的语法差异非常接近,可以忽略,但是当我试图在不同的设置(PostgresSQL)中使用我在工作中(使用 SQL Server)学到的语法时,我已经陷入了太多次的忽略。
最大的问题是,我使用的语法在其他方面是有效的——网上有大量的资料来源——所以很难确切地看出为什么查询不起作用。这让我怀疑自己的技能,而不是意识到我需要使用不同的语法或找到不同的解决方案。
令人惊讶的是,我还没有找到一份完整的语法差异列表!以下是我个人遇到的一些不同之处。让我知道过去有哪些不同之处让你感到沮丧,这样我就可以添加它们了!
如果您知道任何其他可能会使您出错的语法差异,请告诉我!
百分位数函数&寻找中位数
这篇文章——实际上也是我在过去一周半时间里为提高 SQL 技能所做的尝试——是因为一个 SQL 挑战要求我找出中间值。用 Python 编写一个中值函数是我的专长,但是我对用 SQL 编写感到害怕。事实上,我在网上搜索时发现,Median 函数并不是 ANSI SQL 标准,Postgres 也没有它的实现。
有用的 ANSI SQL 标准函数
这个问题让我发现了percentile_cont()和percentile_disc(),其中是 ANSI SQL 标准函数。语法对你来说可能是新的,但是值得记住:
SELECT percentile_cont(.5)
WITHIN GROUP (ORDER BY *column_name*)
FROM *table_name*
column_name是要计算中值的列,table_name是该列所在的表。请注意我们通常使用的聚合函数是如何将column_name作为函数输入的(例如MAX(cost)或AVG(distance),但是percentile_cont(n)取的是您想要计算的百分比。在我们的例子中,我们使用 50%来获得中位数。
percenticle_disc(n)是一个类似的函数,但它仅限于数据集中实际存在的值。也就是说,如果有偶数个列,percentile_disc(0.5)将取位于数据集中间的两个值中的较小值,而percentile_cont(0.5)将返回平均值。
要知道,还有其他 ANSI SQL 标准函数可以让您计算相关性和协方差,甚至回归线斜率,而无需从数据库中取出数据。作为参考,简单看看中的 SQL。
创造性地使用常见的聚合函数
如果你创造性地思考,你实际上可以用普通的聚合函数解决中位数问题:
-- Solution #1, doesn't work in MS SQL ServerSELECT AVG(*column_name)*
FROM *table_name*
ORDER BY *column_name*
LIMIT 1 *--If you have an even number of data points, use LIMIT 2*
OFFSET (SELECT COUNT(*)/2
FROM *table_name)*;-- Solution #2, doesn't work in PostgresSQLSELECT
(
(SELECT MAX(*column_name*)
FROM (
SELECT TOP 50 PERCENT *column_name*
FROM *table_name*
ORDER BY *column_name* ) AS BottomHalf)
+
(SELECT MIN(*column_name*)
FROM (
SELECT TOP 50 PERCENT *column_name*
FROM *table_name*
ORDER BY *column_name* DESC
) AS TopHalf)
) / 2 AS Median
解决方案#1 更简单,尽管它需要人工干预来确保计算是正确的。如果您有奇数个数据点,这很容易—首先,找出哪一行描述了数据集的前 50%。这是使用内部子查询SELECT COUNT(*)/2 FROM *table_name*完成的。例如,如果有 4,383 行数据,子查询将返回第 2,191 行。因为您正在进行整数除法,所以该值是 floored(一个细微的差别,我将在后面说明)。然后,您可以编写外部查询,其中您将LIMIT 1获得您的中值,并OFFSET通过子查询的结果进行选择。(注:这也是OFFSET进来离合的绝佳例子。)
请注意,解决方案#1 仅适用于奇数个数据点。如果您想处理偶数个数据点,您需要将其修改为LIMIT 2,并计算这两个中间值的平均值。虽然在生产中这不是一个很好的解决方案,但在面试中这是一个容易记住的解决方案。
解决方案#2 是 Jeff Atwood 的堆栈溢出响应,它更复杂,但不知道数据点的数量。不幸的是,它在 PostgresSQL 或 MySQL 中不起作用,因为它们不支持TOP或PERCENT关键字。(还是那句话,知道自己的不同!)
定点和浮点数据类型。或者,为什么你的计算总是错的。
当我在一家银行担任业务分析师时,我写了一份 FSD(功能规范文档),概述了如何从各种产品数据库中获取和计算现金流。当我的开发伙伴使用 FSD 来编码计算时,我注意到这些值稍微有些偏差。数百万的交易额相差几分或几美元,但这种差异令人不安——为什么价值不匹配?
事实证明,它与数字在数据库中的存储方式以及计算中使用的数据类型都有关系。像float、real和double precision这样的浮点数据类型被不精确地存储,随着时间的推移,小的不精确性会被放大。一般来说,您应该使用像numeric这样的定点数据类型来进行任何精确的计算。关于为什么永远不应该使用浮点数据类型来进行计算——尤其是数字类型——的更多信息,请查看这个伟大的堆栈溢出响应。要点是如果
顺便说一句,整数除法就是地板除法
与从 Python 2 到 Python 3 所做的改变不同,除法不再默认为整数除法,SQL 仍然假设两个整数之间的除法是底数除法。也就是说,余数被丢弃,只返回一个整数。(例如SELECT 7/3返回2)
如果你想在你的值没有被平均分配时也获得十进制值,不要忘记先把一个值转换成数据类型。例如:
-- Example #1
SELECT 7/CAST(3 AS float);-- Example #2
SELECT 7/3::float;
在上面的两个例子中,函数CAST()和符号::都可以用于类型转换。关于如何使用CAST得到浮点答案的详细说明,我推荐这个堆栈溢出答案。
铅字铸造。或者,如何修正你的计算。
类型转换一开始可能会感觉棘手,尤其是因为 SQL DBMS 标准之间的数据类型是不同的。但是我建议您弄清楚哪些数据类型——尤其是数值型——对于您选择的 SQL 是有效的,并确保您知道计算的结果是什么数据类型!即使您没有对结果中的每一个数值或每一列进行强制转换,您至少应该知道您将得到什么。使用默认结果很容易给你错误的答案。
使用 CAST 函数
强制转换的语法很简单:
CAST(*expression* AS *datatype(length)*)
其中*expression* 可以是列名,也可以是列间的计算。*datatype*是您希望将表达式CAST成的数据类型,(*length*)是可选的,但是可以用于指定varchar(25)的字符限制或类似于numeric(8,1)的数字精度。
使用::符号
::符号的工作方式与CAST函数完全一样,所以如果你看到的是它而不是CAST,就知道它们都在进行类型转换:
-- Using ::
SELECT a.count::Float / (b.count + a.count) * 100 AS ratio-- Using CAST()
SELECT CAST(a.count AS Float) / (b.count + a.count) * 100 AS ratio
请注意,在上面的示例中,我们在计算比率之前将被除数转换为浮点数,因此我们的结果是浮点数而不是整数。
如何检查数据类型
一些数据库管理系统,如 pgadmin4,会在查询结果窗口中显示数据类型:

一些 DBMS 很友好地向您展示了数据类型
其他时候,您需要研究元数据指定的数据类型。您可以通过 DBMS GUI 做到这一点,例如,SQL Workbench 允许您通过数据库浏览器查看表元数据:

通过 SQL Workbench 中的数据库浏览器查看的数据类型
否则,如果您有足够的权限,可以使用以下 SQL 来查看数据类型:
SELECT COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH
FROM information_schema.columns
WHERE TABLE_NAME = '*table_name*';
你在纠结什么?
我很想听听 SQL 技巧真正提升了您的游戏水平——尤其是我在本文中没有提到的那些——或者您仍在努力解决的问题!
将您的数据模型制作成网站

数据可视化
使用 GitHub 部署您的 jupyter 笔记本,让任何人都可以免费查看
你做到了!由于你的分析天才,你成功地确定了预测你所在地区未来十年房地产价格的主要因素,或者气候变化的主要原因,或者你可以在亚马逊上与最高销售额相关的产品描述中使用的词语。只有一个小问题:你需要与世界分享你的发现!
在这篇文章中,我将向您展示如何使用工具免费将您的数据模型部署为网站: Python、Jupyter Lab/Notebook、Git、和 GitHub 。点击以下任何链接,查看我在过去几年中参与的项目网站:
Seaborn 演示项目,车道线寻找项目,人物分类器项目,车辆检测项目,交通标志分类器项目,高级车道线寻找项目,行为克隆项目
先决条件: 安装 Python ,安装 jupyterlab ,安装 Git ,拥有 GitHub 账号
如果您已经准备好了一个 jupyter 笔记本和一个 GitHub 存储库,请跳到第三步
1.创建您的仓库
在你的 GitHub 账户上,你应该创建一个新的库,然后 git 将这个库克隆到你的电脑上。
如果您对本文的 Git & GitHub 部分有任何疑问,请参见“ 掌握 Git 的基础知识&GitHub
您将使用的命令应该如下所示:
**git clone** [**https://github.com/CodyNicholson/Make_Your_Data_Models_Into_Websites_Article.git**](https://github.com/CodyNicholson/Make_Your_Data_Models_Into_Websites_Article.git)*(Replace my URL with the URL you copied from your repo)***cd** [**Make_Your_Data_Models_Into_Websites_Articl**](https://github.com/CodyNicholson/Make_Your_Data_Models_Into_Websites_Article.git)**e/** *(Replace my repository name with yours)***jupyter lab**
您现在应该看到 Jupyter 实验室,它应该已经在您的默认浏览器中打开了一个选项卡
如果您在使用 git clone 命令时遇到问题:确保您已经使用上面提供的链接安装了 git。确保您提供的链接是您通过点击 GitHub 资源库中的绿色“克隆或下载”按钮复制的 HTTPS 链接。
如果您在使用 jupyter lab 命令时遇到问题:确保您正确安装了 jupyter lab。当你点击上面的安装链接时,我使用了他们提供的各种选项中的“pip install jupyterlab”选项。
2.创建 Jupyter 笔记本
在你新打开的 Jupyter 实验室中,点击 【笔记本】 标题下的【Python 3】框。这将创建一个新的 Untitled.ipynb 文件并打开它。从这个新文件中,您可以在代码单元格中编写和运行 Python 代码,并在 markdown 单元格中添加标题和描述。

在上图中,你会看到我已经创建了两个单元格。第一个单元格是一个 Markdown 标题单元格,我在其中添加了标题“我的项目网站”,它将作为标题出现,因为我在单词前加了“#”。运行该单元格将产生一个格式良好的标题。在这个单元格下面,我创建了一个代码单元格,只打印“hello world”。以您选择的任何名称保存该文件将结束我们的 Jupyter 笔记本的创建。请参阅本文开头的“我的项目”链接,了解将来可以添加到笔记本中的更高级逻辑的示例。
3.将我们的笔记本导出为 HTML 文件
在我们打开的 Jupyter Lab 选项卡中,转到:文件→将笔记本导出为… →将笔记本导出为 HTML** 。这将下载一个与您的 ipynb 文件同名的 HTML 文件。**

一旦我们下载了这个文件,你应该把它移到你的仓库里,并且确保你重命名了这个文件:*index.html*****
4.向 GitHub 添加、提交和推送更改
在您的终端或 git bash 窗口中——确保您在您的 git 存储库中。然后,我们应该运行这个命令来选择我们的存储库中所有要提交的更新文件:
**git add .**
接下来,我们将运行此命令提交所有已更改的文件,并给出一条有用的消息:
**git commit -m "Added project notebook and project index.html file"**
最后,我们可以使用以下命令将其向上推:
**git push**
如果我们在这之后去我们的 GitHub 仓库,我们应该看到:

- 如果你不小心犯了”。DS_Store”文件—不要害怕,忽略它。这是一个临时文件,您可以在以后删除它。
5.启用项目网站
回到我们的 GitHub 在线资源库,我们将点击页面顶部“用户名/资源库名称”链接下工具栏中的最后一个选项“T2【设置”按钮。
在以下设置页面—向下滚动到“选项菜单的“ GitHub 页面”部分。您应该会看到一个“ Source ”标题,下面是一个下拉菜单,默认选项为“ None ”。

从下拉菜单中选择总分行,刷新您的设置页面。向下滚动到“ GitHub Pages ”部分,现在应该会显示这条以蓝色突出显示的消息:

这意味着该网站仍在设置中,您需要等待大约一分钟。持续刷新页面,直到“ GitHub 页面”部分的蓝色阴影框再次变为高亮绿色,如下所示:

单击已发布的网站链接应该会将您带到新的项目网站!我的网站可以在:https://clairvoyantcoding . github . io/Make _ Your _ Data _ Models _ Into _ Websites _ Project/

你可以为你的每个 GitHub 库建立一个网站,就像这个一样,把一个index.html文件放在你的库的根目录下,然后像这样启用 GitHub 页面。
6.免费网站的限制和提示
令人惊讶的是,GitHub 为你创建的每个项目提供这些免费网站——但它也有一些限制。对于每个项目,除了你的index.html页面,你不能有更多的页面。因此,如果你添加page2.html并试图从你的index.html引用它,你将无法到达第 2 页。
如果一个文件叫做。DS_Store** "出现在你的储存库中确保你删除它。它是自动创建的,可以包含您不希望通过将其部署到 GitHub 页面与外界共享的文件路径。**
该项目网站的另一个常见错误或限制是,您的主 HTML 文件必须命名为“index.html”,并且它必须位于您的存储库的根目录下,这意味着它不能从您的存储库中的另一个文件夹中引用。
最后,尝试在你网站的每个代码单元前加上一个标题和/或描述标记单元。能够轻松创建项目网站并与世界共享是一件好事,但是您的内容需要能够被您网站的任何访问者所理解。即使是不懂 Python 的人。因此,为了获得最佳的用户体验,总是要尝试并总结你做得好的地方。
这里是本文的存储库:https://github . com/ClairvoyantCoding/Make _ Your _ Data _ Models _ Into _ Websites _ Project
感谢阅读!我很乐意听到你的反馈或者回答任何关于本教程的问题,所以请在下面评论,我会尽力帮助你。
Docker 让您的数据科学生活变得简单
理解、构建和使用 Docker 映像和容器用于数据科学
介绍 Docker 容器用于数据科学需求和项目的迷你指南

https://unsplash.com/photos/eIjIn7zln2U
O 当你开始你的数据科学之旅时,首先要做的是安装不同的软件,比如 Python、Jyupter Notebook、一些 ide 和无数的库。一旦您成功地通过了这一关,您经常会遇到这样的情况:您的代码在您的计算机上似乎工作得很好,但是当您与他人共享它时,它似乎会无缘无故地崩溃。好吧,你并不孤单!
好消息是,有一些令人印象深刻的解决方案,它们在便利性、可访问性和易用性方面有所不同。谷歌 Colab 就是其中之一。它已经准备好启动,加载了许多有用的库,并有 GPU 支持。它也有其局限性。但不是今天文章的主题。可以在这里 学习体验 Google Colab 。
什么是协同实验室?Colaboratory,简称“Colab”,是谷歌研究院的产品。Colab 允许任何人…
research.google.com](https://research.google.com/colaboratory/faq.html)
在本文中,我们将采取不同的方法。我们先动手,后面再来解释。这种方法将展示它有多简单,以及为什么要成为一名精通数据的科学家,您应该学习更多的相关知识。
下面是我们今天要学习的主要概念和任务列表:
1️⃣docker 是什么?
2️⃣ 安装 Docker 桌面
3️⃣ 运行数据科学加载 Jupyter 笔记本
4️⃣ 理解容器
5️⃣ 什么是图像& Dockerfile?
6️⃣ 创建一个定制的 Docker 图像
7️⃣ 保存&分享你的图片 t47】
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
让我们开始逐一讨论。
Docker 是什么?

版权所有 Akhil Bhadwal (hacker.io)
D ocker 是一家提供解决方案的公司(解决方案的名字也是 Docker!)到我们上面描述的问题。事实上,它不仅如此,而且是开发人员工具箱中的一个优秀工具,但我们将坚持它与我们的数据科学相关问题的相关性。这是一个帮助我们构建“映像”和运行“容器”的软件,以支持和更好地交付数据科学项目。我们将在本文后面解释“图像”&“容器”的概念。如上所述,我们先动手,解释随后就到。你可以在这里 阅读更多关于 Docker 。
2013 年,Docker 推出了集装箱行业标准。集装箱是一个标准化的单位…
www.docker.com](https://www.docker.com/why-docker)
在我们开始之前,我还建议在 Docker 上创建一个帐户(免费版本也可以)来保存你在 Docker Hub 上的项目。
安装 Docker 桌面
Vis it this链接 并安装 Docker 桌面。它与任何其他软件安装没有什么不同。可以选择 Windows 版本或者 Mac 版本。对于我们的演示,我们将使用 Windows 版本。Mac 的过程几乎是相同的。下载完成后,单击下载的文件进行安装,并按照说明进行操作。这个过程很简单,应该会很顺利。如果你想在安装前看看这个过程,我在 YouTube 上找到了一个很好的 11 分钟的视频,带你完成安装过程。
视频作者:编程知识
安装完成后,您可以进行一些检查,看看一切是否正常。打开您的命令提示符/终端,编写以下代码并按 enter 键:
docker -v
这将通过向您提供我们安装的 Docker 版本来确认安装是否成功。

作者图片:Docker 版本和安装检查
运行加载了数据科学的 Jupyter 笔记本
我的魔术时间到了。打开命令提示符/终端,写下以下代码:
docker run -p 8888:8888 jupyter/minimal-notebook
我稍后会解释这段代码,现在只需遵循这些步骤。我们是第一次这样做,所以需要一些时间来准备。下一次,重新运行这个命令不会花费更多的时间,因为所有必需的文件都已经下载了。此外,你也不需要任何互联网连接(不像谷歌的 Colab)。该过程结束后,输出应该是这样的:

图片作者:拉&运行数据科学加载 Jupyter 笔记本与一个单一的命令
复制最后三行中的任何一行(这些是地址)并粘贴到您的任何浏览器中(保存令牌供以后使用,在单词“token”后面的地址中提供)。这将在您的浏览器中打开一个 Jupyter 笔记本。
你会注意到笔记本自带 Python3,Julia & R,不仅如此,很多流行的数据科学库都已经安装好了,随时可以导入!

作者图片:通过复制粘贴地址在浏览器中打开 Jupyter 笔记本

作者图片:这个 Jupyter 笔记本装载了许多数据科学库
😯😲 😯 部分是, 这些程序实际上都没有安装在你的机器上!
所以如果你试图在你的电脑上找到 Python/Julia/R 或者 Jupyter 笔记本,祝你好运!即使您之前在计算机上安装了这些程序,这些“dockerized”安装也是独立安装,与您计算机上已安装(或未安装)的应用程序 无关 。
这意味着,如果您使用我们刚刚创建的 Jupyter 笔记本创建一个程序或编写一段代码,测试它,并与您的朋友或同事共享(所有这些内容将在本文后面介绍),只要您的朋友或同事像我们一样启动他们的 Jupyter 笔记本,它就一定会工作。
了解容器
故事从容器的概念开始。不过,这个想法并不新鲜;你可能已经熟悉了“环境”这个概念。几乎是一回事。在适当的时候,数据科学家将创建和开发许多模型,这些模型将依赖于许多库或许多其他数据科学家的工作(我们称之为依赖)。随着依赖性的发展和增长,这将不可避免地导致所有这些模型之间的“矛盾”。
先说一个很一般化的例子。想象你有很多💰💰💰并决定建立一个工厂来生产商业用途的东西。你建了一个工厂(目前只是一个大厅),安装了各种不同的机器和工作场所。然后你雇佣熟练工人来做这项工作。当你的生意是新的,没有规模的时候,事情就不复杂,而且进展顺利。但是,随着业务的增长和竞争的加剧,您决定增加更复杂的技术和先进的流程。问题来了;当你适应这些新技术时,你会意识到这些过程中的一些根本不能在一个屋檐下工作,例如,一种技术需要干燥的环境,而相反,另一种技术在更潮湿的环境中工作。人也一样,一些人需要安静的环境,而另一些人需要在嘈杂的机器前工作(或者出于其他一些随机的原因)

两个技术高超的人一起工作却无法共事(来源:P【ixabay.com】)
那么你想到的最直观的解决方案是什么?
显然,您将简单地建造单独的房间(而不是建造单独的建筑)和大厅,以确保每个过程和部门都得到它所需要的环境。这个解决方案类似于“容器”的概念。
继续我们的示例,现在您想要在另一个国家或地理区域建立具有完全相同设置的相同设施。想象一下,一种技术可以以某种方式克隆您现有的生产设置,并且您可以简单地将其移植到所需的位置。这类似于“共享容器”。
一个与数据科学更相关的例子是您使用 sklearn 版本 x 为用例 a 创建的模型。五个月后,sklearn 有了一个新的改进版本 x+1。您更新了您的库,并使用新版本为另一个用例 b 创建了另一个模型。每个人都很高兴,直到您为用例 A 运行您的模型,该模型崩溃并不运行。结果是新的 sklearn 版本不再支持旧的模型。因此,您只能运行旧模型(如果您回去安装较旧的 sklearn 版本)或新模型,而不能同时运行两者。
再次,试着想一个可能的解决方案。一个简单的方法是再买一台电脑,在上面安装新的 sklearn 版本。这肯定会解决问题。❌Please 不要向任何人建议这个!❌,因为你还能坚持多久?每次更新你的 sklearn 库都买新电脑,更别说其他几百个库了,绝对不是一个实用的解决方案。
如果我们将特定项目所需的所有软件和库都安装在一台计算机或操作系统中,并“隔离”在它们自己的空间中,会怎么样?这样,你的模型将只停留在它的边界之内,而不会干扰它之外的任何东西。

作者图片:隔离拯救了生命,也解决了一些编程/数据科学问题
这就是你们所说的容器;项目及其所有依赖项都封装/隔离/隔离在一个操作系统中。我们可以向前一步,与他人共享该容器,然后他人可以在他们的机器上添加和运行该容器,并执行相同的实验,而不必担心所有涉及的依赖关系。
👉👉👉这正是我们之前通过 Docker 所做的,在命令提示符下运行一行代码。Jupyter 的开发人员将 Python、Julia、R 和其他库放在一个容器中,在云上共享,我们通过 Docker 拉取并运行它。👈👈👈
至此,我们准备再引入两个概念,以获得一个完整的图景;图像和 Dockerfile。
什么是图像和 Dockerfile 文件?
图像是容器的种子。它是项目在某个时间点的“快照”。只有当我们“运行”它时,它才成为一个容器。把它想象成你给你朋友的漂亮房间拍的照片,然后你计划用同样的方式布置你的房间。它的美妙之处在于,我们可以在运行图像并将其转换为容器之前对其进行修改。这种改变来自于一个文档。Dockerfile 是一个扑克脸文件(它没有任何扩展名,如 csv,txt 等。)包含对 Docker 的指令。
在我们的演示中,Jupyter 拍摄了项目的快照,制作了图像,并以“jupyter/datascience-notebook”的名称发布在 Docker Hub 上。我们提取并运行图像,将其放入一个容器中。但是,我们没有改变图像;我们只是照原样运行。这就是为什么没有涉及 Dockerfile。
在下一节课中,我们将展示一个示例,在该示例中,我们将在运行容器之前修改笔记本并添加 Tensorflow 和一个名为 preprocess1 的数据预处理库。这次为了让事情变得更轻更快,我将使用 Jupyter 笔记本的另一个图像(称为 jupyter/minimal-notebook)。如果您愿意,您可以保留我们之前使用的图像。
创建定制的 Docker 图像
让我们继续前面的例子,在这个例子中,我们从 Docker Hub 中“拉出”了加载了数据科学的 Jupyter 笔记本。只是这一次,我们会通过 Dockerfile 将 Tensorflow & preprocess1 库添加到其中。但是首先,让我们看看这个过程会是什么样子。

作者的图像:构建和运行自定义图像的流程
📔如果你有并且知道如何操作 MS Visual Studio 代码,这个过程会变得容易得多。现在,假设我们没有 VS 代码,我们将执行这些步骤。
- 1️⃣创建项目文件夹:在你的电脑上,创建一个空文件夹,你想保存你的项目文件。
- 2️⃣创建 Dockerfile:在文件夹内,创建一个文本文件。打开文件,写下下面的代码(以#开头的行只是注释)
**# import pre-built image from data science notebook* FROM jupyter/minimal-notebook*# Install required libraries* RUN pip install tensorflow
RUN pip install preprocess1*
如您所见,到目前为止,代码很容易阅读和理解。我们只做了导入 Jupyter 笔记本并使用“FROM”和“RUN”命令安装我们想要的库。
- 3️⃣保存 Dockerfile:关闭文件,右键单击将其重命名为“Dockerfile”(确保遵循准确的拼写和大小写),删除扩展名(。txt)并保存它。你的 Docker 文件准备好了!
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
➕奖金:通常,我们通过一个名为“需求”的文本文件来完成所有这些库安装(尽管名字并不重要)。您只需将库名与您想要的任何特定版本放在一起,并将文件保存在 Dockerfile 所在的同一文件夹下。文件中的库要求如下:
*tensorflow==2.2.0
preprocess1==0.0.38*
下面是将这个文本文件“添加”到 Jupyter 图像中的代码。
* [## 投稿食谱- docker-stacks 最新文档
用户有时会分享使用 Jupyter Docker 堆栈的有趣方式。我们鼓励用户贡献这些…
jupyter-docker-stacks . readthedocs . io](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/recipes.html)
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
- 4️⃣火了你的命令提示符,并'光盘'的文件夹中,我们创建了 docker 文件。在那里,我们运行下面的命令来构建我们的映像。
docker build -t notebook_demo .
同样,代码非常直观;这是一个 docker 命令,用来构建一个名为 notebook_demo 的映像。“-t”是用于命名/标记图像的标志词。最后,“点”意味着我们使用的 Dockerfile 在 active directory 中。按回车键执行命令行。它应该是这样的:

作者的图像:在通过 Dockerfile 构建图像的过程中

作者的图像:在图像建立之后
- 5️⃣运行图像:我们现在准备运行我们刚刚创建的图像。在命令提示符/终端中运行以下命令:
docker run -p 8888:8888 notebook_demo
这个命令意味着它是运行名为 notebook_demo 的映像的 docker 命令。标志字“-p”表示将其映射到容器和主机之间的端口 8888。
完成后,复制所提供的三个地址中的任何一个,并在您的浏览器中粘贴它,以打开和访问您的 Jupyter 笔记本(保存令牌供以后使用)。导入 tensorflow & preprocess1 库,以确保它们是正确的。

作者图片:运行新定制的图片作为容器

作者图片:我们可以导入 tensorflow 和 preprocess1 库,而无需 pip 安装它们
我们成功加载了一个最小的 Jupyter 库,预装了一些定制库,如 TensorFlow 和 preprocess1。
保存&分享你的图片
如果我们不能将自己的工作移植到其他电脑上,或者与其他用户分享,这有什么好处呢?那是我们的最后一步!值得注意的是,一旦你在你的电脑上建立了一个形象,它会自动保存。您可以使用 run 命令随时访问它,而不需要任何互联网连接。
▶️的一个选择是将其保存到 Docker Hub。这使它成为公共的,任何人都可以访问它,就像我们从 Docker Hub 访问 minimal 和 data science Jupyter Notebook 一样。这种方法的一个问题是当你上传到 Docker Hub 时图像的大小,因为它增加得相当快。
我们将需要在命令提示符/终端中使用以下命令来保存到 Docker Hub:
#log into Docker Hub
docker login — username= your_Docker_username
#Enter your password when prompted# Push your Image by name, in our case "notebook_demo"
docker push your_Docker_username/your_image_name
就是这样!您的图像可以公开使用。任何安装了 docker 的人都可以轻松访问同一个映像,并使用我们已经熟悉的命令添加(tensorflow & preprocess1)确切的依赖关系:
docker run -p 8888:8888 notebook_demo
▶️The 的另一个选项是将其保存为一个 tar 文件,我们需要在命令提示符/终端中运行以下命令。您需要位于保存 tar 文件的同一个目录中。
# save it under the active directory
docker save notebook_demo > notebook_demo.tar# you can load it this way
docker load — input notebook_demo.tar
恭喜你!如果你已经做到了,你应该得到热烈的掌声!
👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏

图片来源:www.vectorstock.com
👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏
摘要
在本节课中,我们学习并应用了以下内容
✅ 什么是 Docker?安装 Docker 桌面 ✅ 通过 Docker 跑数据科学加载 Jupyter 笔记本 ✅ 了解容器的概念 ✅ 了解 Docker 镜像&Docker 文件 ✅ 创建自定义 docker 镜像 ✅ 保存
记住,我们只是触及了表面。有这么多的学习和爆炸性的材料。图片不仅仅是 Jupyter 笔记本的。它们可以是完整的操作系统、编程语言等等。我强烈建议你看看 Docker 网站上的用例及参考资料
世界领先的服务,用于与您的团队和 Docker 社区查找和共享容器图像。对于…
www.docker.com](https://www.docker.com/)
请随时给我反馈。毕竟我们就是这样学习和提高的!*
用高斯核使你的 KNN 平滑
找出让你的 KNN 更强大的方法。

图片来自 https://unsplash.com/photos/8Zv3Ygm2CLM
这篇文章假设你知道 KNN 的基本知识。所有源代码都在 https://github.com/seho0808/knn_gaussian_medium 的。请随意使用。
所有的要点都在第一部分和第二部分。之后只是为了帮助你更好地理解和彻底浏览源代码。
第 1 部分:默认 KNN 是离散的
一般来说,已知使用 KNN 和随机森林的回归具有离散的预测值。换句话说,预测值不是平滑的,因为我们取原始数据点的平均值。如果你看下面的图,你可以看到默认 KNN 的预测是非常离散的。

图 1 均匀权重的 KNN 插值
Scikit-Learn 库中的默认 KNN 回归器只是在 K-neighbors 中使用统一的权重。换句话说,我们简单地取 K 个最近邻居的平均值。Scikit-Learn 库为此提供了另一种选择:反距离加权。这使得通过使用距离的倒数作为权重,更近的点对预测有更大的影响。下面的图 2 显示了反距离加权。

图 2 使用反距离权重的 KNN 插值
现在看起来比以前光滑了。您注意到的第一件事是 X=(2,4)中的小跳跃。这些缝隙在那里是因为我们没有太多的输入数据。然而,真正的问题是预测曲线似乎过度适应真实数据的噪声。如果给定数据中没有随机噪声,这可能不是过度拟合,但在大多数情况下,像这样完全拟合到单个点是有害的。假设在 X=6 处给定一个新点。如果我们的预测曲线过度拟合随机噪声,新值的误差将会很高。要检查模型是否过度拟合,可以进行交叉验证。
第 2 部分:过度拟合的解决方案
为了解决这个过度拟合的问题,我们需要提出一个新的权重函数。可以说最著名的核函数高斯核解决了过拟合问题。图 3 显示了结果。

图 3 高斯内核的 KNN 插值(宽度=2)
高斯内核使用下面图 4 中的公式。

图 4 高斯核方程
w 是权重,d(a,b)是 a 和 b 之间的距离,σ是我们设定的一个参数。查询点是我们试图估计的点,所以我们取 K 个最近点之一的距离,并赋予其权重,如图 4 所示。那么我们如何在 Python 中做到这一点呢?图 5 显示了我的源代码的截图。我在文章顶部附上了 Github 链接,供大家免费使用。

图 5 在 Scikit-Learn 上使用高斯内核的源代码
如图 5 所示,我们将 weights 参数设置为自定义函数。需要注意的一件重要事情是,您可以将内核宽度设置为您想要的任何值。对于默认的 KNN,您只需要调整一个参数:K-最近邻。使用高斯核时,还需要调整核宽度参数。我建议对每个参数组合进行交叉验证的网格搜索。(即,对于 K=4,宽度=2 为 10 K 倍,对于 K=4,宽度=2.1 为 10 K 倍,等等。)
第 3 部分:调优内核宽度和 n 邻居
这部分更像是附录。这个的源代码也包含在顶部的同一个 Github 链接中。我生成了图 6 中的数据。简单来说就是 y=x+ε,其中ε~N(0,5)。我们将学习如何调整高斯核 KNN。

图 6 生成的数据
我们需要调整两个参数:n_neighbors 和 kernel_width。“n_neighbors”控制我们在 KNN 使用多少邻居。“kernel_width”控制高斯核中的分割参数。有许多方法可以优化超参数。优化算法完全是另一个话题,所以我不会深入细节。通常,对于简单的问题,我们使用网格搜索和随机搜索。网格搜索简单地说就是沿着笛卡尔平面线性探测超参数的组合。随机搜索是设置边界并通过超参数的随机组合进行搜索。图 7 显示了搜索结果。我结合使用了网格搜索和随机搜索。n_neighbors 采用网格搜索方式,因为我们用尽了范围[1,11]内的所有值。kernel_width 采用随机搜索方式,我们在 0 到 100 之间随机选择 100 个值。(确切的说,我用的是“ np.random.randint(5,100000,100)/1000”)。
对于每个组合(图 7 中的单个数据点),我运行了 100 次引导运行。换句话说,图 7 中的每个点都是 100 次 KNNruns 的平均误差度量。自举运行可以替代 K-fold。在这种情况下,我采用 9:1 的测试比率来训练数据集大小。为了更容易理解,引导交叉验证过程应该是:
随机分割 90%的训练集和 10%的测试集= >用选择的 90%的训练集训练 KNN 模型= >预测 10%的测试集并获得准确性指标= >同样,随机分割 90%的训练集和 10%的测试集= >…做 100 次
我通常会做 10~20 次引导运行,但是越多越好。在这种情况下,数据集很小,所以我运行了 100 次。如果您想使用 K-fold,请随意。

图 7 优化两个超参数的随机网格搜索。
那么我们如何解读图 7 呢?正如你在右边看到的颜色条,我们想要浅蓝色,这意味着低误差值。似乎总的趋势是,从 6 个邻居和更高的邻居开始,误差值的递减趋势似乎趋于平稳。此外,对于 kernel_width,任何高于 20 值似乎都会产生较低的误差。从这里开始,一切都是启发式的:您可以根据自己的项目使用自己的逻辑来选择超参数。让我们检查最小误差点。

图 8 获取图 7 中最小点的代码截图。
最小误差似乎是在 7 个邻居处,对于核宽度为 61.739,平均绝对误差为 3.7698。在许多其他应用中,您可能也希望围绕最小值参数进行网格搜索,但我们在这里将跳过这一步。更需要注意的是,内核宽度的高值会使预测不平滑!实际上,我们的收益率值 61.739 绘制成图 9。

图 9 可以看到贴合不平整!
那我们该怎么办?如果降低宽度值,可以看到从 kernel_width=10 或更低的值开始,曲线变得更加平滑。因此,如果您想要获得平滑的曲线和高精度,您将不得不从小于 10 的 kernel_width 中选取较低的误差值。图 10 显示了结果。

图 10 你可以看到 kernel_width=8 产生了更平滑的拟合。
对此我们该如何解读?好吧,至少对于这个生成的数据,统一权重似乎比高斯核稍微好一点。然而,对于更平滑的曲线,误差度量的差异也不是很大,因此您可以使用高斯核或统一权重。对于您自己的应用,您还必须仔细查看误差指标,以选择要使用的权重。生成您自己的图,如图 7 所示,以查看各种选项的趋势。
结论
根据你的项目或应用,使用高斯核或任何其他核可以帮助你的模型更好地拟合数据。这篇文章展示了如何使用高斯核,这是最流行的核之一。如果您发现本文中有任何错误或有任何疑问,请通过 koolee33@gmail.com 或 seho0808@vt.edu发邮件给我。你也可以用这篇文章的评论部分,但是我会反应比较慢。
参考
- Scikit-Learn 库 KNN 回归器链接(你可以在这里找到权重选项):https://sci kit-Learn . org/stable/modules/generated/sk Learn . neighbors . kneighborsregressor . html
- 对于 KNN 使用的其他内核:https://www . ismll . uni-hildesheim . de/lehre/ml-07w/skript/ml-2up-03-nearest-neighbor . pdf
使用 Streamlit 让您的机器学习模型活起来
使用这个免费的 Python 库来快速提供模型和显示数据
你做了一个机器学习模型。耶!😀你希望人们不用启动 Jupyter 笔记本就能使用它。嗯。🤔你该怎么办?
你可以用烧瓶来伺候你的模特。Flask 是一个很好的轻量级网络框架,但是它需要了解路线和其他网络事物。😕 Django 是一个全服务框架,但是比 Flask 有更陡峭的学习曲线。如果只是想最快的服务一个模型,应该用什么?
快去救援!有了 Streamlit 你可以在几分钟内提供一个机器学习模型,而无需学习 Javascript 框架。🚀

资料来源:Pixabay.com
Streamlit 是一个新的开源库,它使用 Python 并与常见的数据科学库很好地集成。它很好地处理了交互性和可视化。

套用联合创始人 Adrien Treuille 的话,Streamlit 应用是将小部件视为变量的 Python 脚本,可以重用数据和计算,并且可以在实时编码环境中开发。Streamlit 非常适合快速开发!
快速入门:
开始使用 Streamlit 非常简单:
- 在你的 Python 虚拟环境中
pip install -U streamlit pandas。 - 在文本编辑器中键入以下内容,并将文件另存为 my_app.py :
import streamlit as st
import pandas as pddf = pd.DataFrame(dict(a=[1, 2, 4], b=[3, 1, 7]))
st.line_chart(df)
3.在您的终端中执行streamlit run my_app.py。

编码并实时查看输出
嘣!🧨:你已经创建了一个图表,你的用户可以与之互动并下载!

折线图
让我们深入了解什么是 Streamlit,什么不是。
什么是细流
- 深受用户喜爱
- 年纪轻的
- 固执己见的
- 快速开始使用
- 纯 Python
- 可视化的理想选择
- 有利于互动
深受用户❤️的喜爱
我这里只是有一些轶事,但是通读一下 Streamlit 社区论坛上的评论和 GitHub 上的问题,你会看到用户真的对 Streamlit 感到兴奋。它解决了数据科学家的一个痛点。🎉
年纪轻的🐣
Streamlit 于 2019 年秋季正式上线,并已快速迭代。该图书馆得到了硅谷风险投资公司的支持,该公司在启动时筹集了 600 万美元的种子资金。
固执己见的☝️
Streamlit 将为您提供一个带有可选边栏的单页应用程序。您可以垂直添加一个又一个元素。
Streamlit 服务器每次都会从头到尾重新运行您的脚本。没有回调。Streamlit 允许您缓存函数,以便您只在必要时重新运行代码和重新加载数据。
快速开始使用🏃🏾♀️
正如你在上面看到的,Streamlit 附带电池。它与 Python 数据科学堆栈配合得很好:pandas、NumPy、scikit-learn、TensorFlow 和 PyTorch。
纯 Python🐍
如果 Javascript 框架和模型-视图-控制器范式( MVC )不是你的东西,Streamlit 已经帮你搞定了。你只需要 Python 函数、控制流和装饰器。如果你想调整格式,可以加入一些 Markdown 和 HTML/CSS。
可视化的理想选择📊
细流已经通过绘图默认使用牛郎星。它可以很容易地改变到其他可视化选项,如 Matplotlib 、 Plotly 、 Bokeh 、 Holoviews 、 Graphviz 和 deck.gl 。
有利于互动⏯
内置的 Streamlit 函数使添加复选框、下拉菜单、文本框和其他交互式功能变得容易。Streamlit 将这些小部件视为变量,稍后您将会看到。
快速部署
更新于 2021 年 7 月 28 日:Streamlit 将托管您的应用程序,只需点击几下鼠标即可从 GitHub 部署。这是最简单的部署系统。当你推送到指定的 GitHub 分支时,Streamlit 会自动部署新版本。😎
得体的造型控制🎨
更新于 2021 年 7 月 28 日:自撰写本文以来,格式选项已经有了显著的改进。现在,您可以创建多个列,并更轻松地控制应用程序的外观。不管是好是坏,它仍然不是一张白纸。
管理会话状态🎮
更新于 2021 年 7 月 28 日:最新的 Streamlit 版本使保存会话状态变得更加容易。您仍然没有 cookie 功能。
现在您已经看到了什么是 Streamlit,让我们看看它不是什么。
什么不是细流🚫(从版本 0.80.0 开始)
Streamlit 不是一个全功能的 web 框架。🕸:没有路由器,所以你不能有多个页面。没有认证。你不能添加 javascript,所以不会出现弹出窗口。
未来🎁
Streamlit 有一个快速一致的发布周期,并且有添加社区所要求的特性的历史。🎉
好了,现在你有了地形,让我们看看如何使用 Streamlit!⚡️
使用细流
要运行下面的代码,请将 Streamlit 安装到一个包含 Python、pandas、NumPy 和 Plotly 的虚拟环境中。在撰写本文时,Streamlit 只在 PyPI 上,所以您需要pip install它。
我建议您并排设置 web 浏览器和代码编辑器,以获得最佳开发体验。😀
您可以在每次更新时手动重新运行您的代码,在您更改代码后,单击 web 应用程序中的重新运行。我建议你通过点击总是重新运行来设置你的应用程序自动重新运行。

更改后的标题按钮
如果电线真的缠绕在一起,你可能需要偶尔刷新你的网页或重启你的 Streamlit 服务器,但一般来说,事情应该只是工作。👍
如果你卡住了, Streamlit 文档异常清晰。这里是社区论坛。
让我们来看看这 10 个关键的 Streamlit 函数。
10 个关键功能
- 标题
- 文本
- 降价
- 数据帧
- 形象化
- 交互式小工具
- CSS 修改
- 媒体
- 贮藏
- 杂项功能
我们先来看标题。
标题
安装了 Streamilt 和一个为您的文件提供服务的 Streamlit 服务器(streamlit run my_app.py),在您的文本编辑器中输入以下代码,并在您的 web 浏览器中观察神奇的事情发生。🐇
import streamlit as stst.title("The Title for my App")
st.header("A Header")
st.subheader("A Subheader")
如果您没有看到任何内容,请将网络 URL 从终端复制到网络浏览器窗口。或者,如果您的 Streamlit 服务器已经在运行,请单击浏览器窗口顶部的重新运行按钮。😉

标题,页眉,副标题= h1,h2,h3
使用您的浏览器检查工具,您可以验证这些函数分别创建了 h1 、 h2 和 h3 HTML 标签。如果你需要 HTML 入门,我建议你去 W3 学校。👍
文本
用st.write()输出文本。
st.write("Some text to output")
或者,如果不需要特殊功能,只需键入字符串,就可以跳过st.write()。
"Some text to output"
像 Jupyter 笔记本一样,一个值或变量名本身会输出到屏幕上。与 Jupyter 笔记本不同,方法调用的结果不会输出任何东西。您必须将返回值保存为变量才能显示它。☝️
例如,以下内容不会显示任何内容:
("Some text to output").upper()
但是这将:
my_uppercased_string = ("Some text to output").upper()
my_uppercased_string

输出文本
值得重复的是,Streamlit 会在您每次进行更改时从头到尾重新运行您的代码。当你探索 Streamlit 时,你会发现你不想一直显示所有的东西。注释掉代码块以节省时间和屏幕空间。👍
降价
你可以使用 markdown 来格式化你的文本并添加表情符号,如下所示:
st.markdown("_This_ __is__ *__markdown__*. 😀")
其中显示了以下内容:

降价促销
您也可以使用 Markdown 添加链接,如下所示:
st.markdown('Learn Python [here](https://memorablepython.com)')
维奥拉。出现一个链接。
我们稍后将探索其他降价用例。
数据帧
Streamlit 是以数据科学家为理念构建的。您可以像这样直接输出熊猫数据帧的内容:
df = pd.DataFrame(dict(a=[1, 2, 4], b=[3, 1, 7]))
df
用户可以自动对这些列进行排序。🎉
如果您想要样式增强,请显式使用st.dataframe()。例如,您可以突出显示每列中的最小值,如下所示:
st.dataframe(df.style.highlight_min(axis=0))

突出显示的数据框架
或者,您可以使用st.write()来实现相同的结果,如下所示:
st.write(df.style.highlight_min(axis=0))
st.write()检测传递给它的对象的类型并相应地调整。
现在让我们看看 Streamlit 可以对绘图做些什么。
形象化
Streamlit 使可视化变得轻而易举。💨
它为交互式折线图、面积图和条形图提供了默认功能。你看了上面的st.line_chart()。st.bar_chart()和st.area_chart()类似。他们都使用引擎盖下的牛郎星绘图库。
有许多其他的顶级函数包装绘图库,例如 Matplotlib 的st.pyplot()和 Mapbox GL 的st.map()。下面是从文档中获取的创建地图的代码:
map_data = pd.DataFrame(
np.random.randn(1000, 2) / [50, 50] + [38.9, -77],
columns=['lat', 'lon']
)st.map(map_data)
这是输出结果:

st.map()的输出
或者,您可以使用您最喜欢的 Python 绘图库。例如,这里有一个来自 Plotly 文档的地理可视化。
with st.spinner("Component is loading"):
fig = px.scatter_geo(
df_geo, # just making it take some time load
title='Gapminder Data',
locations="iso_alpha",
color="continent",
hover_name="country",
size="pop",
animation_frame="year",
projection="robinson",
)fig

用 Streamlit
请注意,我们添加了一个st.spinner()上下文块,在内容加载时显示一条消息。👍
Streamlit 的绘图非常酷!
现在让我们来看看 Streamlit 的核心交互功能。
交互式小工具
Streamlit 使用预定义的函数来创建交互式小部件。
下面是一个选择小部件的例子。

选择小部件输出
创建小部件和变量的代码只有一行!
transport = st.selectbox(label=”Select Transportation”, options=[“car”, “bike”, “walk”])
这里有七个 Streamlit 函数,您可以使用它们让用户选择一些东西。我包括了每个小部件所需的参数和描述。
button(label='Click to do something')—点击按钮radio(label='Choose', options=['rock', 'classical', 'jazz'])—单选按钮checkbox(label='Check the box')—切换复选框selectbox(label='Choose one', options=['walk', 'bike'])—从下拉菜单中选择一个选项multiselect(label='Choose as many as you like', options=['walk', 'bike'])—从下拉菜单中选择多个选项slider(label='Slide the bar')—从滑动条中选择一个值beta_color_picker(label='Pick a color')—选择一种颜色
这里有六个功能供用户输入或上传东西。
number_input(label='Input a number')—输入一个数字text_input(label='Enter text')—输入文本text_area(label='Write an essay')—输入多行文本date_input(label='Input a date')—输入日期time_input(label='Input a time')—输入时间file_uploader(label='Upload a .jpg file')—上传文件
只需向交互函数传递一个用户将会看到的标签。将返回值保存为变量,并对其进行处理。就这么简单!😀
让我们看看如何使用这些小部件的更多信息。
使用小工具
这些小部件是可定制的,并带有合理的默认值。例如,下面是st.date_input()小部件代码:
date = st.date_input(label='Input a date')
date
结果是:

您可以向date_input传递默认值、最小值或最大值。现在,date_input各自的默认值是今天、2021 年 1 月 1 日和今天加 10 年。
请注意,不允许有重复的小部件。每个小部件必须通过你传递给它的参数来区分,否则你会得到一个错误。如果需要,您可以传递一个key参数来确保唯一性。👆
我不会在这里演示所有的小部件类型,但是让我们看看一些常见的模式。
您将经常使用带有if语句的复选框。下面是如何根据用户是否勾选了复选框来显示或隐藏数据框。
display_df = st.checkbox(label='Want to see the data?')if display_df:
df
下面是输出的样子:

带有控制流的复选框,用于显示数据帧
像这样用st.sidebar将任何小部件添加到侧边栏:
st.sidebar.radio(
label="Choose wisely",
options=["Laser Tag", "Ax Throwing", "Trampoline Park"]
)
现在,一个可扩展的侧边栏将容纳这个小部件。👍

侧栏随着单选按钮展开。
虽然大多数小部件已经存在了一段时间,但颜色选择器小部件仍处于测试阶段,可能会发生变化。代码如下:
user_color = st.beta_color_picker("Pick a color")
user_color

颜色选择器小工具
Streamlit 小部件是该库如此强大的重要原因。我鼓励你和他们一起玩,看看他们有多酷!😀
CSS 修改
在 Streamlit 中修改 CSS 是可能的,但并不优雅。您可以通过使用st.markdown("<style> some css goes here </style>")来修改 CSS。
这是一个改变页面某一部分的文本颜色的基本例子。
st.markdown(
'''
<span style="color:blue">
Print it in blue. <br />
Please. 😀
</span>
''',
unsafe_allow_html=True
)
注意多行 CSS 使用了三重引号。☝️

改变文本的颜色。
你必须使用带有关键字参数unsafe_allow_html=True的st.markdown()来访问底层 CSS。
交互式 CSS
让我们看看颜色选择器小部件如何允许用户更改页面上的背景。这是代码。
user_color = st.beta_color_picker("Pick a color")
user_colorif user_color != "#000000":
st.markdown(
f"<style> body{{ background-color: {user_color};}}</style>",
unsafe_allow_html=True
)
注意由于字符串插值,需要用双花括号{{ }}来转义。下面是实际使用的颜色选择器:

使用颜色选择器更改页面上的 CSS
自举
Streamlit 使用 Bootstrap 进行样式化,因此您可以访问 Bootstrap 类,如按钮和警告。例如,以下是如何显示成功徽章:
st.markdown(
'<span class="badge badge-pill badge-success"> Badge </span>',
unsafe_allow_html=True
)

使用引导程序的徽章输出
你可以试着用 Bootstrap 做一个网格布局,但是 Streamlit widgets 不会尊重这个布局,所以这不是一个好的选择。☹ ️A 电网布局方案正在酝酿中。🙂
移除品牌
下面是删除用 Streamlit 文本制作的的移除汉堡菜单和页脚的代码:
hide_st_style = """
<style>
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
</style>
"""st.markdown(hide_st_style, unsafe_allow_html=True)
- 来源 : Streamlit 论坛。
媒体
让我们看看如何在您的 Streamlit 应用程序中显示图像、视频和音频文件。
图像
您需要导入PIL库来显示带有[st.image()](https://docs.streamlit.io/en/latest/api.html#streamlit.image)的图像。下面的代码可以用来从用户那里获取图像并显示出来:
from PIL import Imageimg = []
img = st.file_uploader(label='input', type=['png', 'jpg'])if img:
image = Image.open(img)
st.image(image, caption='Your Image')
如有必要,可以指定宽度和 BGR 通道。
视频
用[st.video()](https://docs.streamlit.io/en/latest/api.html#streamlit.video)播放视频。你可以播放自己的视频或 YouTube 上的视频。以下是如何从 45 秒开始播放 YouTube 视频:
st.video(
'https://www.youtube.com/watch?v=AqAJLh9wuZ0',
start_time=45
)
默认的视频格式是 mp4 ,但是您可以指定其他格式。
音频
用[st.audio()](https://docs.streamlit.io/en/latest/api.html#streamlit.audio)播放音频文件。您可以指定除默认 wav 文件类型之外的内容,并传递开始时间。
贮藏
缓存可以节省应用程序用户第二次加载应用程序的时间。缓存允许你的应用程序避免重新加载相同的文件和重复相同的计算。
用@st.cache装饰器添加缓存。以下是 Streamlit 缓存工作原理的基本解释:
Streamlit 检查这四项内容:
- 用来调用函数的输入参数
- 函数中使用的任何外部变量的值
- 函数的主体
- 缓存函数中使用的任何函数的主体
如果这是 Streamlit 第一次看到这四个组件具有这些确切的值,以及这种确切的组合和顺序,它将运行该函数并将结果存储在本地缓存中。然后,下一次调用缓存的函数时,如果这些组件都没有改变,Streamlit 将跳过执行函数,而是返回之前存储在缓存中的输出。
-来源:文件。
缓存有助于提高应用程序的速度,但也很棘手,有时会表现得出乎意料。⚠️
杂项功能
Streamlit 让用户可以轻松地从汉堡菜单中创建屏幕录像。录制截屏选项为用户提供了一系列录制屏幕选项。这有助于合作。👍
您可以轻松显示 Streamlit 应用程序背后的代码。只需将您想要显示的代码放在一个st.echo()上下文块中,如下所示:
with st.echo():
def my_function():
return None
输出是格式良好的代码,在用户屏幕上看起来像这样:

来自应用程序的代码
或者,如果您想显示格式化的代码但不想运行它,可以像这样使用st.code():
st.code(
"""
my_var = f"testing my code {1 + 2} times"
"""
)

不是由应用程序运行的代码
包装
Streamlit 可以让你快速地将机器学习模型转变为基本的应用程序。它包含许多有用的功能,并定期进行改进。Streamlit 已经成为一种流行的自助服务工具,即数据科学家的工具箱。
我希望这篇关于 Streamlit 的介绍对您有所帮助。如果你有,请在你最喜欢的社交媒体上分享,这样其他人也可以找到它。😀
我写关于 Python、T2、SQL 和其他技术主题的文章。如果你对此感兴趣,请注册我的邮件列表中的令人敬畏的数据科学资源,在这里阅读更多帮助你增长技能的内容。👍
资料来源:Pixabay.com
流线型快乐!😀
使用这些技巧让你的 Matlab 代码更快更真实
我从 4 年多的旅程中学到的技巧,在 Matlab 上工作和编码。

如果你曾经使用 Matlab 进行你的大学项目或研究模拟,你知道它在模拟几乎任何你想要的问题方面有无限的潜力和灵活性。更重要的是,用户界面简单易学,代码易于初学者掌握。
大约 4 年前,我开始在 Matlab 中编写代码,这段旅程令人兴奋,充满了学习。我在学士学位期间开始在 Matlab 上为我的课程项目编写代码,现在我全职使用它进行我的博士论文研究。在我的旅程中,有好几次我不得不等待几个小时到几天,让我的模拟收敛。我总是想知道— 我怎样才能让它更快,我怎样才能让 for 循环迭代得更快?此外,我的一些工作需要分布式设置,即不同版本的 Matlab 相互对话,交换信息并运行算法来执行特定任务。我一直在想——我怎么能做到这一点?我如何让我的代码变得足够酷,变得真实?
在这篇文章中,我将分享一些有用的编程技巧,这些技巧是我在 4 年的编程和玩 Matlab 的过程中学到的。我们开始吧!
1.更快的 for 循环
For 循环可能是 Matlab 中使用最广泛的代码块之一。对于运行迭代算法、计算一组数据的矩阵乘积或模拟一个系统的时间,For 循环无处不在。For 循环按顺序计算每个迭代,这使得它在大量迭代和大量计算时变得缓慢。Matlab 的并行计算工具箱来帮忙了。
并行计算工具箱使您能够利用多核计算机、GPU、集群、网格或云来解决…
www.mathworks.com](https://www.mathworks.com/products/parallel-computing.html)
例如,考虑这个非常简单的例子,我需要计算矩阵a和b ,中条目的元素和,并将结果存储在c中。
a = randn(1e7,1e7);
b = randn(1e7,1e7);
c = zeros(1e7,1e7);for i=1:1e7
for j=1:1e7
c(i,j) = a(i,j) + b(i,j);
end
end
在我的测试中,这个 for 循环计算需要大约 7.72 秒来完成。让我们看看如何在这里使用并行 for 循环。
首先,声明工作线程的数量,最大为处理器拥有的超线程内核的数量。
parpool(4); %declare number of workers (max=cores) parfor i=1:1e7 %use parfor instead of for
for j=1:1e7
c(i,j) = a(i,j) + b(i,j);
end
enddelete(gcp('nocreate')); %close parallel computing
请注意,嵌套的 for 循环是不允许的,因此我们将其中一个 for 循环改为并行循环,并保持内部循环不变。同样的任务现在只需要 1.36 秒。并行计算工具箱不仅仅限于 for 循环,还具有各种有用的功能,使您的模拟能够更快地完成,这样您就可以睡个好觉。
2.进度条(带 ETA)
你是否曾经等着想知道你的代码需要多长时间才能完成执行?我相信你已经尝试了各种选项,其中之一是打印出一个循环的迭代次数,然后估计一下需要多长时间才能完成。好了,不要再这样了!
这个版本的 waitbar 与 MATLAB 的版本兼容。因此,不需要对现有的进行任何修改…
www.mathworks.com](https://www.mathworks.com/matlabcentral/fileexchange/22161-waitbar-with-time-estimation)
您可以在所有的 while 和 for 循环中使用这个插件,不仅可以查看进度的百分比,还可以获得估计的完成时间。它真的很棒,我一直在我所有的 Matlab 项目中使用它。用法就像下面这样简单。
h = waitbar(0,'Please wait...'); %handle for the waitbarfor i=1:1e7
c(i) = a(i) + b(i);
waitbar(i/1e7,h); %update waitbar status
end

学分: Mathworks
你会看到一个进度条,如图所示,上面有“进度百分比”和“预计剩余时间”。
3.分布式算法或共享数据
分布式算法是在不同的计算机上一起执行特定任务的算法。尤其是大型系统,使用分布式算法来使这种算法在单个处理器上更快、更不密集。这种设置还要求数据在不同的计算机之间共享。
然而,大多数时候,在模拟这种算法时,我们只是编写一段代码,然后在一个 Matlab 环境中运行。虽然这可能会产生正确的最终结果,但是当在真实的分布式设置中实现时很难想象它将如何收敛。我将向你展示我是如何发现使用简单的代码使这变得又酷又真实的。

作者创建的 GIF
考虑这个例子,我有两台不同的计算机 PC1 和 PC2。它们分别生成一个随机数,然后需要将它们的数字相互通信,以将两个数字的总和报告给 PC 上的两个用户。虽然这似乎是一个非常简单的问题,但它会让您理解底层的方法,从而使解决方案更加现实。
PC 2 的代码
r = floor(10*rand(1,1)); %random number
disp(strcat('PC2 chose random number as : ',num2str(r)));tot = r; %total
fid = -1;while fid==-1
%data.txt is the shared file used for communication fid = fopen('data.txt','a');
fprintf(fid,'%d %d\n',2,r);
pause(1);
fclose(fid);
endi=0;
while i==0
disp('PC 2 is attempting to get data from PC 2')
fid = fopen('data.txt','r');
tmp=fscanf(fid,'%d %d\n');
fclose(fid);
if (size(tmp)~=0)
if (tmp(1)==1)
tot = tot+tmp(2); %read PC1 data from shared file
i=1;
disp(strcat('Our total is > ',num2str(tot)));
else
disp('PC 1 has not yet written data');
end
pause(rand(1,1)); %pause for small random time
endfclose('all'); %close all files
注意,这里 data.txt 作为一个通信文件。类似的代码在 PC 1 上运行,它读取相同的 data.txt 文件,查看 PC 2 共享了什么。

作者模拟 GIF
你可以在上面的 GIF 图像中看到,两个独立的 MATLAB 环境(相当于两台 PC)如何选择一个随机数,然后通过一个. txt 文件相互通信,以得出相同的最终答案 11。很酷,不是吗?这仅仅是个开始,你可以用这个想法做很多更酷的事情。如果想要更真实的场景,还可以通过远程 SQL 服务器共享数据。这将能够模拟一个更真实的情况,即程序运行在世界上任何地方的两台不同的 PC 上,并且它们仍然得到相同的答案 11。
使用用户名和密码创建到数据源的数据库连接。数据库连接是一个连接…
www.mathworks.com](https://www.mathworks.com/help/database/ug/database.html)
4.向量化您的计算
人们在使用 Matlab 函数时最常犯的一个错误是使用 for 循环来执行某些向量计算。例如,考虑一个函数minProduct,它返回 3 个向量输入的乘积的最小值:x,y,z。传统上,我们会编写一个 for 循环来实现这一点,如下所示。
function d = minProduct(x,y,z)
% find the minimum of product of entries of x, y, z
d = zeros(length(x),1);for i=1:d
d(i) = x(i)*y(i)*z(i); %compute product and store
endd = min(d); %output the minimum of vector d
然而,如果我们以矢量化的形式编写上述函数,将其命名为minProductVectorized,那么代码将如下所示。
function d = minProductVectorized(x,y,z)
% find the minimum of product of entries of x, y, zd = x.*y.*z;
d = min(d); %output the minimum of vector d
对每个包含 100,000 个条目的 3 个随机向量x,y,z运行这些函数,minProduct 需要 0.23 秒来执行,而 minProductVectorized 只需 0.089 秒来计算最小值。
5.现场脚本
实时脚本是 Matlab 最未被充分利用的特性之一。它是在 2016 年发布的 Matlab 中引入的,但大多数学生、教育工作者和研究人员仍然不知道或不使用它。我将通过一个简单的例子来证明这种方法的有效性。
考虑一下,我想为x=0:0.01:10策划罪恶(nx)。这里n可以是任何数字,我应该能够画出从 1,2,..所以如果n=3,我的图应该包含sin(x), sin(2x)和sin(3x)的图。在传统的 Matlab 脚本中,我们会定义一个参数n,并在每次需要更多曲线时手动更改它的值。然而,使用 live script,我们可以只放入一个滑块用于n,Matlab 将负责适当地运行代码以适应情节。

作者模拟 GIF
不就是美吗?当我第一次尝试它的时候,我对用实时脚本管理你的代码是多么简单而强大感到敬畏。这可能看起来是一个非常简单的例子,但是当您需要在代码中的几个地方更改变量以查看输出时,它会非常方便。手动编辑是乏味的,很难跟踪,并且可能给你漂亮的代码带来错误。相反,通过使用这个简单的工具在旅途中可视化您的输出来美化它。这很容易学习,而且肯定会帮助你实现不同参数的代码。
MATLAB live 脚本和 live 函数是将 MATLAB 代码与嵌入式输出相结合的交互式文档…
www.mathworks.com](https://www.mathworks.com/help/matlab/live-scripts-and-functions.html)
我希望你喜欢这篇文章,并学会了使用 Matlab 的新方法,使你的代码更快更真实。这些是我在日日夜夜摆弄 Matlab 的 4 年旅程中学到的一些重要技巧。如果你想分享任何其他有用的提示,欢迎在下面评论。
感谢阅读。如果你想谈论这篇文章,请随时拨打 jishnudeep.kar@gmail.com T3联系我。
如果你喜欢这个故事,你可能想看看这些。
如果你曾经想过在世界的某个地方拥有你的分身,人工智能可能很快就会实现。
towardsdatascience.com](/artificial-intelligence-might-just-get-you-your-doppelganger-6511be7a405b) [## 从印度到美国的文化冲击——一个学生的视角
如果你计划去美国,并且对那里的文化太过好奇,这可能是你最好的剧透!
medium.com](https://medium.com/illumination/cultural-shock-visiting-the-usa-from-india-a-students-perspective-1f901df99984) [## 机器学习对于保持家庭照明变得越来越重要
机器学习超越了图像分类和语音识别。了解为我们的产品提供动力变得多么重要…
towardsdatascience.com](/machine-learning-is-becoming-increasingly-important-to-keep-your-homes-lit-7bd2e62ca2b) [## 为什么我要辞去 7 万美元的工作,过“无聊”的生活?
在进入印度最负盛名的 IIT 德里学院后,我唯一的梦想就是获得高薪…
medium.com](https://medium.com/the-innovation/why-i-left-my-70k-job-for-a-boring-life-160129d42f21)
制作自己的 Python 包

无论您是开发人员还是偶尔的 Python 用户,很难想象一个 Python 脚本在代码的最开始没有一堆 import 语句(或包)。
但是你有没有想过这些神奇的进口包是从哪里来的?

Import 语句使 Python 模块化且易于使用
在本文中,我将指导您如何制作一个 Python 包,带有您自己的自定义函数,您可以用任何代码导入它。这是在团队内部共享现成代码的最快方式,也是对 Python 社区做出贡献的最佳方式,因为任何用户都可以简单地 pip 安装您的包并导入它。
所以我们开始吧!
第一步。制作包装元素
我假设你已经熟悉 Python,但是制作一个包需要知道一些细节。我为您提供了一个预先发布的包(名为 dist_alx ),它基本上是一个文件/文件夹,其中包含了一个包在发布之前必须拥有的所有必要元素。我们将使用这个文件夹作为指南,因为所有 Python 包都必须具有相同的结构。 dist_alx 包具体做什么,这里解释。
要获取该文件夹,请转到我的 Github 库,在您的机器上下载 dist_alx.zip 并将其解压缩。该父文件夹 dist_alx 包含以下文件:
- setup.py 文件-包含包元数据
- setup.cfg 文件-用于存储设置的配置文件格式
- 与父文件夹同名的子文件夹(在本例中为 dist_alx ),其中存储了您的包的实际 Python 代码
每个包装都必须具备以上三个要素。除此之外,包还应该包含以下内容:
- 您的 Python 包必须有一个唯一的名称。没有两个现有的 Python 包可以共享同一个名称。
- 父文件夹和子文件夹必须具有相同的名称,即您的包的名称。
- setup.py 文件中有参数 名称 和包。它们还应该与您的包同名。
- 注意版本参数,如果你修改了你的包并重新发布它,你也应该修改版本
- 在 setup.py 文件中有 author_email 参数。在此键入您自己的电子邮件地址
第二步。编写代码
在这个子文件夹中有这个包的实际 Python 代码。如果你打开 dist_alx 子文件夹,你会注意到它包含了一个 init。py 文件。默认情况下,Python 内核会寻找 init。py 文件作为读取代码时的起点。 init。py 文件链接到子文件夹中的所有其他 Python 脚本(例如,在我们的 init 中)。py 文件,这个链接是通过从。Gaussiandistribution 导入高斯线),这样所有。py 文件连接在一起。在尝试编写包代码之前,最好先复习一下关于 Python 类的知识。
第三步。 开立 PyPI 账户
大多数公开可用的 Python 包都存储在 PyPI 库中。当您在您的机器上安装一个包时(通常通过一个 pip install 语句),您实际上是从 PyPI 存储库中下载这个包并将其安装在您的机器上。当发布一个新的包时,你把它上传到 PyPI 服务器,这样社区就可以使用它了。为了能够在 PyPI 上发布,你需要在 PyPI 上开一个(免费)账户。确保使用与用于 author_email 参数相同的电子邮件地址。

第四步。 发布你的包
发布是从命令提示符/终端完成的,在 Windows 和 Linux 中命令是相同的。
a. 导航到父文件夹的位置

b. pip 安装设置工具和绳线

c. 类型:python setup.py sdist

注意,现在在父文件夹中创建了两个新文件夹( egg-info 文件和 dist 文件夹)。

d. 类型:捆绳上传距离/*

您需要提供您的 PyPI 用户名(不是电子邮件)和密码。

瞧啊。您的包现在托管在 PyPI 服务器上,可以使用了!
e. 进入 PyPI ,点击你的账户,进入你的项目。如果一切正常,你应该在那里看到你的包裹。

注意 PyPI 在文件命名中只支持破折号(-)而不支持下划线(_)。因此 dist_alx 变成了 dist-alx。然而,当稍后导入包时,我们将正常键入 dist_alx。
第五步。 用你的包
去你最喜欢的 Python 客户端(Terminal,Ipython,Jupyter)然后 pip 安装你的包。然后导入您的包并从中获得乐趣!

重述
在本文中,我们经历了创建 Python 包的以下步骤:
- 制作必要的包装元素并注意命名
- 编写包代码
- 创建 PyPI 帐户
- 在 PyPI 上发布包
- Pip 安装、导入和运行软件包
最后一个音符
在 dist_alx 包中的代码是由 Udacity 编写的,因此所有与它相关的致谢和评论都可以发给他们。
在将您的包放在主 PyPI 服务器上之前,首先在 PyPI 测试服务器上发布它通常是一个好主意。
用变形金刚和 DialoGPT 微调制作你自己的 Rick Sanchez(机器人)
教 GPT-2 像一个疯狂的科学家一样写作
我是' Rick 和 Morty '和 NLP(自然语言处理)的忠实粉丝。在看了《疯狂科学家和他孙子的冒险》的最后一集后,我意识到我必须应用我在 NLP 和机器学习方面的知识来创造我自己的 Rick(至少目前是以聊天机器人的形式)。

图片来自 Giphy
创造虚拟瑞克的道路并不容易。我尝试了许多模型和方法,但虚拟里克在很长一段时间内都不想与我找到共同语言。瑞克对我的问候的第一个反应是“我不是你的伙伴”(说实话,一开始,他只知道这句话)。但我没有放弃,在优秀的变形金刚库和微软的大规模预训练响应生成模型(DialoGPT)的帮助下,我成功地与 Rick 进行了推心置腹的交谈。这是我们的一次对话:
用户:嘿,瑞克,给我做个时光机
瑞克伯特:你是个怪物!
用户:不,我只是想穿越时空
RickBot :回到过去。
用户:是
RickBot :请不要时光机。
用户:但是我需要
RickBot :你不需要,莫蒂。去做吧。
用户:我想看古希腊
RickBot :哎呀。

图片来自 Giphy
一点理论
在这篇文章中,我将告诉你如何创建一个虚拟角色,其陈述将基于我最喜欢的动画科幻情景喜剧的脚本。你可以使用你选择的角色和情景喜剧。我添加了代码,将带有对话框的常规文本文件转换成模型能够理解的格式。
正如我已经提到的,变形金刚库,其中包含最新的 NLP 模型(如伯特、 XLNet 、 GPT-2 )将帮助我们完成任务。你可以在 Jay Alammar 的一篇插图精美的文章中读到更多关于变形金刚的内容。

图片来自http://jalammar . github . io
不久前,微软的 DialoGPT 被添加到变形金刚模型集合中。DialoGPT 是 GPT-2 的模型,接受了来自 Reddit 讨论线程的 1.47 亿次多回合对话的训练(你可以在这里了解更多关于 GPT-2 的信息)。这个模型非常适合为一个有趣的对话创建一个虚拟角色,即使在小的实现选项中,它也可以保持连贯的对话,我们现在将看到这一点。
与 DialoGPT 的第一次对话
我们将在 Google Colab 中进行所有的实验,它的资源足以训练小型 DialoGPT 模型。首先,我们将连接到 Google Drive 并安装必要的模块。
from google.colab import drive
drive.mount('/content/drive/')! pip -q install transformers
让我们移动到所需的文件夹,我们将在其中存储所有的数据。
import osos.chdir("/content/drive/My Drive/Colab Notebooks")
尽量用 DialoGPT 聊天,不要微调。
from transformers import AutoModelWithLMHead, AutoTokenizer
import torchtokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-small")
model = AutoModelWithLMHead.from_pretrained("microsoft/DialoGPT-small")
让我们聊 5 行
for step in range(5):
# encode the new user input, add the eos_token and return a tensor in Pytorch
new_user_input_ids = tokenizer.encode(input(">> User:") + tokenizer.eos_token, return_tensors='pt')# append the new user input tokens to the chat history
bot_input_ids = torch.cat([chat_history_ids, new_user_input_ids], dim=-1) if step > 0 else new_user_input_ids# generated a response while limiting the total chat history to 1000 tokens
chat_history_ids = model.generate(
bot_input_ids, max_length=1000,
pad_token_id=tokenizer.eos_token_id
)# pretty print last ouput tokens from bot
print("DialoGPT: {}".format(tokenizer.decode(chat_history_ids[:, bot_input_ids.shape[-1]:][0], skip_special_tokens=True)))
用户:嗨里克
对话 PT: 嗨里克
用户:你好吗?
DialoGPT: 我很好,你好吗?
用户:我没事。莫蒂在哪里?他在地下室。
用户:莫蒂是谁?对话:他是个毛头小子。
用户:你是谁?
对话:我是毛蒂。

图片来自 Giphy
还不错,但不太令人印象深刻。我们将通过微调来修复它。
模型初始配置
让我们训练我们自己的瑞克聊天机器人。首先,我们需要基本的配置和一个数据集。配置和训练脚本大多基于 Huggingface 的这个脚本和 Nathan Cooper 的伟大教程。
将 Python 脚本参数转换为 Colab notebook 的类参数。
准备数据集
我们的对话数据集将基于安德拉达·奥尔特亚努的文章中使用的关于里克和莫蒂情绪分析的数据集。非常感谢她的工作,也感谢 Gabriel Hernandes,原始文本数据集的作者!

图片来自 Giphy
首先,我们将使用一个 Kaggle 模块来下载需要的数据集。你可以通过这个链接阅读关于这个模块以及如何获得 Kaggle API 令牌的更多细节。或者您可以从这篇文章中下载 RickAndMortyScripts.csv 文件,并将该文件放在您的工作目录中。
!pip install kaggle!mkdir ~/.kaggle
!cp kaggle.json ~/.kaggle/kaggle.json!kaggle datasets download andradaolteanu/rickmorty-scripts -f RickAndMortyScripts.csv
!mv datasets%2F506221%2F935855%2FRickAndMortyScripts.csv RickAndMortyScripts.csv
让我们看看原始数据集。
all_rick = pd.read_csv('RickAndMortyScripts.csv')
all_rick.head(10)

我们将以这样一种方式转换该数据集,即每个响应行将包含 n 个以前的响应作为上下文。就我们的目的而言,之前的七个回复就足够了。
contexted = []n = 7for i in range(n, len(all_rick['line'])):
row = []
prev = i - 1 - n # we additionally subtract 1, so row will contain current response and 7 previous responses
for j in range(i, prev, -1):
row.append(all_rick['line'][j])
contexted.append(row)columns = ['response', 'context']
columns = columns + ['context/'+str(i) for i in range(n-1)]df = pd.DataFrame.from_records(contexted, columns=columns)
df.head(5)

将我们的数据集分成训练和测试部分。
trn_df, val_df = train_test_split(df, test_size = 0.1)
现在,我们将把数据集转换成适合我们模型的格式。基本上,我们将在每行的一个字符串中连接响应(此外,我们将在响应之间添加特殊的“字符串结束”标记,因此模型将理解字符串中每个响应的结束)。
培训和评估
训练我们的模型将需要相当多的代码,但不要担心,一切都应该按原样工作,主要的事情是以正确的格式给模型数据集。

图片来自 Giphy
这是主要的跑步者代码。
是时候训练我们的模特了!
main(trn_df, val_df)

图片来自吉菲
我们的数据集很小,所以训练不会花很多时间(通常大约半小时)。
和瑞克聊天
模型做好了,该和 Rick 聊聊了。但是别忘了,我警告过你,瑞克可能会很粗鲁。
在响应生成中可以使用多种方法。你可以通过这个链接找到关于这些方法的更多细节。

图片来自 Giphy
tokenizer = AutoTokenizer.from_pretrained('microsoft/DialoGPT-small')
model = AutoModelWithLMHead.from_pretrained('output-small')# Let's chat for 5 lines
for step in range(5):
# encode the new user input, add the eos_token and return a tensor in Pytorch
new_user_input_ids = tokenizer.encode(input(">> User:") + tokenizer.eos_token, return_tensors='pt')
# print(new_user_input_ids)# append the new user input tokens to the chat history
bot_input_ids = torch.cat([chat_history_ids, new_user_input_ids], dim=-1) if step > 0 else new_user_input_ids# generated a response while limiting the total chat history to 1000 tokens,
chat_history_ids = model.generate(
bot_input_ids, max_length=200,
pad_token_id=tokenizer.eos_token_id,
no_repeat_ngram_size=3,
do_sample=True,
top_k=100,
top_p=0.7,
temperature = 0.8
)
# pretty print last ouput tokens from bot
print("RickBot: {}".format(tokenizer.decode(chat_history_ids[:, bot_input_ids.shape[-1]:][0], skip_special_tokens=True)))
用户:瑞克,你好吗?
RickBot :我没事。
用户:莫蒂在哪里?里克波特:他在医院里。
用户:为什么?那要看谁先崩溃——我还是医院。我是说,那个一直给我吃药的人。
用户:我不懂
RickBot :哇!哇哦。
用户:我明白了,你吃药了
RickBot :嘿,我——我并不以此为荣。
还不错。我会再举几个对话的例子来说明里基现在是我们的里基。

图片来自 Giphy
用户:你是谁?
RickBot :音乐人,我不是音乐人,但我跟你挺亲近的。
用户:你是哪种音乐人?
RickBot :谁在乎?我是一个音乐家。
用户:好,给我放一首
RickBot :闭嘴听我说,莫蒂。听我说。听着!我是一群不同死亡世界的领袖,我只是想组建一个乐队。我会把它做成一体,你会成为其中的一部分。
用户 :ok
RickBot :哇,哇,嘿,这是谁?
用户:这是 Morty
RickBot :哎呀!!!

用户:你怎么看待埃隆·马斯克?
:我经常想起他。
用户:但是你到底是怎么想的?他不是一个坏人。他只是…不是一个很有魅力的人。
用户:我觉得他很有魅力
RickBot :他是。
用户:你还能说他什么?T21:你什么都不用说。他是你们班的领导。
用户:好的,谢谢
RickBot :!!!
结论

图片来自 Giphy
恭喜你!我们的虚拟瑞克(几乎)还活着!借助于在小数据集上对 DialoGPT 模型的微调,我们能够创建一个虚拟角色,我们可以与他进行大量的 mad 对话。
使用所提出的方法,我们可以基于任意的对话数据集创建许多有趣的虚拟角色(只是一个包含角色演讲的 csv 文件,每行一个演讲)。
所有提到的代码都可以作为 Google Colab 笔记本访问。
使用 Python、Dash 和 Moviepy 制作您自己的视频编辑器应用程序!
...以及如何处理 Dash 应用中的大型用户输入文件

Plotly 的 Dash 框架是一个很棒的 Python 库,无需编写 HTML 或 JavaScript 就可以快速轻松地制作交互式 web 应用程序! Moviepy 是一个优秀的以编程方式编辑视频文件的库。然而,开箱即用的 Dash 受到浏览器存储限制,这使得处理存储密集型视频文件变得困难。本文将介绍我们如何使用 np-8 的 Dash-uploader 库来绕过大约 100 MB–200 MB 的浏览器存储限制,这将打开 Dash 应用程序,直到非常大的用户输入文件(视频或数据)。我们还将涉及到dity view 的[ServerSideOutput](https://github.com/thedirtyfew/dash-extensions/)(dash-extensions 的一部分),它允许在服务器上轻松存储数据。你可以查看一下这个 GitHub 库,它包含了 3 个 Dash 应用程序文件,我将在下面一一介绍。
存储问题...举例来说
好了,先说一些数据吧!我编写了一个脚本(st_make_data.py),它创建了一个类似 json 格式的文件,模拟从微控制器串行传来的传感器数据。数据只是正弦和余弦曲线。我用它制作了几个行数逐渐增加的文件(10k、100k、1m、& 5m 行),对应于大约 0.8MB、8MB、82MB、& 409MB 的文件大小。
这里我们有一个简单的 Dash 应用程序(user_large_data_sql.py),它接收数据,解析数据并绘制数据(允许用户为每个轴选择数据)。上传数据有两个选项:标准 Dash dcc.Store对象和 Dash-uploader du.Upload对象(它也使用自己的 dcc)。存储对象以旧文件名)。
这个的回调有点特殊。它检查上下文以查看哪个上传对象被触发。如果标准的 upload 对象被触发,它将解析 base64 对象并从文件中收集行,就像处理小数据一样。最终,这个回调只是启用一个按钮来处理数据,但是这就是我们在处理较大文件时遇到麻烦的地方。

较小的文件通过 dcc 工作。上传组件,但最大的文件通过回调错误
dash-上传者来拯救!
下一个回调执行处理(按下Process Data按钮后)。它处理来自dcc.Upload 组件的base64数据,或者在服务器上打开文件,如果它是通过 Dash-uploader 组件来的话。然后,我们创建一个 sqlite 引擎,并将处理过的 dataframe 数据写入其中。
当文件通过 Dash-uploader 对象上传时,即使最大的文件也能正常工作!唯一的问题是策划。在绘图回调中,我将绘图的总行数限制为 200k,以免浏览器过载。如果需要的话,这可以通过重采样(对于绘图)来处理,但是对于这个例子来说似乎有点多。
简单的服务器端数据存储
在最后一个例子中,我创建了临时数据库文件来存储服务器上的大量数据。来自 Dash-Extensions 库的ServerSideOutput丰富使得在服务器上存储数据更加简单。我们不需要读写文件(也不需要保存文件名),我们只需要在回调中将对象发送回去。在这种情况下,它是经过处理的数据帧。需要注意的关键是装饰器顶部的特殊ServersideOutput(),我们只是在返回语句中传递了df。user_large_data_cache.py文件使用服务器端缓存。
Python Web 应用程序视频编辑器
现在,在 web 应用程序中编写一个成熟的视频编辑器是不现实的。但是对于不了解媒体编辑的用户来说,自动完成一些简单的任务会很有帮助。给视频添加公司标志或一些文字。或者拍一部延时电影。也许转换格式和缩小添加到演示文稿。团队可以使用许多相对简单的固定编辑方案。
有了大文件上传功能,我们现在可以将用户的视频文件上传到服务器上进行处理。Moviepy 有很多功能。我们将浏览的示例应用程序几乎不会涉及它能做什么。

使用最基本的视频编辑器
我使用Dash-bootstrap-components来帮助布局和造型。du.Upload是 dash-uploader 组件,用于大文件上传。然后我添加几个dbc.FormGroups来存放用户输入。当组合多个 Dash 应用程序时,全局变量APP_ID保持组件名称的唯一性。这里不需要,只是习惯。我利用 Moviepy TextClip.list(‘font’)方法获取系统可用的字体,并在初始加载时填充下拉菜单。最后,我有 2 个 Div 元素用于发送图像预览(最终电影的第一帧)和视频预览。
至于回调,首先是 dash-uploader 回调,它将本地文件名链接到 dcc。存储组件。另一个回调检查上传视频的持续时间,并填充Subclip End (s) 和Video Width (px)用户输入。这些可能会被用户忽略,但是知道限制是很好的。
主要的两个回调用于创建预览帧和预览(和最终)视频。对于预览图像,我基本上应用了所有的视频编辑,但不是将蒙版附加到剪辑上,而是在将数组发送到 PIL 之前使用 numpy 函数应用蒙版。PIL 用于将图像数据写入缓冲区,然后编码为 base64 字符串,这样图像数据就可以直接嵌入,而不必处理磁盘上的文件。
创建预览图像的回调
视频预览回调也创建全尺寸电影,并返回链接信息和启用下载按钮。这可能应该是分开的,因为你必须等到预览和最终视频都创建后才能预览。作业!
现在我设置我的 Dash 文件有点不同。我将所有的回调封装在一个add_dash()函数中,该函数接受 Dash app 对象并在被调用时附加回调。这有助于将多个 Dash 应用程序集成在一起。请参阅本文了解更多信息:
[## 使用 Microsoft Authenticatio 在 Flask 中嵌入多个 Dash 应用程序
唷!一次旅程(通过示例)让所有部分走到一起,为多个 Dash 应用程序构建一个可扩展的模板…
towardsdatascience.com](/embed-multiple-dash-apps-in-flask-with-microsoft-authenticatio-44b734f74532)
有了这个设置,我在if __name == ‘__main__’语句中完成了所有的配置。
嗯,就是这样。我希望您发现这很有用,并帮助您解决大用户文件的问题。感谢阅读!
让你的熊猫数据帧输出报告准备就绪

熊猫风格和迷你图片库说明
作为一名使用 Python 作为主要编程语言的数据科学家或分析师,我相信您一定经常使用 Pandas。我们经常在笔记本上输出熊猫数据帧。
然而,你有没有想过我们实际上可以让数据框架自己可视化?换句话说,对于一些简单的可视化目的,我们不需要 Matplotlib 或其他可视化库。Pandas 数据框输出可以像 Excel 电子表格一样可视化,具有复杂的样式和非常简单的代码定义。
在本文中,我将介绍 Pandas 库中的样式包,相对于它的数据处理方法,知道它的人相对较少。此外,还有一些有趣的库支持熊猫数据框的更多内联可视化。在最后一节中,我还将介绍其中的一种——迷你图。
关于熊猫风格套餐

众所周知,熊猫数据帧可以在 iPython/Jupyter notebook 中输出,该 notebook 以 HTML 格式自动呈现 CSS 样式。这绝对是一个惊人的特性,因为即使我们只是简单地打印它,演示也非常好。
但是等等,它使用了“HTML + CSS”。是的,熊猫也允许我们定制 CSS 样式,使它看起来更漂亮。这是通过“样式”API 实现的。
[## 风格-熊猫 1.1.2 文档
编辑描述
pandas.pydata.org](https://pandas.pydata.org/docs/reference/style.html)
我们可以简单地调用df.style来获取一个数据框的Styler对象,然后添加我们想要的样式。现在,让我们看看我们能做些什么。
格式化输出

当然,我们总是可以格式化数据本身,比如df.round(2),用两位小数来舍入所有的数值。然而,使用熊猫风格有一些好处。例如,我们实际上并不改变值,而只是改变表示,这样我们就不会失去精度。
让我们先创建一个随机数据框。
import numpy as np
import pandas as pddf = pd.DataFrame(np.random.randn(10, 2)*100)

然后,让我们输出特定格式的数据帧。
df.style.format("{:.2f}")

顺便说一句,如果你不太熟悉 Python 格式规范 Mini-Language,这是我使用的表达式{:.2f},你可以在这里查看官方文档(强烈推荐)。
[## 格式规范迷你语言- Python 文档
内置的 string 类提供了通过方法…进行复杂的变量替换和值格式化的能力
docs.python.org](https://docs.python.org/3/library/string.html#formatspec)
用背景和文本颜色突出显示单元格

我知道,格式化不够酷。使用 CSS 我们可以很容易地做很多事情,比如改变背景颜色和文本颜色。
例如,对于上图所示的同一数据框,我们希望分别突出显示正数和自然数。如果你有一些关于 CSS 的基本知识,或者只是简单地谷歌一下,你会知道下面的属性来设置 HTML 表格单元格的背景颜色和文本颜色。
background-color: red; color: white
让我们写一个函数来给表格单元格着色。
def highlight_number(row):
return [
'background-color: red; color: white' if cell <= 0
else 'background-color: green; color: white'
for cell in row
]
如果单元格的值是负数,我们使用红色作为背景,否则使用绿色,如果它是正数。因为颜色可能有点暗,我们也想把文本颜色改为白色。
然后,我们可以将该函数应用于数据框。
df.style.apply(highlight_number)

超级爽!现在很明显,我们得到了负数和正数,它们是很好区分的。
链接样式功能

图片由 Pixabay 上的 TanteTati 拍摄
到目前为止,我们每次只添加一种类型的样式。事实上,一旦我们调用了df.style,它就会返回数据帧的Styler对象。Styler对象支持链接样式函数。让我们看看另一个更复杂的例子。
比方说,我们想在原始数据框中添加以下样式。
- 用红色突出显示负数,用绿色突出显示正数。
- 将数字格式化为货币。
- 使用
set_caption()为表格添加标题。 - 增大单元格边距,使其看起来不那么拥挤。
- 在单元格之间添加白色边框以改善显示效果。
是的,我们可以一次完成所有这些,通过使用链式表达式。
df.style \
.apply(highlight_number) \
.format('${0:,.2f}') \
.set_caption('A Sample Table') \
.set_properties(padding="20px", border='2px solid white')

感觉表格可以直接用在一些业务报表上:)
内置高亮显示功能

由 PublicDomainPictures 在 Pixbay 上拍摄的照片
不懂 CSS,还想显摆?可以,熊猫 style 还提供了一些内置功能,很酷但是非常好用。
突出显示功能
让我们使用相同的数据框进行演示。
# Make a nan value for demo purposes
df.at[1, 1] = None# Add styles
df.style \
.highlight_null('lightgray') \
.highlight_max(color='lightgreen') \
.highlight_min(color='pink')

你看,用你喜欢的颜色来突出显示空值、最小值和最大值是非常容易的。我建议使用浅色,因为文本颜色总是黑色。
渐变彩色背景
熊猫风格也支持使用**cmap**给单元格背景涂上渐变颜色。当我们想要可视化刻度中的数字数据时,这非常有用。
df = pd.DataFrame(np.random.randn(10, 2))
df.style \
.background_gradient(cmap='Blues')

所以,背景颜色是渐变的,取决于值。请注意,“蓝调”是熊猫支持的cmap之一。如果您想知道还有哪些支持,下面的 Matplotlib 文档是一个很好的参考。
[## 在 Matplotlib - Matplotlib 3.1.0 文档中选择色彩映射表
Matplotlib 有许多内置的色彩映射表,可以通过。还有外部库,如[palettable]和…
matplotlib.org](https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html#sequential)
内嵌条形图
这是另一个内置的超酷功能。它可以在每个单元格的背景中生成条形来指示它们的值。我们用上面的数据框。
df.style.bar()

当然,我们对条形图的默认样式并不满意。让我们改进演示文稿。
df.style \
.format('{:.2f}') \
.bar(align='mid', color=['#FCC0CB', '#90EE90']) \
.set_caption('A Sample Table with Bar Chart') \
.set_properties(padding="15px", border='2px solid white', width='300px')

你能相信这还是你曾经非常熟悉的“熊猫数据框”吗?😃
让我简单解释一下bar()方法中的参数。color参数支持单个字符串或一个元组,当它是一个元组时,第一种颜色将用于着色负值,第二种颜色用于着色正值。因为我们使用了两种颜色,所以我们需要将滚动条设置为在单元格的中间对齐。
迷你图-内嵌直方图

照片由 Myriams-Fotos 在 Pixabay 上拍摄
我可以停在这里,但我想展示一下我发现的另一个非常有趣的库,叫做迷你图。我不会说它很好看,但这个想法真的很酷。
你可以使用pip来安装这个库。
pip install sparklines
然后,让我们导入库并创建另一个示例数据框用于演示目的。
from sparklines import sparklinesdf = pd.DataFrame({
'a': np.random.normal(0, 1, 100),
'b': np.random.normal(1, 1, 100),
'c': np.random.normal(0, 3, 100)
})

库迷你图的功能很简单。它可以使用 Unicode 字符串生成条形图,比如▁、▂、▃,直到█.为了确保条形的顺序正确,并且作为直方图有意义,我们需要首先使用 NumPy 准备值以生成直方图值。
def sparkline_dist(data):
hist = np.histogram(data, bins=10)[0]
dist_strings = ''.join(sparklines(hist))
return dist_strings
对于每一列,我们可以使用迷你图生成直方图。
[sparkline_dist(df[col]) for col in df.columns]

最后,我们可以将字符串与其他统计数据放在一起,以生成更好的报告。
df_stats = df.agg(['mean', 'std']).transpose()
df_stats['histogram'] = sl_list
df_stats.style \
.format('{:.2f}', subset=['mean', 'std']) \
.set_caption('A Sample Table with Sparklines Distributions') \
.set_properties(padding="15px", border='2px solid white')

搞定了。
摘要

在本文中,我向您展示了熊猫风格包中的所有主要方法。我们可以设置值的格式,给背景上色,用定制的 CSS 属性来改善表现。还有许多内置函数可用于创建“报表就绪”数据框输出。
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@qiuyujx/membership)
如果你觉得我的文章有帮助,请考虑加入灵媒会员来支持我和成千上万的其他作家!(点击上面的链接)
让你的 Python 代码流畅
函数和运算符重载

诺兰·马尔克蒂在 Unsplash 上的照片
Python 中的重载允许我们定义函数和操作符,它们根据所使用的参数或操作数以不同的方式运行。
运算符重载
作为一个例子,我们可以使用 "+"操作符对数值进行算术计算,而当使用字符串操作数时,同一个 "+"操作符连接两个字符串。这被称为操作符重载,它允许我们在不同的对象类型上使用相同的操作符来执行类似的任务。
如下所示,我们可以重载 "+"操作符来使用我们定制的对象类型。
**# No overloading, task is performed by 'add' method**
cost1 = Cost(10)
cost2 = Cost(24)
cost_total = cost1.add(cost2)**# '+' operator is overloaded to work with 'Cost' type of objects**
cost1 = Cost(10)
cost2 = Cost(24)
cost_total = cost1 + cost2
与第一个代码块相比,上面的第二个代码块更容易阅读和理解。这就是重载如何使我们的代码流畅和干净。
函数重载
虽然 Python 默认情况下不支持函数重载,但是有一些技巧可以实现它。
假设我们想创建一个函数来计算三角形的面积。用户可以提供;
- 三角形的底和高,
- 三角形三条边的长度
如果不考虑重载,我们需要定义两个不同的函数来处理这个任务。
我们可以只编写一个函数并重载它来增加代码的一致性和可读性,而不是为同一个任务定义不同的函数。
**#---------------------
# No overloading, task is performed by two similar functions
#---------------------** def **triangle_area_base_height(base, height)**:
....
def **triangle_area_three_sides(a_side, b_side, c_side):**
....**area1 = triangle_area_base_height (10,14)
area2 = triangle_area_three_sides (10, 12,8)****#---------------------
# Function overloading
#---------------------** **from** multipledispatch **import** dispatch@dispatch(int,int)
def **triangle_area****(base, heigth):**
.....@dispatch(int,int,int)
def **triangle_area****(****a_side, b_side, c_side****):**
.....**area1 = triangle_area (10,14)
area2 = triangle_area (10,12,8)**
重载运算符
当我们使用一个操作符时,会调用一个与该操作符相关的特殊函数。举个例子,当我们使用 +操作符时,会调用 add 的特殊方法。要重载+ operator,我们需要在一个类结构中扩展 add 方法的功能。
**# Addition of 2D point coordinates with
# + operator overloading****class** Point2D:
**def** __init__(self, x, y):
self.x **=** x
self.y **=** y# adding two points
**def****__add__(self, other):**
**return** self.x **+** other.x, self.y **+** other.y**def** __str__(self):
**return** self.x, self.ypoint1 **=** Point2D(5, 4)
point2 **=** Point2D(6, 1)
point3 **=** point1 **+** point2**print**(point3)**Output:** (11, 5)
我们可以重载 + operator 来拥有更加流畅和易读的代码,而不是定义一个额外的函数来添加 Point2d objects 。
通过修改类结构中相关的特殊方法,可以重载所有操作符,包括赋值、比较和二元操作符。
重载内置函数
我们还可以重载内置的 Python 函数来修改它们的默认动作。考虑 len() 内置函数,它返回序列或集合中对象的数量。为了将它与我们定制的对象类型一起使用,我们需要实现重载。
为了重载 len() ,我们需要在一个类结构中扩展 len 方法的功能。
下面让我们看看如何用 Python 来实现:
class **Names**:def **__init__**(self, name, country):
self.name = list(name)
self.country = countrydef **__len__**(self):
return len(self.name)obj1 = Names(['Amy', 'Harper', 'James'], 'UK')
print(len(obj1))**Output:** 3
同样,您可以重载所有内置函数。

重载用户定义的函数
Python 默认不支持函数重载。但是我们可以使用多个分派库来处理重载。
导入 multipledispatch,我们需要做的就是用 @dispatch() decorator 来修饰我们的函数。
**import math
from multipledispatch import dispatch**@dispatch(int,int)
def **triangle_area(base, height)**:
return (base*height)/2@dispatch(int,int,int)
def **triangle_area(a_side, b_side, c_side)**:
s = (a_side + b_side + c_side) / 2
return math.sqrt(s * (s-a_side) * (s-b_side) * (s-c_side))area1 = triangle_area (10,14)
area2 = triangle_area (5,5,5)print("Area1: {}".format(area1))
print("Area2: {}".format(area2))**Output:**
Area1: 70.0
Area2: 10.825317547305483
关键要点
- Python 中的重载允许我们根据所使用的参数或操作数来定义行为不同的函数和操作符。
- 操作符重载允许我们在不同的对象类型上使用相同的操作符来执行相似的任务。
- 我们可以只编写一个函数并重载它来增加代码的一致性和可读性,而不是为同一个任务定义不同的函数。
结论
在这篇文章中,我解释了 Python 中重载的基础知识。
这篇文章中的代码可以在我的 GitHub 库中找到。
我希望这篇文章对你有用。
感谢您的阅读!
让您的 Python 函数速度提高 10 倍
学习使用[ElementwiseKernel](https://docs-cupy.chainer.org/en/stable/tutorial/kernel.html) API 在 GPU 上用 CUDA 加速你的 python 代码,加速你的 NumPy 代码!

照片由 chuttersnap 在 Unsplash 上拍摄
他的帖子对我来说非常特别,因为它包含了我在准备 2020 年谷歌代码之夏(未选)时学到的东西。
动机
CuPy 提供了一个名为ElementwiseKernel的 API 来并行化 GPU 上的操作。
下面是 之前和之后部分, 比较了相同任务(计算两个数组的元素态平方差)在不使用元素态内核和在相同大小的数组上使用元素态内核时的运行时间。在这里说不太通也没关系。我们继续下去的时候,我会详细解释的。
之前(不使用 elementwise 内核)

之后(使用元素式内核)

你看,两种情况下数组大小都是 100 万。下面是提速对比。

~40304 倍快😳。等等,标题上说只有 10x。实际上,这是一个非常简单的任务。在真实的场景中,操作不会这么简单。这将导致加速损失。因此,您可以预期它的运行速度比普通方法快 10 到 100 倍,唯一的条件是您的任务应该是可并行的。
关于 CuPy

CuPy 是由 CUDA 加速的 NumPy 兼容矩阵库。这意味着你可以使用 CuPy 在 GPU 上运行几乎所有的 Numpy 函数。numpy.array会变成cupy.array,numpy.arange会变成cupy.arange。就这么简单。签名、参数、输出一切都与 Numpy 相同。唯一的关键区别是 python 列表的对象不能直接传递给任何 CuPy 函数。我们只能通过一个cupy.ndarray的对象。而且就像 NumPy 一样,我们可以用cupy.array(arr)创建一个cupy.ndarray的对象。下图表示 CuPy 在 NumPy 上的加速,紫色条表示 CuPy 调用(数组大小为 800 MB),蓝色条表示 NumPy 调用(数组大小为 8 MB)。

您可以在这个 colab 笔记本中运行和测试加速(您可以简单地编辑最后两个单元格来运行和检查您选择的 NumPy 函数的加速)。
这是关于现有的 NumPy 函数。但是在现实生活中,有些情况下我们需要自己编写函数。这些函数在处理大型数据集时需要很长时间。以下是如何在 GPU 上并行化代码以元素方式运行的方法。这也是它快速运行的条件,你的代码应该是可并行的。例如,按元素添加两个数组是可并行化的,但对数组元素求和却不是。而对多维数组的特定维度求和可以并行化。
元素式内核
Elementwise 内核是 CUDA 和 CuPy 之间的桥梁。他们从 CuPy 获取有关操作和并行化的信息,并以“哪些操作将在 GPU 上并行执行以及如何执行”的形式通知 CUDA。我们将使用自顶向下的方法,而不是先浏览 Elementwise 内核的细节,然后再看一个例子,我们将通过几个例子来尝试理解 Elementwise 内核的内部工作。
注意:我已经在代码注释中解释了大部分重要的东西,我建议阅读所有即将到来的代码片段的注释。
elementwise 内核的定义由四部分组成:输入参数列表、输出参数列表、循环体代码(CUDA-C/C++)和内核名称。例如,按元素计算两个数组的平方差的内核 f(x,y)=(x y)定义和调用如下(x和y是两个数组):

很奇怪,不是吗?循环体不包含循环。原因是循环体代码运行在x和y的元素上,我们不需要迭代循环或显式索引它们。如果数组大小不同,较短的数组将被广播成较大数组的形状。如下所述,

但是如果不可能广播它以使它们具有相同的大小,内核将会产生一个错误。你可以在这里了解更多关于广播的规则。
通用内核
编程中的术语 Generic 指的是被编写为具有类型(稍后指定)功能的编程算法。因此,通用内核是在定义内核时,我们不想指定输入输出参数的数据类型的内核。我们需要为每个唯一的数据类型使用一个字符,就像我们在 Java 中做的那样。参见下面的例子,

原始参数(内核内部的索引)
如果我们想索引其中一个参数,该怎么办?🤔原始论据就是答案。您指定为raw的参数将必须像我们在普通数组中一样进行索引。参见下面的例子,

标量参数
传递标量参数并在内核中使用这些标量几乎和我们在普通函数中做的一样简单。你只需要传递一个标量而不是一个数组,然后像我们通常做的那样使用它。举个例子,

您还可以将输出参数传递给内核。输出参数将通过引用自动传递。在这种情况下,不会返回输出。举个例子,

试一试
这个 colab 笔记本包含了上面提到的所有例子。人们可以去那里尝试一些东西。您可能还想调整一些东西,看看输出的反映。
注意:上面所有的例子都非常简单,因此只包含一行循环代码。在现实场景中,循环体可能包含更多的 CUDA-C/C++代码行。
为了让你了解它在现实世界中是如何使用的,下面是我给 CuPy 的 pr 列表,其中我使用了ElementwiseKernel。
结论
还有很多东西需要挖掘。比如ufuncs、reduction kernels等东西。是 CuPy 最有用的功能之一。甚至 Numba 库的gufunc创建 API 也使得在 GPU 上运行复杂函数变得容易得多。但是我认为这对于这篇文章来说已经足够了。我将会相应地在将来发布其他的东西。
改头换面星期一:权力的游戏版
以 GoT 为主题的现代简约风格仪表盘。

我的仪表板片段
大卫·墨菲的以《权力的游戏》为主题的仪表盘(如下图)是一个不可思议的成就。墨菲煞费苦心地收集了所有屏幕上的死亡数据,并创建了一个仪表盘,将他的个性和品牌与《权力的游戏》系列的设计元素结合在一起。

原始仪表板的片段
注:该数据集和原始仪表板来自 2019 年第 27 周周一的 改头换面 。
在这篇博文中,我将向你介绍我在重新设计大卫·墨菲的仪表盘时所做的设计决定。但是首先,让我们回顾一下源数据背后的一些背景。
数据

(计划或理论的)纲要
正如我前面提到的,这些数据是由原作者收集的。这显然容易犯些小错误,而且带有主观因素,比如效忠(例如,自从乔拉·莫尔蒙在整个系列中为丹妮莉丝·坦格利安效力以来,他效忠的是莫尔蒙家族还是坦格利安家族?).无论如何,对于像我这样的数据发烧友来说,这是一个宝库。
这里有一些关于数据你应该知道的有用的花絮…
- 只有银幕上的杀戮才算数。
- 不死生物不在考虑之列。
- 动物算武器。
现在这个问题已经解决了,让我们来谈谈仪表板改造。
重新设计考虑因素
原始仪表板
墨菲的仪表板做了很多事情非常好。事实上,我保留了不少他创作的可视化作品。具体来说,我喜欢他对条形图、连续杀人计数和剧集分解的使用(所有这些都在下面突出显示)。

我一直用黄色突出显示的元素。
我喜欢他的仪表板有 GoT 主题的元素,比如滚动的标题、字体和角色的图片。在我的仪表板中,我选择删除这些元素,因为我希望我的仪表板感觉更现代和简约。
我还强烈地感觉到,在向用户展示分类数据方面,树形图和条形图比打包的气泡图(在“Top Methods”一节中使用)做得好得多。此外,我希望我的仪表板能够回答更多关于该系列的问题,如房屋如何相互比较,哪些方法被使用最多,以及哪个房屋被杀害最多。
我重新设计的主要目标可以用下面的问题陈述来总结:在一个更干净、更清爽的仪表盘中,我如何更好地理解角色和英雄之间的差异和趋势?
就捕获的要素数量而言,数据集非常有限,但仍可提供大量信息。让我们来看看重新设计的仪表板可以回答的所有问题…
这些问题
我的仪表板分为三个部分,每个部分回答不同种类的问题…
第一部:人物聚光灯
- 对于一个给定的角色,他们最常用的方法是什么?他们在哪里杀得最多?
- 他们在一季或一集里杀了多少人?
- 对于同一个角色,他们抵押房子最常用的方法是什么?
- 这个角色的方法和他/她抵押房子的方法相比如何?
第二部分:总计
- 哪个房子杀人最多?(整体或特定季节。)
- 哪个房子被杀的最多?(整体或特定季节。)
- 哪些方法用的最多?(整体或特定季节。)
- 哪些地方的死亡人数最多?(整体或特定季节。)
第三部分:房屋聚光灯
- 对于一个给定的房子,在不同的季节或不同的剧集中,它们的趋势与其他房子相比如何?
- 在这个系列的所有剧集中,豪斯医生的杀戮是如何分布的?
- 在特定的一季或一集里,哪个房子杀的人最多?
改造

总的来说,新的仪表板去掉了所有额外的 GoT 主题设计元素,看起来应该更整洁。还有很多可视化,所以肯定更复杂更密集,但是可以回答很多问题。
还有一些观众可以修改的可调参数(季/集视图和特定的房子),一些可视化更便于比较(房子与房子比较的折线图或人物与房子比较的项目符号图)。
我也非常喜欢摘要瓦片(第 2 部分:总体总计),因为它们可以快速简洁地传递重要信息。
最后,在格式方面,我喜欢颜色协调的工具提示和标题,它们突出了每个可视化的动态方面。例如,栗色中的所有文本都会根据您的参数选择而变化。此外,如果将鼠标悬停在每个可视化对象上,将使用相同的栗色高亮显示方法。
结论
我不声称我的仪表板比原来的更好或更差。改头换面星期一是关于个人喜好,来自他人的灵感和创造力。
最后,大声喊出来,谢谢大卫·墨菲的灵感和数据来源。
使用 Plotly 制作条形图比赛图——变得简单

在 Unsplash 上 Serena Repice Lentini 的照片
你见过这些随着时间的推移对事物或人进行排名的赛车条形图吗?他们越来越受欢迎,他们看起来很有趣,他们可以看到谁或什么随着时间的推移在某个排名中名列前茅。你可能已经看过 2020 年根据 COVID19 案例进行的国家排名,或者从洛克斐勒到杰夫·贝索斯的最富有的人的排名。无论你的排名如何,今天你将学习如何使用 Python 和 Plotly 制作你自己的赛车图!—也提供包装:)
1995 年至 2019 年间全球 10 大富豪
一段时间内 COVID 病例最多的国家 19
致谢
- 阿曼达·伊格莱西亚斯·莫雷诺在 2017 年写了一篇中期文章,讲述了巴塞罗那顶级婴儿名字的条形图比赛情节。我从那篇文章中学到了很多,我在这篇文章中的意图是使用我从她的文章和其他资源中学到的东西来编写可用于任何特定用例的代码。
- 本教程提供了制作动画 Gapminder 散点图的所有代码。虽然这个例子非常丰富,但是几乎没有解释任何代码。我写这篇文章是为了帮助其他人理解所有这些诡秘的论点意味着什么。当我使用“奇怪的”情节性参数时,我会在代码注释中用简单的术语解释它们的作用。
TL;博士
如果你对如何制作这种图表不感兴趣,我已经为你写了一个包,让你轻松地绘制你自己的数据。使用pip简单安装以下软件包
pip install raceplotly
然后在一个python脚本中运行以下内容:
您将获得 1961 年至 2018 年间产量最高的 10 种作物的时间表(见下文)。我从粮农组织获得数据。
如果您发现任何问题,请向[raceplotly](https://github.com/lc5415/raceplotly) 库提交问题,如果您想提供改进,请向 PRs 提交问题!
龙(呃)解释
对于那些留在这里的人,谢谢。我会尽可能简洁地让你明白如何建立一个这样的情节并超越它。
情节性基础
许多 Plotly 新用户第一次接触到plotly.express库。在这个库中,Plotly 开发人员去除了 Plotly 图形的复杂性,使其更加用户友好。尽管每当一个人想要超越plotly.express的能力时,就有必要看看在引擎盖下发生了什么。
首先要知道的是,所有 Plotly 图形都包含 3 个主要元素:数据、布局、和帧。
- 数据元素是一个 python 列表,包含关于您想要绘制的绘图类型的信息:散点图、条形图、漏斗图、热图、choropleth…以及此类绘图的相关参数:x、y、z、颜色、大小…
- 布局元素是一个 python 字典,包含关于绘图外观的信息,即图形的属性(标题、大小、图例、背景色……)、轴的属性(标题、颜色、刻度……),以及关于图形的交互属性(按钮、滑块、当用户点击或悬停在图形上时显示的内容和位置)。此外,还有许多参数用来调整每一种图形(特别是条形图,特别是漏斗图……)。
- 帧元素允许用户制作动画情节。帧是一个 python 列表包含了每一个要按顺序渲染的帧。
如果您想了解更多细节,请参考官方的 Plotly 基础指南,了解其图形数据结构和/或核心 Plotly 图形的文档。
与许多其他绘图库一样,Plotly 提供了大量的参数来修改绘图。虽然这在你希望完善一个情节时很有用,但它也可能是压倒性的,尤其是在开始或原型制作时。 现在让我们探索一下如何用 python 写一个 Plotly figure 来生成如上图的种族栏图。
从头开始编写种族栏剧情图
正如在 Plotly 基础中提到的,在 python 中,一个 Plotly 图形可以是一个字典或者一个plotly.graph_objects.Figure实例。我个人不喜欢其中一个,我喜欢先创建一个实例,然后再访问。我们将逐个元素地创建 Plotly 图形,首先是数据,然后是布局,然后是框架,当然,您可以在一个块中完成所有这些。
我们将首先加载我们的数据(我从粮农组织下载的数据):
下载粮农组织数据
注意: 如果您使用的是自定义数据集,请确保它有 3 列:一列对应于您正在排序的项目(本教程中的 项目) ,一列对应于您正在排序的值(本教程中的 值 ),另一列对应于每个对应的项目-值对的年份或日期(本教程中的 年份 )
现在让我们实例化我们的图形:
import plotly.graph_objects as go
fig = {
"data": [],
"layout": {},
"frames": []
}
接下来,让我们定义数据元素。正如我们之前所说,这必须是一个 python 列表,其中包含我们希望绘制的绘图类型(在本例中为条形图)以及与每个轴对应的数据框的相应列。在我们的例子中,我们正在构建一个动画,我们为默认图形选择的数据将对应于动画开始前显示的数据切片。在这里,我选择了最早的数据(从 1961 年开始)作为默认框架。
我们还需要一个颜色的每一个项目,我们正在排名。阿曼达·伊格莱西亚斯·莫雷诺在她的 2017 帖子中,写了一个函数来为每个类别分配一个 RGB 三元组。使用列表理解,我们可以在一行中做到这一点(参见下面的代码)。
填充绘图图形数据条目
注: 要了解texttemplate的功能,请参考 Plotly 文档
现在让我们继续填充布局。我在这里的默认选择是使用白色背景,y 轴上没有轴信息(对应于项目名称),因为我们已经显示了带有文本注释的信息。此外,我决定显示 x 轴刻度及其相应的值,并将 x 轴设置为一个固定值(等于表中的最大值)。
初始化默认框架的布局
因为我们正在创建一个动画情节,所以我们必须在布局中包含两个额外的条目:更新按钮(播放和暂停)和滑块。我们暂时将滑块留空,因为我们将在创建框架时填充一个滑块字典。Plotly 提供了一个名为[updatemenus](https://plotly.com/python/reference/layout/updatemenus/#layout-updatemenus-buttons-method)的布局属性,允许我们创建按钮、下拉菜单、更新布局和控制动画。
添加播放和暂停按钮
注:过渡持续时间对应于帧过渡所需的时间。低值将使过渡非常快,就像切换图片,而长值将使它更像一个视频。帧持续时间控制每帧显示多长时间。
最后,我们将创建对应于每年前 10 名的帧。在这一步,我们还填充布局的滑块属性。这样做是为了使每一帧都链接到滑块中的一个位置。首先,我们用滑块元信息和一个空的steps列表初始化一个字典:
接下来,我们制作框架并生成步骤:
最后,在所有这些艰苦的工作之后,你可以简单地运行go.Figure(fig)来展示你来之不易的数字。
结论
- 我们需要大量的代码来生成条形图比赛图。移动代码是痛苦的,如果你打算经常使用的话,我鼓励你使用!
- 我应该指出的一点是,我们的杆在相互超越时不会滑过对方。我无法用 Plotly 实现这一点, Ted Petrou 使用
[matplotlib](https://medium.com/dunder-data/create-a-bar-chart-race-animation-in-python-with-matplotlib-477ed1590096)设法做到了这一点,所以看看他吧!
如果你已经做到了这一步,我希望你已经发现这是有用的。如果你对自己的情节有任何具体问题,请随时联系。
PS: 我一定要把你指向兴旺 app 获得无代码的快乐
为开源数据科学做一个案例(OSDS)

开源软件改变了我们的生活。但是开源数据科学在哪里?我们为什么要关心?

暴风突击队合作。照片由将放在的 Unsplash 上
答:几乎我们所有人都将开源软件作为生活的一部分。合作创建公共软件已经改变了软件开发的世界和整个世界。但是我们在数据科学领域没有看到同样的行为。开源数据科学(OSDS)在哪里?
在宣称开源数据科学有意义之前,我们先来解释一下为什么开源软件有意义。
开源软件的案例
许多人认为 OSS 的好处是显而易见的,大多数开发者和软件公司都与开源社区有某种关系。但并不总是这样。
开源软件的(真正的)简史

很久以前,在一个遥远的星系里。张家瑜在 Unsplash 上的照片
在一开始(20 世纪 50-60 年代),几乎所有的软件都是开源的。它是由研究人员和学者创建的,他们本着科学的精神与社区分享它。
但是甚至在更晚的时候,当像 IBM 这样的公司卖出他们的第一台电脑时,软件与源代码一起被分发,以使“黑客”能够修复错误并创造改进。
到 20 世纪 60 年代末,封闭软件逐渐成为一种标准,与硬件相比,软件的价格大幅上涨。像许多其他的技术转变一样,始于对 IBM 的反垄断诉讼,其结论是捆绑软件是反竞争的。几年后,在 1974 年的,美国认为软件是可以被版权保护的,由此开始了封闭源代码软件的时代(和商业模式)。
尽管开源从来没有消失过(例如像 TeX 这样的项目),但它经历了一次复兴,始于 1983 年的 GNU 项目,但只是在 20 世纪 90 年代后期才显著显现,出现了像 Linux 和 Git 这样的项目(由同一个人——Linus Torvalds)以及最终的 GitHub。
为什么不总是显而易见
有一句关于维基百科的名言同样适用于开源:
“维基百科的问题在于它只在实践中有效。理论上,这是一场彻底的灾难”——加雷斯·欧文
在开源软件(OSS)的早期,有一种强烈的说法认为软件公司永远不会共享他们的源代码,因为这是他们的知识产权——他们最有价值的财富,把它交给竞争对手没有任何意义。
闭源软件有它的优势——它往往有更好的支持,更丰富的特性集,并且有时更加用户友好。事实上,公司有他们想要保护的知识产权,而且开源软件如何适应开发者或公司的商业模式并不总是清楚的。换句话说,它有时会增加赚钱的难度。
另一方面…
开放源码软件的好处

新的希望。照片由 Xenomurphy 在visual hunt/CC BY-NC-ND
今天,OSS 的许多好处是显而易见的:
- 透明和自由——使用 OSS 意味着你不会被一个供应商所束缚,并且可以很容易地理解你所使用的工具的内部工作原理
- 可靠性和安全性——当有成千上万只眼睛检查您的代码时,识别 bug 和安全风险要容易得多
- 更快的上市时间——有数百名贡献者帮助进行功能开发会快得多。对于那些没有大量员工的创业公司来说尤其如此
然而,有些好处不太直观。例如,在技术行业最困难的事情之一是找到伟大的开发者,他们中的许多人都非常关心 OSS。将 OSS 整合到一个公司的产品组合中可以让开发者展示他们的能力并回馈社区。这对人才有巨大的吸引力。
当然,我们不要拐弯抹角。将一个内部项目作为开源项目发布是很好的 PR(公共关系,而不是拉式请求),特别是如果你有一个基于它的非开源产品,和/或如果你的用户是开发者。
这只是有意义的(在某些情况下)
什么时候创建开源项目最有意义?我认为我们可以将组织的“开源标准”定义如下:
当一个项目解决了公共问题并且不是你的核心产品的一部分时,开源这个项目是一个好主意(尽管这是一个经验法则,也有例外)。
作为例子,我们来看看的反应。

帝国在 React 之前设计了他们的第一个用户界面。照片由张家瑜在 Unsplash 上拍摄
React 是一个用于构建用户界面的 JavaScript 库。它是由脸书在 2013 年发布的。它有麻省理工学院的许可证,这意味着你可以用它做任何你想做的事情,包括商业项目。
现在,从产品角度分析 React,它解决了 web 开发中的一个严重问题——很难从头开始构建用户界面。很明显,这是一个非常普遍的问题,而且解决这个问题也不是 Facebook 作为一家公司的目标——他们 s̶e̶l̶l̶ ̶a̶d̶s̶建立社交网络 。
这意味着 React 是上述标准的一个例子——一个公共问题,而不是公司的核心知识产权。因此,将其作为 OSS 发布保证了脸书的所有好处,而没有太多的负面影响。
OSDS 的案例
我想现在你应该相信 OSS 是有价值的。现在,让我们来谈谈这些概念是如何转移到数据科学领域的。为了做到这一点,让我们通过给出一个遵守“开源标准”的例子——人脸识别——来描绘 OSDS 如何工作的更详细的愿景。
您可能很容易想到一些可以使用人脸识别的应用程序。对于这个例子,让我们看看在疾病诊断和时尚推荐的背景下的人脸识别。在谷歌上快速搜索一下,就会发现确实有公司在做这些事情。
在第一个用例中,患者的照片将作为医疗检查的一部分(或在家)被拍摄,然后被分析以识别可能的疾病,帮助医生优先处理紧急情况并治疗更多的人。
在第二个用例中,一个应用程序会根据你的购买历史,以及顾客的面部特征或身体结构来推荐最好的衣服。
这些公司绝对不是而是在相互竞争。它们的 IP 在于分别提供用于疾病诊断或时尚推荐的系统。然而,今天,两者很可能正在并行开发他们系统的一个关键部分——人脸识别。这意味着重复工作,浪费大量数据科学家的时间和金钱。
在 OSDS 的世界里,两家公司都将致力于一个开放的人脸检测项目,贡献代码和数据来帮助应对边缘案件,并创建一个更强大的解决方案。与当前状态相比,他们可以让更少的数据科学家来完成这项任务,让他们专注于更棘手、更关键的问题。
想要学习和展示其技能以改进其产品组合的新数据科学家将会投身于识别错误、低效并创建替代模型,从而为不同的用例区分各种指标的优先级。他们可以看到一个严肃的数据科学项目是什么样的。
最重要的是,寻找未来数据科学家的公司可以找到并联系那些已经为他们关心的项目做出贡献的人,从而缩短新团队成员的招聘和入职流程。
最近,人工智能的透明度、多样性和包容性成为科技领域的焦点。OSDS 可以在这些领域产生重大影响。举个例子,假设其中一个产品的用户,碰巧也是一名数据科学家,发现面部检测在她的图像上表现很差。她查看了数据集,发现没有她所属的某个少数民族的图像。她添加了另一个数据集中的图像来填补空白,并提交了一个拉取请求——瞧,新模型对她来说表现得更好了,公司也享受到了一个更加多样化和改进的模型。
真正的双赢局面。
当我开始写这篇文章时,这是一个理论上的例子。现在,情况已经不同了。
为了结束这篇文章,我想写两个例子来说明开源数据科学在实践中应该和不应该是什么样子。
伪装成开源数据科学的开源软件
现在,我已经能听到你的反对:“但是我从 GitHub 克隆了 tensor2tensor 和 BERT ,这已经是开源数据科学了!”或者“我在 arXiv 上读到的很多论文都在网上发布了代码”。

三位一体——代码、预训练模型和 arXiv 论文。 GitHub 上的照片
这不是对 BERT 作者的讽刺,这一部分也不是对这些项目的不尊重。这些项目非常有用,要让公众能够接触到它们需要付出很多努力。他们的作者尽他们所能给出他们所拥有的工具和行业标准。
我想说的是,他们是开放源码软件,但不是 OSDS。
如果一个这样的例子中的代码有一个 bug,这使得发布模型的 API 由于某种原因不能工作,独立的程序员通常可以以 pull 请求的形式贡献一个 bug 修复。另一方面,如果独立的数据科学家意识到数据中存在问题,比如模型对某些种族群体有偏见,在大多数情况下,他们无法修改数据集并创建改进的模型。
这导致对代码的贡献,而不是对项目的数据科学部分的贡献。换句话说,这个项目实际上变成了一个软件项目。
OSDS 还会对数据科学研究产生重要的副作用。
提高数据科学研究的质量
提高研究质量是一个值得追求的重要目标。实现这一目标的一些值得注意的努力是:
- distilt . pub—一份旨在使机器学习研究更加可访问、互动和透明的出版物
- 开放评审 —一个开放的科学交流平台,致力于使同行评审过程透明化
- arXiv —在完全同行评审之前被批准发布的论文的电子印刷库
- 代码为的论文——机器学习研究论文的在线集合,结合了它们的代码,简化了实现。
关于数据科学研究中一些最新(SOTA)成果的问题本质,已经说了很多。通常,当一篇论文发表后,你只能看到最终结果,即与之前的 SOTA 相比提高的百分比。很多时候,小的改进可能归因于随机种子的成功选择或执行许多实验,直到一个人成功地改进了一个指标,而没有充分考虑结果的统计显著性。
更简单地说,由于研究过程不透明,我们不知道一个结果实际上代表了研究的进步还是运气的侥幸。
在 OSDS 的世界里,研究团队可以发布他们的整个研究历史,同时提交论文以供审查。审稿人将能够提供高质量的反馈,并确保严谨的研究方法。每个人都将享受更高质量的数据科学研究。
最后的想法
我是 DAGsHub 的联合创始人,这是一个让数据科学家能够合作、管理和分享他们的项目的平台。在 DAGsHub,我们花大量时间思考 OSDS,并与数据科学家交谈。
本文总结了我们与社区中的数据科学家进行的一些对话。本文的目的是阐明为什么开源是今天软件开发的重要组成部分,并提出论点,即在不久的将来它将成为数据科学的重要组成部分。
下一篇文章将深入技术和技术细节——为什么创建 OSDS 社区需要不同于 OSS 社区使用的工具,困难,以及如何克服它们。有关我们解决这一挑战的方法的更多详细信息,我们邀请您访问 DAGsHub 。
如果你有机会合作一个 OSDS 项目,我很想听听你的评论(并获得一个链接,链接到你正在建设的项目)。
今天,脸书有许多其他产品,但构建用户界面不在其中。
使用全球新闻(使用 Python)通过连续 ML 预测苹果股票的出色结果
简单是关键。
目标
在本教程中,我们将制作一个机器学习管道,它输入商业新闻,并随着时间的推移为苹果股价再培训生成预测。

图片来自 apple.com
我们还将衡量它在现实生活中有多有利可图。
我们要做什么
- 步骤 1:设置技术先决条件
- 第二步:获取 2017 年以来每日苹果库存的数据
- 步骤 3:定义并理解 ML 的目标
- 第四步:将商业新闻融入我们的数据
- 第五步:准备我方数据并应用 ML
- 第六步:测量和分析结果
- 第七步:打破数据和训练/测试穿越时间
第一步。先决条件
- 安装 Python 2.6+或 3.1+版本
- 安装熊猫、sklearn 和 openblender(带 pip)
$ pip install pandas OpenBlender scikit-learn
第二步。获取数据
我们将使用这个每日苹果股票数据集

它有每天的最高价、最低价、开盘价和收盘价,以及当天的百分比变化。
所以让我们通过 OpenBlender API 拉数据。打开一个 python 脚本,运行以下代码:
# Import the librariesimport OpenBlender
import pandas as pd
import numpy as np
import jsontoken = '**YOUR_TOKEN_HERE**'# Specify the action
action = 'API_getObservationsFromDataset'interval = 60 * 60 * 24 # One dayparameters = {
'token' : token,
'id_dataset':'5d4c39d09516290b01c8307b',
'date_filter':{"start_date":"2017-01-01T06:00:00.000Z",
"end_date":"2020-02-09T06:00:00.000Z"},
'aggregate_in_time_interval' : {
'time_interval_size' : interval,
'output' : 'avg',
'empty_intervals' : 'impute'
}
}
# Pull the data into a Pandas Dataframedf = pd.read_json(json.dumps(OpenBlender.call(action, parameters)['sample']), convert_dates=False, convert_axes=False)
df.reset_index(drop=True, inplace=True)
df['date'] = [OpenBlender.unixToDate(ts, timezone = 'GMT') for ts in df.timestamp]
df = df.drop('timestamp', axis = 1)
注意:要获得您需要的令牌必须在 openblender.io (免费)上创建一个帐户,您可以在您个人资料图标的“帐户”选项卡中找到它。

现在让我们来看看数据:
df.head()

检查!
第三步。定义和理解目标
让我们画出价格和变化:

现在,我们想要的是检测第二天价格是否会在上涨或下跌,这样我们就可以买入或做空。
“变化”是开盘价和收盘价之间发生的百分比上升或下降,因此它对我们有效。

让我们将我们的目标变量定义为大于 0.5%的增长(这样就不值得购买):
阳性 POC: 其中“变化”增加超过 0.5%

“变化”的分布
这意味着绿线右侧的所有观察结果都将是我们的“成功”情景。
第四步。向量化和混合商业新闻
这是非常 简单的执行,但是让我们试着理解后台发生的事情。
我们想要的:
- 我们需要收集有用的新闻数据,这些数据与我们的目标相关
- 我们希望将它融入我们的数据中,使消息与第二天的价格“变化”保持一致(这样模型就可以学习预测第二天的价格,我们就可以实际使用它)
- 我们想把它转换成数字特征,这样它就可以遍历一个 ML 模型。
因此,让我们寻找时间重叠的商业新闻数据集:
# First we need to add the UNIX timestamp which is the number
# of seconds since 1970 on UTC, it is a very convenient
# format because it is the same in every time zone in the world!df['timestamp'] = OpenBlender.dateToUnix(df['date'],
date_format = '%d-%m-%Y %H:%M:%S',
timezone = 'GMT') # Now, let's search on OpenBlendersearch_keyword = '**business**'df = df.sort_values('timestamp').reset_index(drop = True)print('From : ' + OpenBlender.unixToDate(min(df.timestamp)))
print('Until: ' + OpenBlender.unixToDate(max(df.timestamp)))# We need to pass our timestamp column and
# search keywords as parameters.OpenBlender.searchTimeBlends(token,
df.timestamp,
search_keyword)

我们可以看到时间重叠(交叉)数据集及其一些属性,甚至可以看到界面的 url。
因此,让我们挑选这个华尔街日报新闻数据集:

这是今日美国推特新闻。

- 注意:我选择这些是因为它们有意义,但是你可以搜索数百个其他的。
我们可以通过搜索按时间聚合的新闻术语,将新的列混合到我们的数据集中。例如,我们可以用“华尔街”数据集中的新闻数量创建一个“苹果”特征,该特征与我们自制的 ngrams 相匹配:
**positive_filter** = {'name' : 'apple',
'match_ngrams': ['apple', 'iphone', 'ipad',
'tim cook', 'mac store']}# We need to pass the 'id_dataset', the name of the
# column (which is 'text') and an optional filter.blend_source = {
'id_dataset':'**5e2ef74e9516294390e810a9**',
'feature' : '**text**',
'filter_text' : **positive_filter**
}df_blend = OpenBlender.timeBlend( token = token,
anchor_ts = df.timestamp,
blend_source = blend_source,
blend_type = 'agg_in_intervals',
interval_size = 60 * 60 * 24,
direction = 'time_prior',
interval_output = 'list')df_anchor = pd.concat([df, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1)
df_anchor
timeBlend 函数的参数:
- anchor_ts :我们只需要发送我们的时间戳列,这样它就可以作为锚来混合外部数据。
- blend_source :我们想要的特性的信息。
- blend _ type:‘agg _ in _ intervals’因为我们想要对我们的每个观察值进行 24 小时间隔聚合。
- inverval_size :间隔的大小,以秒为单位(本例中为 24 小时)。
- 方向:‘time _ prior’因为我们希望间隔收集之前 24 小时的观察值,而不是向前。
输出是两个新的列,我们的“苹果”功能的“计数”和一个实际新闻的列表,以防有人想遍历每一个。

现在让我们创建一个文本矢量器,它是 OpenBlender 上的一个模型,你可以从中提取数千个计算化的 ngrams 作为特征:
action = 'API_createTextVectorizerPlus'parameters = {
'token' : token,
'name' : 'Wall Street and USA Today Vectorizer',
'sources':[
{'id_dataset':"**5e2ef74e9516294390e810a9**",
'features' : ["**text**"]},
{'id_dataset' : "**5e32fd289516291e346c1726**",
'features' : ["**text**"]}
],
'ngram_range' : {'min' : 1, 'max' : 2},
'language' : 'en',
'remove_stop_words' : 'on',
'min_count_limit' : 2
}response = OpenBlender.call(action, parameters)
response
根据上述内容,我们指定了以下内容:
- 名称:我们将其命名为“华尔街和今日美国矢量器”
- 源:要作为源包含的数据集的 id 和源列(在本例中,两者都只有一个名为“text”)
- ngram_range :将被标记的单词集的最小和最大长度
- 语言:英语
- remove_stop_words :这样就从源头上消除了停用词
- min_count_limit :被认为是令牌的最小重复次数(出现一次很少有帮助)
现在,如果我们转到 OpenBlender 的仪表板,我们可以看到矢量器:

它生成了 4999 个 n-gram,这些 n-gram 是最大 2 个单词的令牌的二进制特征,如果提到了 n-gram 则为“1”否则为“0”。
现在我们希望矢量化的数据在 24 小时内被压缩,并与第二天的苹果股票价格保持一致。
您需要添加您的矢量器的 id (它是在您创建它时打印的,或者您可以在 OpenBlender 中获得它。
blend_source = {
'id_textVectorizer':'**5f74fb7895162967ca2160fe**'
}df_blend = OpenBlender.timeBlend( token = token,
anchor_ts = df_anchor.timestamp,
blend_source = blend_source,
blend_type = 'agg_in_intervals',
interval_size = 60 * 60 * 24,
direction = 'time_prior_strict') .add_prefix('VEC.')df_anchor = pd.concat([df_anchor, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1)
df_anchor.head()

现在我们有了 1068 个观察值和 4887 个特征。我们的原始数据集加上过去 24 小时的矢量化和聚合新闻。
第五步。准备数据并应用 ML
没有更多的争论或清理要做,我们只需要创建我们的目标特性正 POC 和负 POC(我们将使用‘正 POC’来实现前面定义的目的)。
# Where ‘change’ **decreased** more than 0.5%
df_anchor['negative_poc'] = [1 if log_diff < -0.005 else 0 for log_diff in df_anchor['change']] # Where ‘change’ **increased** more than 0.5%
df_anchor['positive_poc'] = [1 if log_diff > 0.005 else 0 for log_diff in df_anchor['change']]# We need to shift our target one day so that we predict
# for what will happen 'tomorrow' with news and data from 'today'df_anchor['target'] = df_anchor['positive_poc'].shift(-1)
df_anchor[['change', 'positive_poc', 'target']]

现在我们有了'目标'特性,它简单地将的“变化”值与“前一天的数据对齐,这正是我们所需要的。最近的观察(最后一次)是 NaN,因为那是我们想要为“明天”预测的。
现在,让我们尝试一些 ML 来学习和预测目标。
# Import libraries
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score
from sklearn import metrics
df_anchor = df_anchor[:-1] # Remove the last one with NaN# Define target
target = 'target'
df_positive = df_anchor[1:].select_dtypes(['number'])# Create train/test sets
X = df_positive.loc[:, df_positive.columns != target].values
y = df_positive.loc[:,[target]].values
div = int(round(len(X) * 0.71))X_train = X[:div]
y_train = y[:div]
X_test = X[div:]
y_test = y[div:]print('Train:')
print(X_train.shape)
print(y_train.shape)
print('Test:')
print(X_test.shape)
print(y_test.shape)
产出:
Train:
(758, 4995)
(758, 1)
Test:
(310, 4885)
(310, 1)
现在让我们训练模型并预测:
rf = RandomForestRegressor(n_estimators = 1000, random_state = 1)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
第六步。分析结果
现在公布结果。
print("AUC score:")
print(roc_auc_score(y_test, y_pred))
print('---')# Let's binarize and look at the confusion matrix
preds = [1 if val > 0.5 else 0 for val in y_pred]
print('Confusion Matrix:')
print(metrics.confusion_matrix(y_test, preds))
print('---')# Lets look at the accuracy score
print('Accuracy:')
print(accuracy_score(y_test, preds))
print('---')

如果我自己这么说的话,这是相当惊人的。
我们来分析一下结果。

这意味着,从这个模型预测第二天价格变化将增加 0.5%或更多的所有时间来看,它有 72%的时间是正确的。我不知道任何现实生活中的模型甚至可以与此相比。
如果我们在一天结束时运行模型,我们可以在第二天早上买入/做空,期待当天结束时的结果。
*旁注:如果你们中的任何人把这个投入到自动交易(或手工交易)的生产中,至少送我一份礼物。
第七步。打破时间的数据
现在,我们需要一种方法,在这种方法中,数据经过训练和测试,以观察结果是否一致。

让我们运行我们刚刚做的,但是在这个循环中中断数据。
results = []for i in range(0, 90, 5):
time_chunk = i/100
print(“time_chunk:” + str(time_chunk) + “ starts”)
df_ml = df_positive[:int(round(df_positive.shape[0] * (time_chunk + 0.4)))]
X = df_ml.loc[:, df_ml.columns != target].values
y = df_ml.loc[:,[target]].values
div = int(round(len(X) * 0.29))
X_test = X[:div]
y_test = y[:div]
X_train = X[div:]
y_train = y[div:]
rf = RandomForestRegressor(n_estimators = 1000, random_state = 1)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
preds = [1 if val > 0.5 else 0 for val in y_pred]
try:
roc = roc_auc_score(y_test, y_pred)
except:
roc = 0
conf_mat = metrics.confusion_matrix(y_test, preds)
accuracy = accuracy_score(y_test, preds)
results.append({
‘roc’ : roc,
‘accuracy’ : accuracy,
‘conf_mat’ : conf_mat,
‘time_chunk’ : time_chunk
})

我们可以看到指标增加并稳定低谷时间!

容错和冗余系统与 AWS 上的开发无缝集成
理解大数据
受网飞猿人军队的启发,使用 AWS 自动伸缩组和 CI/CD 构建了一个完全管理良好的容错系统,利用 CodeDeploy 和 CodePipeline 将 GitHub 作为源代码控制。

每个架构师都梦想为他们的开发环境开发一个复杂的系统。制造一个容错系统可以确保从单点故障到系统的高可用性和冗余。现在有很多工具可以自动完成这项工作,比如 AWS 自动缩放组,我们需要使用它。我从网飞科技博客上读到这篇文章,并有了写这篇博客的动力。我的博客包括一个全面的端到端系统,从 GitHub 开始,到您的浏览器结束。我画了一张草图,这样你会对这篇文章的输出有一个更清晰的了解。

苏拉布什雷斯塔。AWS UML 图。2020.JPEG 文件。
陷阱:这个博客有一个单独的部分叫做陷阱,它显示了我在哪里绊倒了,在哪里你也可能滑倒和绊倒。在写这篇博客的时候,我犯了很多这样的错误,并花了很多时间来解决它。因此,了解你可能跌倒的地方也很重要,可以防止你跌倒。
网飞科技博客创建了一个名为混沌猴的工具,“一个随机禁用我们生产实例的工具,以确保我们能够在没有任何客户影响的情况下经受住这种常见类型的故障。”[1](网飞四面军,2011 年)
因此,基本上我们将复制相同的工具,如混沌猴,并将其部署在我们的系统上。他们的名字混沌猴来自于猴子的不可预测性属性,它会破坏服务器中它去的任何地方,我们做的完全相反。我们选择昏睡的熊猫,它是如此懒惰以至于忘记更新云上的一些服务器。我们将把这只熊猫放在服务器上,并修复它造成的问题。
对于这个项目,我将使用 AWS 的服务,如用于冗余和容错系统的 EC2 实例、启动模板、弹性 IP 和自动扩展组、 CodeDeploy、和 CodePipeline 用于实例的无缝代码集成,以及作为我们代码库的 GitHub 。在开始之前,我们需要知道这些服务到底是什么。
- Amazon Elastic Compute Cloud(Amazon EC2)是 Amazon 提供的虚拟机服务,根据使用情况以最低的成本使云计算变得更简单、更快速、更可扩展。[2](亚马逊 EC2,未注明日期)
- 一个 自动缩放组是一组 Amazon EC2 实例,用于根据使用参数自动缩放。自动缩放组主要用于防止云上可能出现的任何容错。3
- 一个 启动模板是一个配置模板,用于自动伸缩或者作为一个单一服务来启动 EC2 实例。4
- 弹性 IP 是由 EC2 实例分配的动态 IP 地址的静态 IPv4 地址。对于自动扩展组,弹性 IP 被动态分配给当前正在运行的实例,以减少或消除停机时间。[5](弹性 IP 地址,未注明)
- AWS CodeDeploy 是一个部署服务,它自动将代码部署到不同的 Amazon 服务中,如 Amazon EC2、Lambda 和本地服务器。[6] (AWS 代码部署,未注明)
- AWS CodePipeline 是亚马逊提供的持续集成和持续部署服务,有助于将不同来源的代码引入 AWS 服务。 AWS CodePipeline 也在顶层使用 CodeDeploy 将代码部署到 CodeDeploy 上配置的服务中。[7] (AWS 代码管道,未标明)
- GitHub 是一个代码托管服务,它提供了一个版本控制系统,来自一个名为 Git 的开源服务。[8] (GitHub,未注明日期)
弹性 IP
让我们开始建立这个系统吧。我们将首先从弹性 IP 中分配一个弹性 IP 地址。打开 AWS 控制台,然后进入 EC2 服务,在屏幕左侧滚动时,您会看到 Elastic IPs 。选择它然后点击分配弹性 IP 地址。

苏拉布什雷斯塔。分配弹性 IP 地址 1。2020.JPEF 档案。
点击后,您将被重定向到下一页。

苏拉布什雷斯塔。分配弹性 IP 地址 2。2020.JPEG 文件。
在这里,您必须输入您希望系统存在的区域。我所在的地区目前在北弗吉尼亚,所以对我来说是“美国东部-1”。您可以在您/您想要的地区相应地进行更改。点击分配。

苏拉布什雷斯塔。分配弹性 IP 地址。2020.JPEG 文件。
因为您已经分配了一个弹性 IP 地址。现在,需要注意的重要部分是分配的 IPv4 地址和分配 ID。这是因为我们需要将它与我们的自动缩放组相关联。
陷阱 1:事实证明,我们不能简单地将弹性 IP 地址添加到自动扩展组中,也不能通过 AWS 控制台添加启动模板。这只能通过 AWS CLI 完成。
现在,我们需要一个 bash 脚本来动态分配地址。你需要做一些小的改动,所以一定要在一些文本编辑器上复制下面给出的代码
苏拉布什雷斯塔。Bash 脚本二分法。2020.JPEG 文件。
在获得那些分配的 IPv4 地址和分配 ID 后,将它们复制到它们适当的位置,行号 10 和 11。如果您所在的地区不是 us-east-1,在第 6(2)、10 和 11 行更改您所在的地区。不要担心第 2–9 行,因为它们是 AWS CodeDeploy 的一部分,用于在实例上安装代码部署代理。
陷阱 2:我已经测试了上面的代码,到目前为止它运行得很好,但是如果后来有什么不工作,你需要改变,唯一的方法就是创建一个实例,然后一个接一个地运行这个命令。如果你发现错误——修复它,如果没有,转到下一个命令,如果一切正常,那么就太棒了。此外,您还会在第 10 行看到一条错误消息,因为它试图取消一个甚至没有关联的 IP,所以您可以忽略它。
启动模板
到目前为止一切顺利,现在我们需要为我们的自动缩放组创建一个模板,以便从中启动实例。对于这个系统,我们将创建一个 t2.micro 实例,只需进行最少的设置就可以运行一个网页。在同一个 EC2 服务上,选择启动模板,然后点击创建启动模板。
你也可以使用启动配置,但是 AWS 更喜欢启动模板,所以最好使用后者。

苏拉布什雷斯塔。正在创建启动模板 1。2020.JPEG 文件。
在你被重定向到下一页后,你会得到一个表格来填写细节。用我提供的图像填充它。有些很简单,不需要解释,但有些需要解释,我会用图片来解释。

苏拉布什雷斯塔。正在创建启动模板 2。2020.JPEG 文件。
这是带有标签的基本名称和描述。相应地把它们装满。

苏拉布什雷斯塔。正在创建启动模板 3。2020.JPEG 文件。
我在 t2.micro 上用默认的 keypair 选择了 Amazon Linux 2 AMI。

苏拉布什雷斯塔。正在创建启动模板 4。JPEG 文件。
养成添加标签的习惯。如图所示,输入实例的标记名。
陷阱 3:如果你不打算在模板中使用图形,那么就不要添加 Elastic graphics 标签,因为这会在 CodeDeploy 阶段产生错误。因此,根据需求选择实例标签至关重要。

苏拉布什雷斯塔。正在创建启动模板 5。JPEG 文件。
现在,展开高级细节,点击创建一个新的 IAM 配置文件。您将被重定向至 IAM 服务。用这个 JSON 制定政策。
苏拉布什雷斯塔。EC2 模板策略。2020.JPEG 文件。
EC2 策略用于实例从命令行分配弹性 IP。
陷阱 4:您可以看到有 S3 get 和 list 访问,您可能想知道为什么?这正是我所想的。不知何故,CodeDeploy 代理需要 S3 get 和 list 操作来使其工作。我在哪里可以看到我的错误,并且知道我在哪里得到错误。如果您的实例在部署 CodeDeploy 代理时出现问题,您可以随时在此处查看日志:
-less/var/log/AWS/code deploy-agent/code deploy-agent . log
从这里您可以调试将来可能面临的任何问题。
制定策略后,将其附加到您创建的新角色,然后保存它。点击刷新,然后你会看到新的角色在选择中弹出。我的角色名是 EC2AddressRole。

苏拉布什雷斯塔。正在创建启动模板 6。2020.JPEG 文件。
记得你上面复制的脚本。现在,是时候将脚本代码复制回用户数据上的模板了。

苏拉布什雷斯塔。正在创建启动模板 7。2020.JPEG 文件。
点击创建模板版本和查看启动模板。您已经成功制作了一个启动模板。现在到自动缩放组。
自动缩放组
让我们制作自动缩放组。转到同一 EC2 服务上的自动缩放组,然后单击创建自动缩放组。

苏拉布什雷斯塔。创建自动缩放组 1。2020.JPEG 文件。
现在添加名称并选择我们刚刚制作的模板。

苏拉布什雷斯塔。创建自动缩放组 2。2020.JPEG 文件。
从给定区域中选择子网。

苏拉布什雷斯塔。创建自动缩放组 3。JPEG 文件。
陷阱 5:选择子网时要非常小心。在我的例子中,t2.micro 实例在 us-east-1e 上不可用,这导致自动缩放组崩溃。您总是可以在自动缩放组活动部分看到错误。请仔细阅读,因为这对于调试您的系统以及了解整体情况非常重要。

苏拉布什雷斯塔。创建自动缩放组 4。JPEG 文件。
让它默认。

苏拉布什雷斯塔。创建自动缩放组 5。2020.JPEG 文件。
在这里,添加您想要的容量,即您想要启动并运行多少个实例。选择最小容量始终等于或小于所需容量,最大容量等于或大于所需容量。在扩展策略中,您可以选择它,并且可以将 CPU 利用率作为您的指标添加到自动扩展中,但是现在,我将保留默认设置。

苏拉布什雷斯塔。创建自动缩放组 6。2020.JPEG 文件。
如果需要,可以在电子邮件或电话中添加通知。

苏拉布什雷斯塔。创建自动缩放组 7。2020.JPEG 文件。
陷阱 6:不要依赖启动模板标签,因为有时标签不会写在实例上。所以最好把他们放在自动缩放组里,这样比较安全。
按照上面的选择添加标签。单击下一步,然后创建自动缩放组。您将看到您的实例在 EC2 仪表板上弹出。
代码部署
现在下一步是设置 CodeDeploy 和 CodePipeline,将您的代码从 GitHub 部署到这些实例。在此之前,您需要再次创建一个新角色,这次是为了 CodeDeploy。转到 IAM 并为 CodeDeploy 创建一个角色。这很简单:进入角色- >创建角色- > 选择 CodeDeploy - > 选择第一个 ( 允许 CodeDeploy 调用 AWS 服务,比如代表你自动伸缩。 ) - > 下一个- > 给个名- >评完事。现在,从 AWS 服务转到 CodeDeploy,并从应用程序中单击创建应用程序。

苏拉布什雷斯塔。设置代码部署 1。2020.JPEG 文件。
写下名称并在计算平台上选择 EC2,然后点击创建应用。

苏拉布什雷斯塔。设置代码部署 2。2020.JPEG 文件。
现在,点击创建部署组。

苏拉布什雷斯塔。设置代码部署 3。2020.JPEG 文件。
添加名称并选择您刚刚从上面创建的角色。我的角色名是 CodeDeployUnit4。

苏拉布什雷斯塔。设置代码部署 4。2020.JPEG 文件。
选择自动缩放组作为您的部署设置。

苏拉布什雷斯塔。设置代码部署 5。2020.JPEG 文件。
禁用负载平衡和创建一个部署组。

苏拉布什雷斯塔。设置代码部署 6。2020.JPEG 文件。
您的部署组现在已经准备好了。现在让我们向您的 Git 存储库添加一些示例代码。
代码管道
AWS 有自己的代码准备从 CodeDeploy 推送,这里是桶。
aws s3 cp s3://aws-codedeploy-us-east-1/samples/latest/SampleApp_Linux.zip . — region us-east-1
陷阱 7:现在不要试图上传你自己的代码,因为你稍后会看到它本身有一些钩子,我们可以在另一个博客中深入挖掘,所以现在坚持使用 AWS 给出的默认代码。从桶中下载时也要注意区域。
将此代码添加到您的存储库中,私有/公共无关紧要。现在在开发者工具的设置上,选择连接

苏拉布什雷斯塔。设置代码管道 1。2020.JPEG 文件。
点击创建连接

苏拉布什雷斯塔。设置代码管道 2。2020.JPEG 文件。
它会将您重定向到下一页,在这里您给出连接名称。在那里添加任何名称。

苏拉布什雷斯塔。设置代码管道 3。2020.JPEG 文件。
这将把你重定向到 GitHub 页面。登录,如果已经登录,则允许访问。之后,您将在 Connections 选项卡上看到您的连接。很好。现在转到代码管道,点击创建管道。

苏拉布什雷斯塔。设置代码管道 4。2020.JPEG 文件。
添加您的姓名,一切保留默认值,然后单击下一步的。

苏拉布什雷斯塔。设置代码管道 5。2020.JPEG 文件。
选择 Github 版本 2 并在设置中选择您刚刚建立的连接。此外,给出存储库名称和它的分支名称。

苏拉布什雷斯塔。设置代码管道 6。2020.JPEG 文件。
跳过构建阶段,因为我们使用的是普通的 HTML 代码。现在,选择您刚刚创建的应用名称和部署组,点击下一步和创建管道。

苏拉布什雷斯塔。设置代码管道 7。2020.JPEG 文件。
结果
现在,唯一要做的就是测试。在 HTML 页面上编辑一些行,并推送代码。一旦您推送代码,代码管道将运行,然后将其部署到自动扩展组,这将通过单个弹性 IP 显示。
陷阱 8:这段代码将会运行,但是当然,当你把你自己的代码放入时,你将会遇到部署问题。为此我有备而来。
https://docs . AWS . Amazon . com/code deploy/latest/user guide/error-codes . html
code deploy 有自己的错误,你可以使用上面的链接对它们进行排序。还要检查陷阱 4,因为也可以在那里找到错误陷阱 9:有时一切从头到尾都是正确的,但是代码部署失败了。你可能会笑,但这里的解决方案是
sudo 服务代码部署-代理重启
是的,重启有时会修复所有错误,所以在调试时也使用它

苏拉布什雷斯塔。代码管道 1 的结果。2020.JPEG 文件。
现在让我们看看弹性 IP。我将把我的名字写进 index.html 档案。

苏拉布什雷斯塔。代码管道 2 的结果。2020.JPEG 文件。
我把我的名字加在了样板文本的下面,这看起来很有效。Yayyy!
昏睡的熊猫
事不宜迟,让我们召唤昏睡的熊猫行动起来。对于它的先决条件,您只需要安装一个 AWS CLI 、 AWS IAM 用户和 EC2 访问角色,并将其添加到您将要使用的机器上。
苏拉布什雷斯塔。昏睡的熊猫二分法。2020.JPEG 文件。
运行该命令,您可以看到这只熊猫导致您的一个实例被终止。但是担心,不是我们的自动缩放组已经得到了它。现在检查你的弹性 IP,看看你的网站是不是宕机了。它运行正常。

苏拉布什雷斯塔。昏睡的熊猫的结果。2020.JPEG 文件。
结论
我真的很喜欢做这个系统,它能流畅地运行代码并具有容错能力。这只是一个开始,因为我们可以采用其他技术,如通过它运行机器学习代码,使用 S3 保存模型,托管 Node/React 应用程序,同时利用代码管道上的构建步骤,使用代码管道将 GitHub 代码推送到 CodeDeploy 以外的地方,利用 AWS Lambda 上的部署组,但让我们具体谈谈这在数据科学中的使用。
陷阱 10:这更像是我过去所做的事情。在部署用于构建模型的机器学习代码时,我将代码推入 GitHub,然后打开实例,提取最新的代码,运行代码并生成模型。有时在对代码做小的修改时,我会直接在实例上修改它,这有时会导致两个本地存储库之间的差异。落实到这一点,不仅仅是在做一些网站的同时,在大数据科学上,机器学习项目肯定会加速,工作流的速率也会提高。执行这些步骤可以让您更专注于模型的研究方面,而不是配置方面,因为做数据科学就是要进行实验和交付。
缺陷 11:在生成机器学习模型后,你可以在 linux 系统的 cronjob 上使用这个命令将其自动同步到 S3。
AWS S3 syncS3://
这将使您的模型在单一路径上高度可用。不需要进入实例,搜索和下载路径。
然而,选择是无穷无尽的,你想做什么取决于你自己。如果你遇到任何问题或难以遵循这些步骤,请在下面评论这篇文章或在 tsulabh4@gmail.com 给我发消息。你也可以通过 Linkedin和 GitHub与我联系,或者订阅我的时事通讯来获得精彩的博客。
Sulabh Shrestha 电子邮件表单
eepurl.com](http://eepurl.com/hg2RQP)
参考
[2]亚马逊 EC2,检索自亚马逊官网【https://aws.amazon.com/ec2。
[3]自动缩放组,检索自https://docs . AWS . Amazon . com/Auto Scaling/ec2/user guide/Auto Scaling group . html(n . d),亚马逊官网。
[4]启动配置,检索自https://docs . AWS . Amazon . com/auto scaling/ec2/user guide/Launch configuration . html(n . d),亚马逊官网。
【5】弹性 IP 地址,检索自https://docs . AWS . Amazon . com/AWS C2/latest/user guide/Elastic-IP-addresses-EIP . html(n . d),亚马逊官网。
[6] AWS CodeDeploy,检索自亚马逊官网https://aws.amazon.com/codedeploy/(未注明)。
[7] AWS CodePipeline,检索自亚马逊官网https://aws.amazon.com/codepipeline/(未注明)。
[8] Github,从 https://github.com/的 GiHub 公司检索。
制作一个免费的单页闪屏
想炫耀你的作品集吗?也许你需要一个网页来放你的在线简历?也许你想演示一个 web 开发项目?
不要再看了!

这是我们将要做的:
- 从头开始建立 GitHub Pages 网站。
- 添加一个模板,使它看起来很漂亮。
这是我的:T3【https://nistrup.github.io/】T5
开始之前,我们有几个先决条件:
- GitHub 账户。
- 一个终端。
- 非常有限的 Git 和一般 HTML 编辑经验。(我拒绝称之为“HTML 编程”)
我们需要一个 GitHub 帐户的原因是我们将使用 GitHub 页面,所以如果你还没有 GitHub 档案,现在是时候创建它了!
现在,请准备好直接从 GitHub 中大量复制/粘贴一些分步说明。
步骤 1,创建一个存储库
转到 GitHub 和创建一个名为username. GitHub . io 的新存储库,其中 username 是你在 GitHub 上的用户名(或组织名)。

忽略错误,这只是因为我已经创建了我的。
注意:如果存储库的第一部分与你的用户名不完全匹配,它就不能工作,所以要确保它是正确的。
步骤 2,克隆您的新存储库
导航到终端中您想要存储项目的任何文件夹,并克隆新的存储库:

将 用户名 替换成自己的。
可能会提示您输入 GitHub 凭据,只需输入并继续。
步骤 3,创建初始 index.html
进入项目文件夹并添加一个 index.html 文件:

将 用户名 替换成自己的。
如果你在 web 开发方面更有经验,可以随意使用你的 index.html 文件。如果没有,请继续阅读,我们将建立一个很好的模板。
第四步,把它推送到你的仓库
添加、提交和推送您的更改:

第五步,它是活的!
打开浏览器,进入 https:// 用户名 .github.io

宏伟!
虽然这是伟大的,我相信所有轻微的改善是有序的..!让我们给它加点料。
第六步,找到并应用一个模板!
我发现Start Bootstrap对于单页模板来说是一个非常好的资源,这正是我们所需要的!一个明显的候选是“一页奇迹”:

https://startbootstrap.com/themes/one-page-wonder/
现在简单地说:
- 直接下载模板或者从 GitHub 克隆。
- 提取到与步骤 2 相同的目的地。(很可能会让你覆盖 index.html,显然没问题)**
一旦所有内容都与初始 index.html 在同一个文件夹中,导航到终端中的文件夹,然后将新模板提交到存储库:

这只是步骤 4 中的映像的副本,但这是相同的过程,在提交消息中写入您想要的任何内容,不必是“初始提交”。
第七步,个性化
现在你已经在 https:// 用户名 .github.io 上用你选择的模板有了一个活的网站!
显然你会想要做一些改变,这可以通过简单地在你喜欢的文本编辑器中编辑模板中包含的 HTML 和 CSS 文件来实现(主要关注index.html文件)。这些是你唯一需要担心的文件,你可以忽略其他一切!
结束语
我希望这篇短文对你有所帮助!
阅读彼得·尼斯特拉普在媒介上的作品。数据科学、统计和人工智能...推特:@PeterNistrup,LinkedIn…
medium.com](https://medium.com/@peter.nistrup)****
做模型就像烤蛋糕

可供选择的蛋糕种类
随着我们在当今时代的进一步发展,数据科学和技术的进步继续在研究和实践的各个领域取得惊人的进展。由于数据科学和技术的广泛适用性,已经构建了各种不同类型的模型。
举几个例子:广义线性模型、支持向量机、K-最近邻算法、梯度推进决策树、随机森林和神经网络。
鉴于数据量和数据内交互的复杂性,已经用几种不同的语言开发了各种特定于数据科学的包。在 python 中,我们有 sklearn、xgboost、lightgbm、pyspark 和 H2O。在 R 中,我们有,但不限于,Caret、Prophet、SparkR 和 xgboost。
上述每个软件包都试图解决非常具体的数据科学问题。然而,考虑到初始问题的性质,我们可能需要一种更加定制的方法来导出解决方案。这就是每个数据科学家努力解决的问题。
通常,由于该领域中存在各种各样的问题,数据科学家使用模型和预定义的模型架构来开发解决方案,并寻求提高预定义模型无法解决的某些 KPI 指标性能。
幸运的是,有一种方法可以开发一个建模架构来专门解决您的问题。通过理解这些预定义模型架构中每一个所使用的数学和统计过程,就有可能针对您的具体问题对模型进行逆向工程。
首先,让我们检查一系列模型,然后继续开发我们自己的模型。
我们的预制蛋糕

如前所述,有不同类型的模型,其中大多数是预定义的。唯一的例外是神经网络,在神经网络中,可以指定您自己的模型架构,并定义您自己的性能来直接优化。然而,考虑到参数的整体复杂性,我们将不讨论如何做到这一点。
为了便于讨论,我们将讨论一个相当基础的模型架构,它很容易进一步扩展。我们将考虑广义线性模型族。
警告。这部分文章本质上是非常数学化的,需要一定程度的数学成熟度和理解力。如果您不想阅读这一部分,请跳到下一节,因为这一节有更多的 python 代码表示。
广义线性模型族由不同的模型架构组成。它可以是普通的最小二乘线性回归、休伯回归、逻辑回归和泊松回归,具有 L2 或 L1、或两者的混合、正则化。从解决数据科学问题的角度来看,这些不同的模型都是相似的

在这个问题陈述中,我们有一个任意函数, f ,作用于我们提出的定义为 Ax 的预测,其中 A 是我们的训练数据集, x 是我们的系数列表,以及我们的实际训练标签, y 。我们的罚函数,可以作为我们的正则子,是 p 。此外,双括号指的是一个规范。
我们的预定义模型架构如何使用的一个示例是我们的普通线性平方问题,其中

而我们的范数叫做2-范数。
我们的罚函数,【p】取决于我们是否要使用正则化。目前,让我们假设 p(x) = 0 。
在下一节中,我们将介绍一个例子,说明如何为我们自己的指标创建我们自己的 GLM。
我们需要的原料
现在让我们定义我们想要直接优化的指标!
对于我们的例子,让我们优化平均绝对误差。
对于这个任务,我们将使用两个特定的 python 包。一个是 scipy,另一个是亲笔签名的。下面是如何利用这两者来创建我们选择的模型的代码片段,请注意这是如何遵循 sklearn API 的。
**# this is for our optimization scheme
from scipy.optimize import minimize# this is to allow autograd to perform auto-differentiation
from autograd import grad
import autograd.numpy as np# this function calculates our metric
def mean_absolute_error(y_pred, y_true):
return np.mean(np.abs(y_pred - y_true))# the loss function we want to use, where data is our training data,# y is our training labels, and x is our linear coefficients
def loss(data, x, y):
return mean_absolute_error(np.dot(data, x), y)# this class is fully equipped with all of the needed functions to # follow the sklearn API
class MAERegressor: def __init__(self, fit_intercept=True):
self.fi = fit_intercept
self.coef_ = None def fit(self, data, y):
# we try to determine whether we want to fit the intercept
# or not fi = self.fi if fi:
_data = np.hstack((np.ones((data.shape[0], 1)), data))
else:
_data = data # below we define the optimization function and the gradient def opt(x):
return loss(_data, x, y) def f_grad(x):
return grad(opt)(x) # we assume our initial coefficients follow a normal
# distribution res = minimize(opt, x0=np.random.normal(0, 1, (_data.shape[1], 1)),
jac=f_grad) # the coefficient is saved here
self.coef_ = res.get("x")
return self def predict(self, data): fi = self.fi if fi:
_data = np.hstack((np.ones((data.shape[0], 1)), data))
else:
_data = data coef_ = self.coef_ if coef_ is None:
raise RunTimeError("The model has not been trained yet") return np.dot(_data, coef_) def score(self, val_data, val_y): return mean_absolute_error(self.predict(val_data), val_y)**
从上面可以看出,我们能够创建我们自己的模型架构,并优化我们自己的度量函数!
别忘了糖霜!

Jordane Mathieu 在 Unsplash 上拍摄的照片
作为演示,在将上一节中的代码复制并粘贴到 Python 内核中之后,尝试运行以下代码片段
**n = 10000
m = 5num_labels = 1data = np.random.normal(0, 1, (n, m))
w_ = np.random.random((m + 1, num_labels))
_data = np.hstack((np.ones((n, 1)), data))
labels = np.dot(_data, w_)model = MAERegressor(True)model.fit(data, labels)model.score(data, labels)**
你有它!自定义模型,它将确定线性模型的系数,该模型专门设置为最小化平均绝对误差。
为了创造一个类似的模型,你所要做的就是按照食谱做,你应该很棒!
如果这引起了你的共鸣,请到我的主页订阅我的时事通讯
**[## 主页
在这里,您将找到有关 Edward Turner 所做工作的信息,以及…
ed-特纳. github.io](https://ed-turner.github.io/)**
或者,在 LinkedIn 上关注我
** [## 爱德华·特纳-数据科学家- Paylocity | LinkedIn
爱德华·特纳(Edward Turner)是一名多语言开发人员,懂 Python、R 和 Scala,懂 Java 和 C/C++的语法。他…
www.linkedin.com](https://www.linkedin.com/in/edward-turner-polygot/)**
如果你有兴趣了解更多关于我是如何在这个领域变得熟练的,你可能也会对这篇文章感兴趣。
**[## 数据科学之旅
通常,所有的旅程都有开始和结束。幸运的是,或者至少我现在知道,我的…
medium.com](https://medium.com/@edward.turnerr/the-journey-into-data-science-d702f8b810a9)**
一如既往,#快乐编码
制作生产分类器集成
使用 BERT、Inception 和 fastText 的现成 PDF 分类器服务

照片由 Jason Dent 在 Unsplash 上拍摄
机器学习的演示很容易找到,但是实用的、可以投入生产的端到端解决方案呢?我在这里描述了一个用于 pdf 的开源的、生产就绪的、基于集成的文档分类器。它达到了 98%的准确率。这是对它如何产生的解释,为什么不同的分类器被结合,以及我如何把它变成一个生产系统。
需求
我的客户,非盈利的互联网档案馆保存着网络上的内容,这样过去就不会丢失。几乎每个人都知道“时光倒流机”,他们提供的网络时光机器。
互联网存档有一个选择存档内容的启发法:如果某样东西可能很快就会永远丢失,那就先存档。有时这是战术性的,也是必然的,就像在拔掉插头之前保存 Google Plus 内容一样。这项工作的重点是保存那些不为人知的 pdf 文件,但也许有一天在长尾理论中会很重要。特别是,像学术论文这样由小出版商提供服务的研究工作可能会消失,因为它们没有足够的资金。相比之下,在天平的另一端,公共科学图书馆的论文没有丢失的危险。
安德鲁·梅隆基金会有支持图书馆的历史,它为这项工作提供了资助。该授权规定所开发的软件是开源的;这使得把这个项目放在 github.com 变得很容易。
Internet Archive 在 2019 年初向我呈现了这种情况:确定一个 PDF 是否是研究作品需要 30 秒,但需要小于 1 秒。它将用于已存档的 pdf 和在网络搜索中找到的 pdf。使用将是批处理,而不是交互式的,它必须在没有 GPU 的情况下工作。重要的是,它必须与多种语言一起工作,因为没有太多的训练示例。该计划是处理 6.5 亿个 pdf 文件,以找到 6%的研究工作。
正面训练集是已知的 1800 万篇论文的集合,这些论文可以被认为是干净的、基本的事实。负面训练集只是从被正面案例污染的 6.5 亿个 pdf 中随机选择的。对 1,000 个负面案例的审核显示有 6–7%的正面案例。通过手动检查对这些进行清理,并使用自举来增加集合的大小。
带着这些目标和事实,我开始形成一个解决方案。
PDF 挑战
任何机器学习项目的第一步都是了解你的数据。我检查了 pdf 的一个子集,发现:
一些 pdf 仅包含文本图像
页面数量从一个到数百个
纵横比和页面布局各不相同
要处理只有图像的文档,第一页可用于制作图像,然后用于图像分类。
一小部分研究作品在出版时会附上封面,为出版商做广告和/或展示许可文本。这表明可以呈现多个页面来提高准确性,但是在项目的这个阶段,仅使用第一个页面就已经给了我们足够的准确性,因此检查更多页面的工作留待将来完成。
你可能会想象一项研究工作看起来像一篇典型的计算机科学会议论文,在第一页上有标题、作者、居中的摘要,也许还有一些正文。我当然预料到了这一点,但是一旦你涉足生命科学、立场文件、转录的会议主题演讲等等,设计是相当多样的。以下是一些随机挑选的正面和负面例子:

四个正面例子

四个反面例子
即使对于人类来说,这也不是视觉分析的不二法门。
PDF 到图像
ImageMagick 被选择用于第一页图像生成。它使用下面的 ghostscript 来渲染图像。最初,有许多问题图像大多是黑色的。解决这个问题的诀窍是将背景明确设置为白色。显然,大约有一半的 pdf 实际上是打印到透明背景上的。
产生的图像实际上是一个缩略图。这样做很好,因为很多成功的图像分类都是在小图像上完成的。这有一个附带的好处,即结果与语言无关:在 224x224 的情况下,不可能辨别文档中使用的语言。
必须开发一种试探法来检测和剔除空白图像。这可能是由于渲染错误,如缺少日语字体,或者实际上可能有一个空白的第一页。显然,如果正负样本集都包含空白图像,那么分类就像扔骰子一样,所以这些必须被移除。
与自然图像不同,猫可以出现在框架的任何地方,研究工作 pdf 是严格对齐的,通常在标题中居中显示文本。为了捕捉这个方面,ImageMagick 被指示水平居中渲染,使其与北边齐平。在一项对 2000 个例子的研究中,我没有看到对齐带来的大的准确性提高,所以可能的情况是,已经能够处理未对齐图像的模型没有从更多的对齐中受益。
PDF 转文本
文本需要提取以及首页图像。经过大量实验后,发现 pdftotext 实用程序对于文本来说是快速而有效的。此外,因为它是作为子流程运行的,所以使用超时来避免陷入寄生案例。当一个系统暴露在数以百万计的例子中时,导致过程缓慢或停滞的坏的苹果 pdf 是可能的。
使用 pdftotext 是一种乐趣。开箱即用,它只是工作,它可以保持人类阅读的顺序,即使有 2 列格式的话。
预处理可以跳过吗?
PDF 格式是一组使用排版、艺术线条和图像来呈现文档的指令。有许多自由度,所以 PDF 的每个实现可能都有稍微不同的风格。如果有些是专门用于研究工作或没有,指令模式可能是一个廉价的线索,但没有保证它是稳定的时间;风格会随着时间来来去去。我估计大概有 100 种指令模式在使用中。对于只有图像的 pdf,仅仅通过对正面和反面例子的训练,训练不可能在任何合理的计算预算上学会 OCR。这就像科幻作家斯坦尼斯拉夫·莱姆的想法,通过在阳光下用放大镜杀死出错的蚂蚁来训练蚂蚁写自然语言。
在放弃端到端原始 PDF 的想法后,我认为文本提取和将第一页呈现为图像是很好的方法。这些特征提取预处理步骤的速度很容易控制在 1 秒的时间预算内。
基线
假设使用 pdftotext,那么什么是好的基线模型?经典的计算机科学论文有“摘要”和“参考文献”这两个词。只需要这两个词会有多好?我进行了非正式的测量,发现要求两个单词只有 50%的准确性,这是令人沮丧的。要求任一关键字对于阳性情况有 84%的准确性。只有 10%的阴性病例有这些关键词。这给了我一个需要打破的准确性目标。
接下来,有哪些模型可以使用?
图像分类
利用迁移学习,TensorFlow Hub 用于测试十几个图像分类器模型的准确性。InceptionV3 和 Resnet 最好,为 87%;我选择 InceptionV3 有些武断。
虽然 87%并不完全是一流的,但只有包含文本图像的 pdf 才会遭受 13%的错误率。大多数 pdf 包含明确的文本。
一袋单词
线性文本分类器可以非常快,但是当没有足够的训练样本时,它们在处理多种语言时会有麻烦。在这个项目中,选择了 FaceBook 的 fastText[1]。这是一个写得很好的带有 python 绑定的 C++包,在速度方面毫不妥协。
“快”是指 0.4 毫秒,比 CPU 上的深度神经网络快 3 个数量级。在 20,000 个文档训练和测试集上的准确率达到 96%。一个很大的优点是它是全文,但一个很大的缺点是这种词袋分类器对很少或没有训练样本的语言没有泛化能力。
FastText 能够处理 n 元语法,比如单词对。在测试中,没有发现二元模型的准确性优势。
伯特
到目前为止,每个人都知道 BERT[2]模型是“自我监督”自然语言的一大进步。多语言模型是用 100 多种语言训练的,它是这个项目的完美选择。
使用 BERT 的分类器模式,在 20,000 个文档训练和测试集上对模型进行微调。结果是 98%的准确率。
一些语言中的例子数量并不多,但是分类对于非英语语言是正确的,这表明它确实是跨语言通用的。
整体建筑
21 世纪初,整体学习风靡一时。那是在贝叶斯学习流行之前。事实上,随机森林通常被认为是一种集成,因为它在训练示例上创建了一个拼凑物。
我们现在处于深度学习时代,但集成是组合文本和图像等多种形式的标准工具包的一部分。下一步是使用集成,通过使用快速的线性模型有条件地加速分类,如果置信度低,则使用 BERT。
下图显示了生产分类器集成的工作原理:

运行时架构显示 REST via Flask、TensorFlow Serving for BERT/CNN 和 FastText 线性分类器
上述每个模型计算一个分类置信度。这使得创建选择性地使用模型来强调速度或准确性的集成分类器成为可能。对于速度示例,如果文本可用并且快速文本线性分类器置信度高,则可以跳过 BERT。为了强调准确性,可以运行所有三个模型,然后结合置信值和分类预测进行总体分类。
REST 接口
使用 Flask 实现的 REST 接口使用 URI 路径中的变化来指示运行哪个分类器的偏好。URI 指出的可能的加工选择:
使用特定的分类器列表
运行所有分类器
自动模式使用最快的方法,这取决于可信度
使其可以投入生产
TensorFlow Serving[3]对于在生产中运行 TensorFlow 模型至关重要。一些实际的评论是适当的。TensorFlow Serving 是一个张量图计算引擎,它加载“保存的模型”(我引用它是因为它听起来很普通,但它是一种特定的数据格式),并通过网络为请求提供服务。为了提高速度,它是用 C++编写的,可以重新编译以利用机器提供的精确指令集来获得最大的吞吐量。
TensorFlow 服务可以使用 REST 或 gRPC。事实证明,gRPC 对客户端的干扰相当大,因为当使用 gRPC 时,用于创建输入张量的服务器端 Python 代码(“处理器”)往往也会在客户端使用。这导致了非常混乱的集成,服务器端和客户端的耦合超过了必要的程度;不仅仅是 API,还有代码。这可能只是 BERT 中的一个疏忽,也可能是 gRPC 在与 TensorFlow 结合使用时普遍缺乏封装实践。
另一方面,REST 能够使用不需要后端代码的更通用的调用签名。与 HTTP 相比,gRPC 的优势是通过较小的消息传输速度稍快,但是在只有 CPU 的部署中,这种速度差异可以忽略不计。由于这些原因,REST 在这个项目中更受欢迎。
来自 Google 的 BERT 的原始代码没有导出模型的“保存的模型”格式。为了解决这个问题,正式的 BERT 项目被分叉,并添加了一个选项来创建必要的模型格式。
回购协议
这个项目被戏称为三个分类器的集合:“pdf_trio”。
有 3 个回购:
主要项目https://github.com/tralfamadude/pdf_trio
图像分类器【https://github.com/tralfamadude/pdf_image_classifier
https://github.com/tralfamadude/bert 的伯特分类器
首先是主体工程。第二个是来自 TensorFlow Hub 的 CNN 分类器示例。第三个是官方 BERT 的一个小 delta。pdf_trio 有 5 个 README.md 文件作为参考文档,并有用于训练、测试和部署的脚本。
经过训练的模型对于 github 来说太大了,但是可以从 archive.org 下载,正如项目自述文件中所描述的。
最后
这次 PDF_trio 的温柔之旅到此结束。通过使用不同的训练示例,可以简单地制作不同种类的 PDF 分类器。希望你觉得 PDF_trio 有用。
承认
感谢:布莱恩·纽博尔德,杰斐逊·贝利,大卫·s·h·罗森塔尔。
参考
[1] 快速文本
[3] 张量流发球
用 Python 制作股票筛选程序!
学习如何用 Python 制作一个基于 Mark Minervini 的趋势模板的强大的股票筛选工具。
免责声明:本文内容基于 理查德·莫格伦的 Youtube 频道 纯属教育目的,不应视为专业投资建议。自行决定投资。
股票筛选是为你的特定交易策略寻找完美股票的好方法。然而,当我试图使用 Python 寻找股票筛选工具时,我几乎找不到任何功能性的自动化代码。所以我创建了这篇文章,帮助其他人根据马克·米纳尔维尼的趋势模板(选择最佳股票的 8 条原则)制作一个简单易懂的股票筛选 Python 程序。特别是在当前市场波动的情况下,我希望这个代码能帮助你做交易。

在我进入代码之前,我想谈谈股票筛选标准。
- 证券的当前价格必须高于 150 和 200 天的简单移动平均线。
- 150 天简单移动平均线必须大于 200 天简单移动平均线。
- 200 天简单移动平均线必须至少有 1 个月的上升趋势。
- 50 天简单移动平均线必须大于 150 简单移动平均线和 200 简单移动平均线。
- 当前价格必须大于 50 天简单移动平均线。
- 当前价格必须比 52 周低点高出至少 30%。
- 当前价格必须在 52 周高点的 25%以内。
- IBD RS 评级必须大于 70(越高越好)。RS 评级是衡量一只股票在过去一年中相对于所有其他股票和整体市场的价格表现的指标。查看这篇文章了解更多信息。
你可以在 Mark Minervini 的博客文章中读到更多关于这个模板的内容。
现在你已经熟悉了标准,我们可以进入代码了。首先,导入以下依赖项。如果您的机器上没有安装以下模块之一,请在您的终端中使用“pip install (module name)”下载它们。
导入这些依赖项,并使用yf.pdr_override.覆盖弃用警告
首先,我们必须导入我们将在程序中使用的依赖项,如 yahoo_fin(获取报价机列表)和 pandas_datareader.data(获取历史股票数据)。
接下来,我们必须为程序的其余部分设置变量。我在下面概述了每个变量的含义。
- 票贩子:标准普尔 500 所有的票贩子
- index_name:标准普尔 500 雅虎财经符号
- start_date:历史数据的开始日期(正好一年前)
- end_date:历史数据的结束日期(今天)
- exportList:我们将为每只股票收集的值
- returns _ multiples:查看每只股票相对于市场表现的列表(将用于计算 RS 评级)
for 循环的开始。
现在,我们可以计算过去一年标准普尔 500 指数的累计回报,并将该值与同期标准普尔 500 每只股票的累计回报进行比较。IBD 相对强弱指标本质上是计算一只股票在特定时间段内相对于市场和其他股票的表现。由于该指标仅在 IBD 服务中使用,我们可以通过将每只股票的累计回报率除以指数的累计回报率来估计 IBD RS,然后为每只股票创建一个百分制排名。例如,如果 AAPL 在特定时期内的表现优于 MSFT,那么它的 RS 就会更高。在 Mark Minervini 的趋势模板中,他寻找 RS 值为 70 或更高的股票(市场中表现最好的 30%的股票)。
因为在这个程序中,RS 度量是用相对于给定列表中其他股票的百分比值来计算的,所以最好有一个更大数量股票的列表,以使 RS 值更准确。在这个程序中,我们选择了标准普尔 500 指数中的 500 只股票,这样就有了足够大的样本量。
为了加快这个过程,我们可以下载每只股票过去一年的历史数据,而不是不断地向雅虎财经发出请求(这可能会导致错误)。for 循环末尾的 time.sleep(1)也有助于抑制请求涌入时的潜在错误。最后,在使用分位数进行数据处理之后,我们得到了一个数据框架,其中包含给定列表中表现最好的 30%的股票以及它们各自的 RS 值。
我们可以只包括通过 Minervini 趋势模板条件 8(RS 值大于 70)的前 30%的股票,而不是计算每只股票的指标。从这里,我们可以计算出创造条件所需的指标。当前收盘价通过采用最后一天的调整收盘价来使用。过去一年的高点和低点是通过找出过去 260 个交易日(大约一年)数据框架中的最大值和最小值得到的。移动平均值是通过计算相应天数的滚动平均值来使用的。其余的代码实际上是按照前面提到的原则执行 screener。如果一只股票通过了每一个条件,我们可以将它添加到我们的通过 Minervini 趋势模板的股票导出列表中!
最后,为了方便起见,这段代码将打印出所有符合要求的股票的数据帧,并将股票下载到 excel 文件中。现在你知道如何创建一个有史以来最好的交易者使用的股票筛选工具了!
下面的 GitHub 要点包含了该程序的所有代码。我希望这个算法将来对你有用。非常感谢您的阅读!
如果你喜欢这篇文章,可以看看下面我写的其他一些 Python for Finance 文章!
了解如何在不到 3 分钟的时间内解析顶级分析师的数千条建议!
towardsdatascience.com](/parse-thousands-of-stock-recommendations-in-minutes-with-python-6e3e562f156d) [## 用 Python 进行股票新闻情绪分析!
对财经新闻进行秒级情感分析!
towardsdatascience.com](/stock-news-sentiment-analysis-with-python-193d4b4378d4) [## 在 3 分钟内创建一个财务 Web 应用程序!
了解如何使用 Python 中的 Streamlit 创建技术分析应用程序!
towardsdatascience.com](/creating-a-finance-web-app-in-3-minutes-8273d56a39f8)
使用移动平均交叉策略生成交易信号——Python 实现
移动平均线通常用于股票的技术分析,以预测未来的价格趋势。在本文中,我们将开发一个 Python 脚本,使用简单移动平均线(SMA)和指数移动平均线(EMA)交叉策略生成买入/卖出信号。

尼古拉斯·卡佩罗在 Unsplash 上拍摄的照片
—————— 免责声明 —本文交易策略及相关信息仅供教育之用。股票市场上的所有投资和交易都有风险。任何与购买/出售股票或其他金融工具相关的决定都应在彻底研究后做出,并在需要时寻求专业帮助。 ——————
移动平均线(MAs)、布林线、相对强弱指数(RSI)等指标是交易者和投资者用来分析过去和预测未来价格趋势和形态的数学技术分析工具。基本面分析者可能会跟踪经济数据、年度报告或各种其他指标,而量化交易者和分析师则依靠图表和指标来帮助解读价格走势。
使用指标的目的是识别交易机会。例如,移动平均线交叉通常预示着趋势即将改变。将移动平均线交叉策略应用于价格图表,交易者可以识别趋势改变方向的区域,从而创造潜在的交易机会。
在我们开始之前,你可以考虑通读下面的文章,让自己熟悉一些与股票市场相关的常见金融术语。
15 个常见的股票市场术语和相关的概念,每个新手投资者都应该知道。
什么是均线?
移动平均,也称为滚动平均或移动平均,用于通过计算完整数据集的不同子集的一系列平均值来分析时间序列数据。
移动平均线是一系列数值的平均值。它们有一个预定义的长度来表示要平均的值的数量,随着时间的推移,随着更多数据的增加,这组值会向前移动。给定一系列数字和一个固定的子集大小,移动平均值的第一个元素是通过取数字系列的初始固定子集的平均值获得的。然后,为了获得随后的移动平均值,子集被“前移”,即排除前一个子集的第一个元素,并将前一个子集之后的元素立即添加到新的子集,保持长度固定。由于它涉及在一段时间内对数据集取平均值,因此也称为移动平均值(MM)或滚动平均值。
在金融数据的技术分析中,移动平均线(MAs)是最广泛使用的趋势跟踪指标之一,它展示了市场趋势的方向。
移动平均线的类型
根据平均数的计算方式,有许多不同类型的移动平均数。在任何时间序列数据分析中,最常用的移动平均线类型是—
- 简单移动平均线
- 加权移动平均(WMA)
- 指数移动平均线(均线或 EWMA)
各种移动平均线之间唯一值得注意的区别是在移动平均线周期内分配给数据点的权重。简单移动平均线对所有数据点应用相同的权重。指数和加权平均值对最近的数据点应用更多的权重。
其中,简单移动平均线(SMAs)和指数移动平均线(EMAs)可以说是分析师和交易员最常用的技术分析工具。在本文中,我们将主要关注涉及 SMA 和 EMA 的策略。
简单移动平均线
简单移动平均线是交易员和投资者用于股票、指数或证券技术分析的核心技术指标之一。简单移动平均线的计算方法是将最近 n 天的收盘价相加,然后除以天数(时间段)。在我们深入探讨之前,让我们先了解简单平均值背后的数学原理。
我们在学校学习了如何计算平均值,甚至在我们的日常生活中也经常会遇到这个概念。假设你正在观看一场板球比赛,一名击球手前来击球。通过查看他之前的 5 场比赛得分——60、75、55、80、50;你可以预计他在今天的比赛中大约能得 60-70 分。
通过计算一名击球手过去 5 场比赛的平均得分,你可以粗略地预测他今天会得这么多分。虽然,这是一个粗略的估计,并不能保证他会得到完全相同的分数,但机会仍然很高。同样,SMA 有助于预测未来趋势,并确定资产价格是否会继续或逆转牛市或熊市趋势。SMA 通常用于识别趋势方向,但是它也可以用于产生潜在的交易信号。
计算简单移动平均线 — 计算 SMA 的公式很简单:
简单移动平均线=(过去 n 个周期的资产价格之和)/(周期数)

来源: Investopedia
SMA 中的所有元素都具有相同的权重。如果移动平均周期是 5,那么 SMA 中的每个元素在 SMA 中的权重是 20% (1/5)。
n 个句号可以是任何东西。你可以有 200 天简单移动平均线,100 小时简单移动平均线,5 天简单移动平均线,26 周简单移动平均线,等等。
现在我们已经熟悉了基础知识,让我们跳到 Python 实现。
计算 20 天和 50 天移动平均线
对于这个例子,我取了从 2018 年 2 月 1 日到 2020 年 2 月 1 日的 UltraTech 水泥有限公司 股票(在 NSE 注册的 ULTRACEMCO)的收盘价的 2 年历史数据。你可以选择自己的股票组合和时间周期来进行分析。
让我们从使用 Pandas-datareader API 从雅虎财经中提取股票价格数据开始。
导入必要的库—
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
import
提取上述时间段内 UltraTech 水泥股票的收盘价数据
# import package
import pandas_datareader.data as web# set start and end dates
start = datetime.datetime(2018, 2, 1)
end = datetime.datetime(2020, 2, 1) # extract the closing price data
ultratech_df = web.DataReader(['ULTRACEMCO.NS'], 'yahoo', start = start, end = end)['Close']
ultratech_df.columns = {'Close Price'}
ultratech_df.head(10)

请注意,SMA 是根据收盘价计算的,而不是根据收盘价调整的,因为我们希望交易信号是根据价格数据生成的,而不是受支付的股息的影响。
观察给定期间收盘价的一般价格变化—
ultratech_df[‘Close Price’].plot(figsize = (15, 8))
plt.grid()
plt.ylabel("Price in Rupees"
plt.show()

在我们的数据框架中为长期(即 50 天)和短期(即 20 天)简单移动平均线(SMAs)创建新列
# create 20 days simple moving average column
ultratech_df[‘20_SMA’] = ultratech_df[‘Close Price’].rolling(window = 20, min_periods = 1).mean()# create 50 days simple moving average column
ultratech_df[‘50_SMA’] = ultratech_df[‘Close Price’].rolling(window = 50, min_periods = 1).mean()# display first few rows
ultratech_df.head()

在熊猫中,data frame . rolling()函数提供了滚动窗口计算的功能。min_periods 参数指定窗口中需要有一个值的最小观察次数(否则结果为 NA)。
现在我们有了 20 天和 50 天的 SMAs,接下来我们来看看如何利用这些信息来产生交易信号。
移动平均交叉策略
股票市场分析师和投资者可以通过多种方式使用移动平均线来分析价格趋势并预测未来的趋势变化。使用不同类型的移动平均线可以开发出各种各样的移动平均线策略。在本文中,我试图展示众所周知的简单而有效的动量策略——简单移动平均交叉策略和指数移动平均交叉策略。
在时间序列统计中,特别是在股票市场技术分析中,当绘制时,基于不同时间段的两条移动平均线趋于交叉时,移动平均线交叉。该指标使用两条(或更多)移动平均线,一条较快的移动平均线(短期)和一条较慢的移动平均线(长期)。快速移动平均线可以是 5 天、10 天或 25 天的周期,而慢速移动平均线可以是 50 天、100 天或 200 天的周期。短期移动平均线比快,因为它只考虑短期内的价格,因此对每日价格变化更敏感。另一方面,长期移动平均线被认为是较慢的,因为它包含了更长时期的价格,并且更加呆滞。
从交叉点产生交易信号
移动平均线本身是一条线,通常覆盖在价格图表上来指示价格趋势。当较快的移动平均线(即较短周期的移动平均线)与较慢的移动平均线(即较长周期的移动平均线)交叉时,就会发生交叉。在股票交易中,这个交汇点可以作为买入或卖出资产的潜在指标。
- 当短期移动平均线越过长期移动平均线时,这表明一个买入信号。
- 相反,当短期移动平均线低于长期移动平均线时,可能是卖出的好时机。
具备了必要的理论,现在让我们继续我们的 Python 实现,其中我们将尝试合并这个策略。
在我们现有的 pandas 数据框架中,创建一个新的列' Signal ,这样如果 20 天 SMA 大于 50 天 SMA,则将信号值设置为 1,否则当 50 天 SMA 大于 20 天 SMA 时,将其值设置为 0。
*ultratech_df['Signal'] = 0.0
ultratech_df['Signal'] = np.where(ultratech_df['20_SMA'] > ultratech_df['50_SMA'], 1.0, 0.0)*
从这些“信号值中,可以产生代表交易信号的位置指令。当较快的移动平均线和较慢的移动平均线交叉时,交叉发生,或者换句话说,“信号”从 0 变为 1 (或者 1 到 0)。因此,为了合并这些信息,创建一个新的列' Position ,它只不过是' Signal 列的日常差异。
*ultratech_df[‘Position’] = ultratech_df[‘Signal’].diff()# display first few rows
ultratech_df.head()*

- 当'位置* ' = 1 时,意味着信号已经从 0 变为 1,意味着短期(更快)移动平均线已经越过长期(更慢)移动平均线,从而触发买入看涨。*
- 当'持仓* ' = -1 时,意味着信号已经从 1 变为 0,意味着短期(较快)移动平均线已经穿过长期(较慢)移动平均线下方,从而触发卖出指令。*
现在让我们用一个图来形象化地说明这一点。
*plt.figure(figsize = (20,10))
# plot close price, short-term and long-term moving averages
ultratech_df[‘Close Price’].plot(color = ‘k’, label= ‘Close Price’)
ultratech_df[‘20_SMA’].plot(color = ‘b’,label = ‘20-day SMA’)
ultratech_df[‘50_SMA’].plot(color = ‘g’, label = ‘50-day SMA’)# plot ‘buy’ signals
plt.plot(ultratech_df[ultratech_df[‘Position’] == 1].index,
ultratech_df[‘20_SMA’][ultratech_df[‘Position’] == 1],
‘^’, markersize = 15, color = ‘g’, label = 'buy')# plot ‘sell’ signals
plt.plot(ultratech_df[ultratech_df[‘Position’] == -1].index,
ultratech_df[‘20_SMA’][ultratech_df[‘Position’] == -1],
‘v’, markersize = 15, color = ‘r’, label = 'sell')
plt.ylabel('Price in Rupees', fontsize = 15 )
plt.xlabel('Date', fontsize = 15 )
plt.title('ULTRACEMCO', fontsize = 20)
plt.legend()
plt.grid()
plt.show()*

正如你在上面的图中看到的,蓝线代表较快的移动平均线(20 天 SMA),绿线代表较慢的移动平均线(50 天 SMA),黑线代表实际收盘价。如果你仔细观察,这些均线只不过是实际价格的平滑版本,只是滞后了一段时间。短期移动平均线非常类似于实际价格,这完全有道理,因为它考虑了更近的价格。相比之下,长期移动平均线具有相对更大的滞后性,与实际价格曲线大致相似。
当快速移动平均线穿过慢速移动平均线时,就会触发买入信号(用绿色向上三角形表示)。这表明趋势发生了变化,即过去 20 天的平均价格已经超过了过去 50 天的平均价格。同样,当快速移动平均线穿过慢速移动平均线下方时,会触发卖出信号(由红色向下三角形表示),表明最近 20 天的平均价格已低于最近 50 天的平均价格。
指数移动平均线(均线或 EWMA)
到目前为止,我们讨论了使用简单移动平均线(SMAs)的移动平均线交叉策略。显而易见,SMA 时间序列比原始价格噪音小得多。然而,这是有代价的——SMA 滞后于原始价格,这意味着趋势的变化只有在延迟1天后才能看到。这个滞后 L 是多少?对于使用 M 天计算的 SMA 移动平均线,滞后大约是 M/2 天。因此,如果我们使用 50 天的 SMA,这意味着我们可能会晚了将近 25 天,这可能会极大地影响我们的策略。
减少使用 SMA 导致的滞后的一种方法是使用指数移动平均线(EMA)。指数移动平均线给予最近的时间段更多的权重。这使得它们比 SMAs 更可靠,因为它们相对更好地代表了资产的近期表现。均线的计算方法如下:
EMA[今日]=(αx价格[今日])+((1—α)x EMA[昨日])**
其中:
α = 2/(N + 1)
N =窗口长度(均线周期)
EMA【今日】=当前 EMA 值
价格【今日】=当前收盘价
EMA【昨日】=前一个 EMA 值
虽然均线的计算看起来有点吓人,但实际上很简单。事实上,它比 SMA 更容易计算,此外, Pandas ewm 功能将在一行代码中为您完成!
理解了基础,让我们试着在均线策略中用 EMAs 代替 SMAs。我们将使用与上面相同的代码,只是做了一些小的改动。
*# set start and end dates
start = datetime.datetime(2018, 2, 1)
end = datetime.datetime(2020, 2, 1)# extract the daily closing price data
ultratech_df = web.DataReader(['ULTRACEMCO.NS'], 'yahoo', start = start, end = end)['Close']
ultratech_df.columns = {'Close Price'}# Create 20 days exponential moving average column
ultratech_df['20_EMA'] = ultratech_df['Close Price'].ewm(span = 20, adjust = False).mean()# Create 50 days exponential moving average column
ultratech_df['50_EMA'] = ultratech_df['Close Price'].ewm(span = 50, adjust = False).mean()# create a new column 'Signal' such that if 20-day EMA is greater # than 50-day EMA then set Signal as 1 else 0
ultratech_df['Signal'] = 0.0
ultratech_df['Signal'] = np.where(ultratech_df['20_EMA'] > ultratech_df['50_EMA'], 1.0, 0.0)# create a new column 'Position' which is a day-to-day difference of # the 'Signal' column
ultratech_df['Position'] = ultratech_df['Signal'].diff()plt.figure(figsize = (20,10))
# plot close price, short-term and long-term moving averages
ultratech_df['Close Price'].plot(color = 'k', lw = 1, label = 'Close Price')
ultratech_df['20_EMA'].plot(color = 'b', lw = 1, label = '20-day EMA')
ultratech_df['50_EMA'].plot(color = 'g', lw = 1, label = '50-day EMA')# plot ‘buy’ and 'sell' signals
plt.plot(ultratech_df[ultratech_df[‘Position’] == 1].index,
ultratech_df[‘20_EMA’][ultratech_df[‘Position’] == 1],
‘^’, markersize = 15, color = ‘g’, label = 'buy')plt.plot(ultratech_df[ultratech_df[‘Position’] == -1].index,
ultratech_df[‘20_EMA’][ultratech_df[‘Position’] == -1],
‘v’, markersize = 15, color = ‘r’, label = 'sell')plt.ylabel('Price in Rupees', fontsize = 15 )
plt.xlabel('Date', fontsize = 15 )
plt.title('ULTRACEMCO - EMA Crossover', fontsize = 20)
plt.legend()
plt.grid()
plt.show()*

以下节选自约翰·j·墨菲的著作《金融市场的技术分析》,由纽约金融研究所出版,解释了指数加权移动平均线相对于简单移动平均线的优势
“指数平滑移动平均线解决了与简单移动平均线相关的两个问题。首先,指数平滑的平均值给较新的数据分配较大的权重。因此,它是一个加权移动平均线。但尽管它对过去价格数据的重视程度较低,但它确实在计算中包括了该工具生命周期中的所有数据。此外,用户能够调整权重,以给予最近一天的价格更大或更小的权重,该权重被添加到前一天的价值的百分比中。两个百分比值之和为 100。
完整的 Python 程序
函数'MovingAverageCrossStrategy()'接受以下输入—
- 股票代号—(str)股票代号,如雅虎财经。例如:ULTRACEMCO。纳秒
- start_date — (str)从此日期开始分析(格式:' YYYY-MM-DD')
例如:' 2018-01-01 '。 - end_date— (str)在此日期结束分析(格式:' YYYY-MM-DD')
例如:' 2020-01-01 '。 - short_window— (int)短期移动平均线的回看周期。例:5,10,20
- long_window — (int)长期移动平均线的回看周期。
例如:50,100,200 - moving_avg— (str)要使用的移动平均线的类型(“SMA”或“EMA”)。
- display_table — (bool)是否在买入/卖出位置显示日期和价格表(真/假)。
现在,让我们用过去 4 年的 HDFC 银行股票来测试我们的脚本。我们将使用 50 天和 200 天的 SMA 交叉策略。
输入:
*MovingAverageCrossStrategy('HDFC.NS', '2016-08-31', '2020-08-31', 50, 200, 'SMA', display_table = True)*
输出:
**
富通 Healtcare 股票怎么样?这次我们分析过去 1 年的数据,考虑 20 天和 50 天的均线交叉。此外,这次我们不会显示表格。
输入:
*MovingAverageCrossStrategy('FORTIS.NS', '2019-08-31', '2020-08-31', 20, 50, 'EMA', display_table = False)*
输出:

由于它们计算方式的根本不同,均线对价格变化反应迅速,而均线反应相对较慢。但是,一个不一定比另一个更好。每个交易者必须决定哪个 MA 更适合他或她的策略。一般来说,短线交易者倾向于使用 EMAs,因为他们想在价格向相反方向变动时得到提醒。另一方面,长期交易者倾向于依赖 SMAs,因为这些投资者不急于行动,更喜欢不太积极地参与交易。
当心!作为一个趋势跟踪指标,移动平均线适用于具有明确长期趋势的市场。在长期波动的市场中,它们并不那么有效。故事的寓意——均线不是万能的圣杯。事实上,没有完美的指标或策略可以保证在任何情况下每项投资都能成功。量化交易者经常使用各种技术指标及其组合来制定不同的策略。在我随后的文章中,我将尝试介绍其中的一些技术指标。
结束注释
在本文中,我展示了如何构建一个强大的工具来执行技术分析,并使用移动平均交叉策略生成交易信号。这个脚本可以用于调查其他公司的股票,只需将参数更改为函数 MovingAverageCrossStrategy()。
这仅仅是开始,有可能创造出更复杂的策略,这是我所期待的。
展望未来
- 结合更多基于指标的策略,如布林线、移动平均线收敛发散(MACD)、相对强弱指数(RSI)等。
- 使用适当的指标执行回溯测试,以评估不同策略的性能。
参考资料:
- QuantInsti 博客
- Investopedia
- 雅虎财经
- Clif Droke 简化的移动平均线
- 约翰·j·墨菲对金融市场的技术分析
你可能也想看看我的另一篇文章——
* [## 金融中的数据分析和可视化—使用 Python 对股票进行技术分析
如何使用 Pandas、Matplotlib、Seaborn 这样的 Python 库从股市数据中获取洞见?
towardsdatascience.co](/data-analysis-visualization-in-finance-technical-analysis-of-stocks-using-python-269d535598e4)*
使用 Plotly 为 Django HTML 页面制作漂亮的可视化效果
创建交互式可视化并不需要了解 Python 或 HTML
结果可视化,作者提供的图像
大家好!最近,我不得不为我的大学项目做一些可视化,我做了一些谷歌搜索,还没有找到任何关于如何在 HTML 页面上放置情节的简单指南。
在开始之前,我假设您已经运行了 Django HTML 页面。为什么是 Plotly?Plotly 允许你在几分钟内制作出互动,设计精美的情节。尽管最初 Plotly 是一个 Python 库,但我们今天不会使用任何 Python 编程。
对于那些没有太多时间的人,这里有一个简短的指南:
- 去 Plotly 图表工作室,创建你的账户。
- 点击“创建”按钮并选择“图表”。
- 导入您的数据,然后单击“跟踪”按钮。
- 选择您想要的绘图类型。
- 一旦你制作了你的梦境,保存它,设置所有的设置为“公共”。
- 通过从“嵌入”标签中复制 iframe 代码并将其粘贴到 HTML 页面的正文中来共享您的绘图。
现在,对于那些有时间的人来说,让我们详细看看我们如何才能得到相同的结果,就像你们在开始时看到的那样。
第一步。创建帐户并上传数据。

作者图片
我们将使用 Plotly 图表工作室。注册后,您会在右上角看到“创建”。
为了创建我们的可视化,我们必须首先导入我们的数据。数据可以是 CSV,单表 Excel 文件,链接到 CSV 文件或使用 SQL 和 Falcon SQL 客户端获得的数据。
上传数据后,您会在屏幕顶部的表格(红色方块)中看到它。

Plotly 工作室,作者图片
第二步。选择绘图类型并追踪数据。
现在让我们看看图片上的蓝色方块,并追踪一些数据。

作者图片
您可以在不同类型的地块之间进行选择。在这里,我选择了 Choropleth 地图集,因为它可以让我得到这个漂亮的地球可视化。
第三步。指定位置和值。
然后,您必须指定将用作位置和值的列。您还必须选择位置格式,因为它可以是国家名称或缩写等。

作者图片
在这里你可以看到我所有的设置,你可以用它来得到和我一样的结果。
第四步。保存和共享情节。

作者图片
我们快到了!单击“保存”按钮,并为绘图和网格选择“公共”。

作者图片
最后,你点击“共享”按钮,选择“嵌入”并复制 iframe HTML 代码,你可以在你的 HTML 页面的主体中传递这些代码。
感谢您的阅读!
利用 Hadoop、Hive、Parquet、Hue 和 Docker 在大数据领域取得重大进展
在这篇大数据简介中跳跃和奔跑

2020 年大多数大公司的数据是什么样的。说真的。
本文的目标是向您介绍大数据领域的一些关键概念。在阅读完这篇文章之后——可能还需要一些额外的谷歌搜索——你应该能够(或多或少)理解整个 Hadoop 是如何工作的。
因此,在本文中更准确地说,您将:
- 学习很多定义(耶)
- 通过 docker-compose,使用一些附加功能构建一个 Hadoop 集群。
- 了解拼花文件以及如何将 csv 数据集转换为拼花文件。
- 对您的拼花文件运行 SQL(技术上是 HiveQL,但它非常类似)查询,就像与 Hive 无关一样。
- 此外,预计有一些 Docker 和 docker-compose,运行 Python 脚本等基本知识。—没什么疯狂的,但如果你事先知道会更好。
如果你已经在使用 Hadoop 生态系统的替代产品——cool——这篇文章更适合那些由于工作、大学等原因必须熟悉 Hadoop 的读者。这只是大数据难题的一个“解决方案”,各有利弊。
大数据:这是一个大数据。大数据通常包括数据集,其大小超出了常用软件工具在可容忍的运行时间内捕获、筛选、管理和处理数据的能力。现在你可能会问一个简单的问题(很多人都问过):“大数据有多大?”坦率地说,这是一个非常困难的问题,取决于技术发展的速度,今天被认为是“大”数据的东西明天可能就是“小”数据。尽管如此,上面的定义是非常永恒的,因为它指的是超出常用工具能力的尺寸——这是你的参考线;因此,在 2020 年,让我们咬紧牙关,假设以下情况属实:当您开始处理数据库及以上数据库中两位数的 TB 数据集时,您可能会触及一些更普通的工具的极限,也许是时候研究分布式计算了,可能还有本文。
Hadoop: 一个框架,允许使用简单的编程模型在计算机集群上分布式处理大型数据集。它旨在从单个服务器扩展到数千台机器,每台机器都提供本地计算和存储。您应该了解的 3 个最重要的核心模块是:
- (存储)HDFS:一种分布式文件系统,同时具有高吞吐量访问和冗余(跨集群维护所有文件的副本)
- 又一个资源协商者:一个作业调度和集群资源管理的框架,例如哪些节点是可用的等等。
- (处理)MapReduce:一个基于 YARN 的大数据集并行处理系统。这是用于跨集群节点无缝分配计算任务的主要算法。你可以在网上阅读 MapReduce 的起源。流行的替代品是 TEZ 和 Spark,它们后来被开发出来用于更有效地处理数据。

在一张图中展示 Hadoop 生态系统的各个部分。现在关注 HDFS,纱,MapReduce 和蜂巢。
Hive: 一个数据仓库软件,使用 SQL 帮助读取、写入和管理驻留在分布式存储中的大型数据集。结构可以被投影到已经存储的数据上。提供了命令行工具和 JDBC 驱动程序来将用户连接到 Hive。因此,基本上 Hive 位于前面提到的 Hadoop 堆栈之上,它允许您在集群上直接使用 SQL。
Hue: 一个用于数据库的开源 SQL 助手&数据仓库,即一个用于查看 HDFS、Hive 等的简单 GUI。对于初学者来说非常方便!它由 Cloudera 维护,你可以在 GitHub 上找到它。
Parquet: 一种柱状存储*格式,适用于 Hadoop 生态系统中的任何项目。你可以在下面的解释中了解为什么这是一个关于大数据集的好主意。同样,有许多替代方案,但这项技术是免费的、开源的,并在整个行业的生产中广泛使用。
列存储:在普通的基于行的数据库(如 MySQL)中,数据是按行存储的,如果无法将数据存储在一个块中,这些数据将分布在不同的块中。现在,如果您的数据中有许多列和行分布在多个块中,那么事情会变得非常慢。这就是为什么您可以将每一列存储在单独的块中。在这种情况下,你可以通过访问一个块来访问一列的所有数据。此处对概念有更长的解释。正如 AWS 所言(与 Parquet 无关,但仍然正确):“数据库表的列存储是优化分析查询性能的一个重要因素,因为它大大降低了整体磁盘 I/O 需求,并减少了需要从磁盘加载的数据量。” 这里的也是对 CSV 的另一种比较,它显示了你可以节省多少存储空间,以及你可以期待什么样的加速。*

只是一个伟大的大白鲨参考,这是在这里只是为了照亮你的心情,如果文章已经太多了。
建造某物
好的。是时候做点什么了!即一个 Hadoop 集群,上面有 Hive,可以对存储在 HDFS 的 Parquet 文件运行 SQL 查询,同时在 Hue 中可视化所有内容。这句话现在比文章开头更有意义吗?酷毙了。
有很多方法可以做到这一点,Hadoop 以运行基于“商用硬件”构建的计算机集群而闻名,但由于这只是一个学习练习,所以使用 docker-compose 在 Docker 中快速构建一个具有上述堆栈的小型 Hadoop 集群会更容易一些——当然,您也可以在 Kubernetes 中这样做,但这超出了本文的范围。这里的设置甚至不会接近生产,但本文应该只是作为您大数据之旅的一个门户。
以下是这篇文章的回复:
[## tech 4242/docker-Hadoop-hive-parquet
这个项目将展示如何用 Hive 启动 Hadoop 集群,以便在 Parquet 文件上运行 SQL 查询…
github.com](https://github.com/tech4242/docker-hadoop-hive-parquet) 
资源库中 docker-compose 文件的更好视图,它应该粗略地勾勒出项目的架构。
Docker中实现的一些亮点
这并不像最初想的那么简单,所以如果你想进一步定制的话,这里有一些来自开发的提示。本文的重点也不是给你一个 Docker 和 docker-compose 的速成课程,所以这一节很简短,只强调一些你可能遇到困难的地方。
- 如果您想让任何东西与 Hue 一起工作,您需要通过挂载 hue-overrides.ini 文件来覆盖 Hue 的默认配置(您可以在 repo 和 docker-compose 中的覆盖中找到它)。很明显对吗?眨眼眨眼。
- 在 hue-overrides.ini 中,您应该看到:[[database]] = >这是内部的 hue 数据库,[[hdfs_clusters]] = >连接到 hdfs 以查看 Hue 中的文件,[[yarn_clusters]] = >设置 yarn 和[bewax]= >连接到 Hive 以运行 Hue 中的 SQL 查询。
- 如果在 hue-overrides.ini 中没有这一行 thrift_version=7 ,hue 将拒绝连接到 Hive (=Thrift)服务器,因为它默认为过高的 Hive 服务器版本。这花了几个小时。
- 如果您使用 Hue 的默认 SQLite DB,当您尝试连接到 Hive 时,将会得到“database locked”消息= >这就是 docker-compose 文件中有 db-hue Postgres DB 的原因。关于 SQLite 不适合多线程环境的一些事情在这里描述。Cloudera 应该处理他们的错误信息…
- hadoop-hive.env 中的 POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD 可以与官方 postgres Docker 映像一起使用,以便在启动容器时直接创建 DB 用户。检查。
- 注意你的 5432 端口,不要多次暴露它,因为 PGDB 为这个项目运行了不止一次(一次作为 Hive 的 metastore,一次作为 hue 的 DB)
TL;博士接下来的步骤
好的。对没有耐心的工程师来说,接下来会发生什么的简短总结:
- 用 docker-compose up 启动 Hue、Hive 和你的 Hadoop 节点
- 从 Kaggle 下载一个. csv 数据集,并使用提供的 Python 脚本进行转换
- 导入所说的拼花文件到 HDFS 通过色调和预览它,以确保一切正常
- 在使用 parquet-tools CLI 工具检查模式后,使用 Parquet 文件模式创建空的配置单元表
- 将文件从 HDFS 导入到 Hive 的表中
- 运行一些 SQL 查询!
启动集群,用 docker-compose 启动 Hue
好了,既然一切都已经设置好了,只需在您的计算机上克隆存储库,并在您的终端中键入 docker-compose up。就是这样。然后转到 localhost:8888,您应该(在设置 Hue 的初始密码后)看到这个屏幕:

这个屏幕显示了您的 Hadoop 集群的 HDFS,而侧栏显示了 Hive 的 metastore 中的 DB 表——在本例中这两个表都是空的。
在 HDFS 上传拼花文件并在 Hue 中预览
当试图在 Hue 中打开一些(相当多的)拼花文件时,您会得到以下错误消息:
“无法读取拼花文件”
在您的 docker-compose 日志中:
名称错误:全局名称‘snappy’未定义
事实证明,Hue 不支持 snappy 压缩,这是 pandas 等许多拼花转换工具的默认设置。除了重新创建您的拼花文件(如果他们使用 snappy)之外,没有其他解决方法。Cloudera 有史以来最差的 UX…
在 GitHub 存储库中,您将找到一个 parquet_converter.py,它使用 pandas 并指定压缩为 None,因此不会默认为 snappy,因为这会破坏 Hue。这意味着你可以从 Kaggle 中获取任何数据集。csv 格式,并使用提供的 Python 模块将其转换为 Parquet。
在这一点上——如果你不喜欢 CLI——最好的建议是你忘记色调,直接使用配置单元和 HDFS 为你的拼花文件。但是如果你像我一样坚持使用 Hue,你可以看到一份来自 Kaggle 的英国守时统计报告,它是用上面提到的 Python 脚本转换的,然后上传为一个文件:

当您单击成功导入的拼花文件时,文件浏览器显示为 Hue。你可以从左边黑色的边栏进入文件浏览器。
从您的 Parquet 文件和模式创建一个配置单元表
在看到您的数据被正确导入后,您可以创建您的 Hive 表。为此,您应该在您转换文件的文件夹(可能是/your_github_clone/data)中的命令行中运行以下命令:
工具模式 201801 _ 守时 _ 统计 _ 完整 _ 分析
这将输出创建色调表所需的模式(UTF8 =色调字符串):
消息模式{
可选二进制 run _ date(UTF8);
可选 int64 reporting _ period
可选二进制报告 _ airport(UTF8);
可选二进制 origin _ destination _ country(UTF8);
创建表格的时间:

您创建的新表格的预览。转到黑色侧边栏中的 DB 图标,使用上面描述的模式手动创建一个新表。然后点击黑色侧边栏中的导入按钮,将您的拼花文件导入到空桌子中。之后,您应该会看到上面的屏幕。
运行 SQL 查询
运行 SQL 查询是承诺过的,应该会实现。Hue 侧边栏的第一个图标是它的查询编辑器。
如果您想找到所有从波兰起飞的平均延误超过 10 分钟的航班,该怎么办?
SELECT * FROM 2018 _ 守时 _ 统计其中始发地 _ 目的地 _ 国家= '波兰',平均 _ 延误 _ 分钟> = 10;
编辑器中的自动完成特性非常棒,所以即使您是 SQL 新手,也应该能够轻松地处理数据。

最后。
该放手了
亲爱的读者,很遗憾你已经到了这篇文章的结尾。如果你觉得这个旅程应该有续集,请在下面的评论中写下。因此,概括地说,您学习了如何使用 Hive 运行 Hadoop 集群来运行 SQL 查询,同时使用 docker-compose 可视化 Hue 中的所有内容。还不错。
这当然是对 Hadoop 可能实现的功能的一个非常非常简化的介绍,但是您可能刚刚开始涉足这一领域,所以请给自己一些时间,在这些知识和基础设施的基础上进行构建。此外,还有很棒的在线课程,你接下来可以去看看。
展望 2020 年及以后
现在,如果你在过去几年中一直在收听 Hadoop 的生态系统,你就会看到市场上最大的两家公司——cloud era 和 Hortonworks — 大约在一年前合并了,当时 Hadoop 大数据市场发展缓慢。事实上,人们似乎对 Kubernetes 比对更老的 Hadoop 特定技术更感兴趣,如用于资源管理和编排的 YARN,对 PyTorch 等 DL 框架的快速采用,以及对老化的 Hadoop 堆栈的完美风暴的形成。尽管如此,像 Apache Spark 这样的项目仍在稳步前进,例如引入 Kubernetes 作为纱线的替代品。生态系统激动人心的时刻!
来源:
- 2020 年 1 月 17 日,里克·梅森在 Unsplash 拍摄的照片
- Hadoop 架构图:https://2 . BP . blogspot . com/-w7 keanwwnbq/WfYBJzgtvQI/aaaaaaaaaaamk/d 58 spzfk 7 lkj 8 qnknqzw 268 mkzrvuoonaclcbgas/s640/Hadoop stack . png,2020 年 1 月 23 日
- https://hadoop.apache.org/,2020 年 1 月 17 日
- 2020 年 1 月 17 日,https://hive.apache.org/
- 2020 年 1 月 17 日,http://parquet.apache.org/
- https://docs . AWS . Amazon . com/redshift/latest/DG/c _ column _ storage _ disk _ mem _ MGM nt . html,17.01.2020
- 斯尼德斯角;Matzat,u;美国大学 reips(2012 年)。“‘大数据’:互联网领域的知识大空白”。国际互联网科学杂志。7:1–5.
- 2020 年 1 月 19 日,https://pbs.twimg.com/media/BiZiNmXCAAA2n8U.jpg
通过 5 个简单的步骤使用人口普查数据制作酷地图
面向数据科学家的基础地理空间数据可视化

克里斯·劳顿在 Unsplash 上的照片
人类有 1100 万个感觉受体,其中 90%以上是光学审查者。这就是为什么数据的可视化表示如此重要,并且没有比制作地图更好的方式来表示数据。人们不常看到表格、饼状图和条形图,但他们每天都会用到地图。因此,地理空间分析是每个数据科学家工具箱中如此强大的工具。
使用人口普查数据库(Census.gov)这篇文章将演示如何制作简单的地图来可视化数据。该职位主要面向:a)希望学习空间数据表示基础知识的人,以及 b)对普查数据分析感兴趣的人。
所以让我们开始吧。
1.加载库
在继续之前,首先您需要有自己的 API 键来访问来自人口普查局 API 的数据。你可以在这里注册来获得你的密钥——这应该是一个快速的过程。
Python 是我处理所有数据的“首选”语言。除了两种情况——时间序列预测和地理空间分析。所以我用 r 做这个演示。
有相当多的 Rstat 软件包可以用来处理人口普查数据,但是tidycensus可以说是记录最完整的软件包,在网上有很多例子。除此之外,我还是绘制人口普查变量的tmap的忠实粉丝。因此,让我们在第一步加载所有的包!
库(tidysensus)
库(tmap)
库(tidyverse)
当然,您将使用census_api_key()函数加载您的 API 密匙。
census _ API _ KEY(" YOUR _ API _ KEY _ HERE ")
2.寻找正确的变量
人口普查局既是工厂(即制造商),也是仓库(即储存库),储存了美国人类生活几乎每个方面的大量数据集。许多数据是通过每五年一次的美国社区调查(ACS)收集的。
一旦您准备好启动您的 IDE,您需要知道您感兴趣的变量的正确标识符(ID)。如果你不知道如何访问变量 ID,这将是一个真正的挑战。这里有 3 个选项来找到合适的变量:
a)tidycensus中的[load_variable](https://walkerke.github.io/tidycensus/articles/basic-usage.html#searching-for-variables)()函数加载 RStudio 中的所有普查变量。从这里你可以搜索你正在寻找的变量。

b)使用acs包中的[acs.lookup](https://www.rdocumentation.org/packages/acs/versions/2.1.4/topics/acs.lookup)()功能

c)如果您不想在您的计算机中添加另一个软件包,可以从这里或这里轻松访问 25,000 个变量的列表。
3.获取数据
一旦你知道你在找什么,那么获取数据只是一行代码。我将提取马里兰州每个县的家庭收入中位数变量(ID: B19013_001)。
df
head(df)

The dataframe may look a bit messy and intimidating but all you need to care about are 4 columns: NAME (name of the state/county), variable (variable ID: median household income), estimate (the actual data you are looking for) and moe (margin of error).
The rest of the info in the dataset are basically metadata and geometry information for mapping purpose.
4. Mapping data
The data you fetched in the previous step has a geometry column in it for displaying on the map. And for that you’ll need another package. Of all the mapping packages out there I prefer 【 the most because it’s easy to write, read and interpret.
You can make two kinds of maps: a static map and an interactive map. You need to tell 【 upfront which kind do you want.
tmap_mode(“view”) # you can change “view” to “plot” for static map
Now you can add as many layers of other info to make your map pretty and beautiful by tuning mapping parameters.
tm_shape(df)+
tm_fill("estimate ",palette = "BuGn ",title = " Median income ")+
TM _ scale _ bar(breaks = c(0,25,50),text . size = 0.5)+
TM _ borders(" white ",LWD = . 5)+
TM _ bubbles(size = " estimate ",col = " green ")+
tmap _ options(BG . color = " white ",legend.text.color = "black ")

显示马里兰州所有县的家庭收入中位数的地图。
5.统计可视化
地图是可视化和交流数据空间变化的一种很好的方式,但有些东西在传统的数据可视化中表现得更好。例如,在上面显示的地图中,您看到了不同县的中值收入的全州分布,但如果您有一个类似于下图的图表,则更容易看到哪些县在顶部,哪些县在底部。
ggplot(data = df,aes(x = estimate,y = reorder(NAME,estimate))+
geom _ error barh(AES(xmin = estimate—moe,xmax = estimate+moe))+
geom _ point(color = " red ",size = 2)+
geom _ label _ repult(AES(label = estimate),size = 3) +
xlab("家庭收入中位数")+ ylab(")

可视化马里兰州所有 24 个县的中值家庭收入[这是第一次剪切的可视化,有点乱,需要做一些清理]。
这里不仅列出了估计收入,还列出了误差幅度。可以想象,统计可视化是地图表示的真正补充。
如果你有问题,请在下面的评论中写下,现在就可以开始了。我也在推特和 LinkedIn 上。
用风格转移让深度学习成为你的艺术家
"风格是我们每个人已经拥有的东西,我们需要做的只是找到它."— 黛安·冯·芙丝汀宝

为了用 CNN 对图像进行分类,我们需要首先提取特征,然后将这些特征输入到我们的分类器中。这些特征不仅有助于分类,也有助于图像重建,并且是风格转移和深度梦境的基础。由深度卷积神经网络的进步所驱动的计算机视觉算法已经能够提取图像的纹理、边缘、颜色和其他更高级的特征,并将这些特征融合到另一幅图像中。这个过程就是我们所说的风格转换。
Tensorflow page 将样式转移定义为:“神经样式转移是一种优化技术,用于获取两个图像——一个内容图像和一个样式参考图像(如著名画家的作品)——并将它们混合在一起,以便输出图像看起来像内容图像,但以样式参考图像的样式“绘制”
CNN 和 Images 背景下的内容和风格是什么?
如果我们有几层 CNN 堆叠在一起,随着我们在网络中深入,我们的 CNN 学会从图像中提取更复杂的特征,并在池层的帮助下丢弃那些对我们的图像分类无用的噪声。因此,我们在 CNN 网络中的图像的最后一层将理想地表示图像的内容,其中像像素颜色和纹理这样的细节已经被移除,并且我们留下了表示对象以及它在输入图像中如何排列的高级内容。换句话说,网络较高层中的特征表示被称为内容表示
图像中的样式代表了图像中的纹理、颜色和曲率。风格转移的目的是分离出艺术形象的风格(风格形象),并将其与内容形象融合或适应,以产生一种新的形象,称为目标形象。
我们如何隔离内容和风格?
这篇文章将描述 2014 年 CVPR 题为“使用卷积神经网络的图像风格转换”的论文中使用的方法

VGG19 架构(来源)
仔细观察上面的网络,可以看到它是由 5 个由最大汇集层分隔的 2 或 4 个卷积层堆叠而成。每个堆叠中的层的深度是标准值,但是深度随着堆叠从 64 增加到 512。网络通常接受彩色图像。在我们的例子中,彩色图像是内容图像、风格图像和目标图像。本文利用了来自 conv4_2 层的特征响应。可以使用任何更深的层,并且仍然获得一些好的结果。该算法的目标之一是最小化内容表示和我们想要产生的实际新艺术图像之间的差异。也就是说,新样式的图像(目标表示)和原始内容图像彼此非常接近,网络几乎会将它们视为同一图像。损失被表示为内容表示和目标表示的平均差。


由于我们使用预训练的 VGG19 网络,我们不需要进行任何训练来提取特征。我们只需要将内容和目标图像输入到网络优化中,使得它们之间的平均差异尽可能地接近。应该注意,我们的内容图像的内容表示没有改变。然而,目标图像的内容表示将继续改变,直到内容损失被最小化。
表示图像的样式有点复杂,但和前面讨论的内容表示一样简单。
通过计算每一层的相关性(相似性)来找到风格表示?每一层的相关性由一个 Gram 矩阵给出。让我们记住最大池层的工作是丢弃每个连续层的样式。因此,我们在丢弃发生之前获取特征图。
如何求克矩阵
让我们举一个例子,我们有一个 88 的图像与 20 个特征图或内核卷积。结果输出将是 2088。这意味着我们有 20 个特征图,我们想找到它们之间的相关性。为了找到这种相关性,我们首先需要对该特征图中的值进行矢量化(或多或少地将 2088 的 3 维重新成形为 2 维)。因为我们有 20 个 88 的向量,所以我们展平 88 图像的 x 和 y 维度,以给出 164 的长度,其现在表示特征地图。堆叠 20 行 164 的特征地图将得到 2064 的特征地图。现在,通过将 2064 特征图与其转置相乘来给出 gram 矩阵,以给出 2020 矩阵,该矩阵是我们的特征图的非局部化信息,其在正交空间中是不相关的。从上面我们可以看出,Gram 矩阵的维数只是一个平方矩阵,其维数是特征图的数目,并且不依赖于输入图像的维数。
Gram 矩阵的 x 行和 y 列简单地表示了图层中第 x 个和第 y 个特征图之间的相关性。由此,gram 矩阵的对角线将简单地具有相关值 1,因为在这种情况下,我们正在寻找特征图和它本身之间的相似性。
风格损失简单地被给定为我们的风格图像和目标图像的 gram 矩阵之间的均方差之和。目标是最小化这种差异。再次,表示样式图像的样式表示的样式图像的 gram 矩阵不变。然而,目标图像的样式表示将继续改变,直到目标被最小化。


每层中的权重 w 是给出某种偏好的值(根据层的不同,权重更大或更小)

上面给出的总损失函数是样式损失和内容损失的权重之和。但是,这两种损失的计算方式不同,大小也不同。因此,内容损失可能会对我们的目标图像产生更大的影响,我们希望确保这两种损失对最终目标图像的影响几乎相等。α和β在原始论文中被引入作为权重,用于使总权重显示内容损失和风格损失之间的平衡。实际上,β值总是比α值大。α-β比率越低,我们的最终目标图像将越有风格,因为这意味着在这种情况下β具有非常高的幅度。因此,Alpha 和 beta 是超参数,我们可以根据图像的类型和我们想要的结果输出风格来调整和选择。
对于本文中给出的例子,选择α为 1,β为 0.00001。

初始化目标图像
再次需要注意的是,目标形象是我们想要产生的新的艺术形象。我们可以使用任何随机噪声值来初始化图像,或者使其成为恒定的彩色图像或具有 0 的行和列的黑色图像,或者具有 1 的行和列的白色图像。在这项工作中,目标映像已经用内容映像的副本进行了初始化。
一些结果
下面的结果显示了我们试图实现最小化目标时的优化过程示例。我们会看到,如下图所示,这种风格正在逐渐被学习并在内容图像上进行调整。




最终的样式图像如下所示:

用于这项工作的代码可以在这里找到
最后一点:风格转移的应用
- 照片和视频编辑:我实际上已经使用了几个移动应用程序将样式应用到我的图像中,事实上,深度学习原理在这里很方便,它让我们了解后台可能发生的事情。
- 商业艺术:这里是另一篇有用的论文,题为“使用卷积神经网络的头像绘画风格转换”
- 游戏:你会发现这个视频很有趣,视频游戏看起来像另一个有风格转移的游戏。这里是另一个引人入胜的视频及其文章。
- 虚拟现实:这是一份报告的参考文献,展示了它在虚拟现实中的应用
参考
- Gatys、Leon A .、Alexander S. Ecker 和 Matthias Bethge。"使用卷积神经网络的图像风格转换."IEEE 计算机视觉和模式识别会议论文集。2016.
- Tensorflow 关于风格传递的文档:https://www . tensor flow . org/hub/tutorials/tf2 _ arbitrary _ image _ stylization
- 郑,于峰,Clifford Yang 和 Alex Merkulov。“使用卷积神经网络和后续数字乳腺摄影进行乳腺癌筛查。”计算成像 III 。第 10669 卷。国际光学与光子学会,2018。
- 用神经网络风格转移让《我的世界》看起来像其他游戏:https://www.youtube.com/watch?v=K4610QkRCnI
- EE267 虚拟现实,2018 春季 Style Transfer for VR:http://Stanford . edu/class/ee 267/Spring 2018/report _ lei _ Castillo . pdf
- Google Stadia-Style Transfer ML 演示:【https://www.youtube.com/watch?v=yF1bZiH-wJQ
- 观看令人印象深刻的演示视频中的谷歌 Stadia 将于 2019 年推出:https://twin finite . net/2019/03/Google-stadia-action-demo-videos/
- 使用卷积神经网络的头像绘画风格转换:https://dl.acm.org/doi/abs/10.1145/2897824.2925968
用文字地图制作热图:如何使用 Python 构建一个 Chloropleth
你有没有读过一篇新闻文章,读到一半时,你看到了一幅文章所讨论的任何内容的漂亮的图形表示?它是完美的——这是一张地理地图,某些区域阴影的深浅对应于该区域特定统计趋势的存在或强度。你心里想,“哇,真不错。我真的理解为什么他们说一张照片胜过千言万语。因为这篇文章只花了我五分钟的时间告诉我一些我可以单独从这张图中收集到的东西。强大。我敢打赌,你必须是某种数学奇才或计算机天才,才能弄明白如何制作其中的一个。”
我很高兴告诉你一些关于这个时刻的事情。第一,我完全同意你的观点;这些图表很简洁。它们被称为氯普图,它们可以提供大量的信息。你可能会比你意识到的更经常地看到这些(我们正处于美国最激烈的选举季节,所以我觉得我每周都要被它们轰炸好几次)。第二,你不需要成为一名电脑大师来制造一台电脑;事实上,用一些基本的 Python 技巧就可以很容易地构建它们。在博客的其余部分,我将向你展示如何制作这样一个图表,这样你就可以给你所有的朋友留下深刻印象。本指南将假设您对 Python 和 Pandas 包有基本的了解(如果您没有,您真正需要知道的是如何从您的计算机上打开一个 Jupyter 笔记本,并用您的计算机终端导航到文件夹;理论上你可以复制粘贴剩下的部分)。
第一步:安装 Geopandas
所以你需要做的第一件事就是安装一个名为 Geopandas 的新 python 包。这基本上只允许我们导入形状文件,并使用 Python 绘制图形。要安装 Geopandas ,只需在您的终端中运行以下代码行:
conda install geopandas
您将看到软件包下载,好消息,您已经上路了!
第二步:获取一些数据
接下来,我们要下载一些数据来使用。你想做什么地图?!因为我住在纽约州的布鲁克林,而且这里每个人脑子里无处不在的话题是新冠肺炎,所以我将使用我在下面的 GitHub 页面上找到的一些最近的测试数据:https://github.com/nychealth/coronavirus-data
具体来说,我将使用每个邮政编码最近的正 COVID 测试率,并将它们绘制在纽约市的地图上,该地图恰好按邮政编码划分。
您确实可以使用任何您想要的数据,但是对于您自己的修补,您至少需要在您的数据中有一个. csv 文件和一个. shp 文件。第一个是您想要使用的类似电子表格的实际数据列表,第二个是实际绘制地图的形状文件。你要确保你的。csv 文件。shp 使用相同的惟一键对地区进行分类(在我的例子中,这些惟一的地区是邮政编码)。将这些文件下载到计算机后,打开终端,导航到包含这些项目的相应文件夹,然后运行以下代码:
jupyter notebook
您应该会看到类似下图的内容。只是为了检查一下你的。csv 和。shp 文件应该列在屏幕的左侧:

在这个页面中,通过点击右上角的“new”按钮创建一个新的 Python 笔记本,我们终于可以开始构建我们的图表了。
第三步:导入 Python 中的相关包和文件
在我们的笔记本中,我们希望首先导入相关的 Python 包和我们下载的数据。为此,请使用以下代码:
# import relevant packages
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt# import relevant data
nyc_map = gpd.read_file("Geography-resources/MODZCTA_2010.shp")
stats=pd.read_csv("recent/recent-4-week-by-modzcta.csv")
如果您使用自己的数据,只需确保用您实际的文件路径/名称替换最后两行中引号内的文本。作为参考,分配包含在我的。csv 文件中的数据保存到名为“stats”的变量中。shp 文件保存到名为“nyc_map”的变量中。如果您要查看我们刚刚导入的任何一个文件,它们看起来会像这样:

我的。csv 文件

我的。shp 文件
这里我想让大家注意两件事。首先,浏览一下我的“几何”专栏。shp 文件。你会看到它看起来有点像一个坐标列表。差不多就是这样。存储在该列中的是 Geopandas 绘制一个形状(或者在我们的例子中是多个形状)所需的所有几何数据。其次,检查“MODZCTA”列,注意这个列出现在我的文件的和中。这些是我前面提到的唯一的区域键,它们很重要,因为它们允许我们将。csv 文件中的几何数据。shp 文件。
第四步:准备绘图数据
那么,我们如何执行这种数据婚姻呢?我们将通过合并两个表来创建一个包含地理和统计数据的新数据框架。我们使用以下代码来执行此操作:
map_and_stats=nyc_map.merge(stats, on="MODZCTA")
在这里,我把我的“纽约市地图”数据(的。shp 文件),并使用“MODZCTA”列中的邮政编码,附加我的“stats”中的所有数据。csv 文件)。我将这个新表命名为“map_and_stats”(我知道这很有想象力)。我们可以看看新的数据框来验证:

我的组合“地图和统计”数据框架
看看吧,我们现在把所有信息都放在一个地方了。我们准备好策划了。
第五步:绘制数据
好了,我们一直在等待的时刻,我们数据的实际绘图。首先,我们要建立我们的情节和大小(我使用 8“x8”大小)。我还将把我们的 x 轴标签旋转 90 度,只是为了让内容更具可读性。我们用下面的代码实现了这一点:
fig, ax = plt.subplots(1, figsize=(8, 8))
plt.xticks(rotation=90)
接下来,我们希望专门绘制上一步中连接的新数据帧中的数据。具体来说,我想看看我的数据中名为“最新利率”的一栏。您可以在这里调整其他属性(线条粗细、阴影颜色等。),但我会把它留给你们去玩。该图形的代码如下:
map_and_stats.plot(column="Latest Rates", cmap="Reds", linewidth=0.4, ax=ax, edgecolor=".4")
当我们执行此操作时,会得到下图:

纽约市的 COVID 检测率
很酷,是吧?我们也可以做一些装饰。标题、轴标签等。可以像添加其他支线剧情一样添加,但是让我们在这里添加一个颜色标尺,这样我们就可以告诉人们这些红色的阴影实际上意味着什么。我们可以通过下面的代码实现这一点:
bar_info = plt.cm.ScalarMappable(cmap="Reds", norm=plt.Normalize(vmin=0, vmax=120))
bar_info._A = []
cbar = fig.colorbar(bar_info)
您需要注意的是,色阶的界限是通过上面看到的“vmin”和“vmax”属性设置的。在我的数据中,最大的阳性测试率大约是 100,所以我决定将我的最大值设为 120。在任何情况下,如果您现在绘制图表,您可以看到以下内容:

纽约市使用色标的 COVID 测试率
哇,看看我们看起来多专业。我们有了这张图,但是假设我对其中的某个部分感兴趣。再说一次,我住在布鲁克林,所以也许我想放大那个地区。我们可以通过在图表上设置 x 和 y 的极限来达到这个目的。你可以在轴上看到,我们有类似坐标的数字,Geopandas 用来绘制我们的地图。我们使用这些相同的坐标来有效地放大感兴趣的区域。我要查看的区域在 x 轴上介于 970000 和 1010000 之间,在 y 轴上介于 140000 和 200000 之间,因此我将使用以下代码将我们的图像限制在这些范围内(然后出于美观的原因关闭我们的轴):
ax.set_xlim(970000, 1010000)
ax.set_ylim(140000, 200000)
ax.axis("off")
当我们执行时,我们得到下面的图形:

布鲁克林的 COVID 测试率与色标
太棒了,对吧?现在你要做的就是保存你的形象,打印出来,向你所有的朋友和家人吹嘘你有多专业。
默认情况下使 Matplotlib 美观
使用 Seaborn 来控制 Matplotlib 默认值(永远忘记蓝色的阴影)

我的网站的背景图片——用 Matplotlib 创建
如果你曾经用 Python 做过数据可视化,那么你很可能用过 Matplotlib。这是一个意见分歧的方案。一些概念上简单的可视化需要惊人数量的代码来生成。在这个时代,人们希望能够与图表进行交互——这是普通 Matplotlib 所不具备的。而且,也许最重要的是,Matplotlib 图表通常看起来很简单不好。
诚然,默认的 Matplotlib 设置可以让你的视觉效果看起来很简单,如果不是有点过时的话(如果我们很大方的话)。它默认的蓝色阴影萦绕在许多数据科学家的梦中。


然而,Matplotlib 被低估的一个方面就是它的可定制性。远离上面的例子,您可以创建非常复杂的视觉效果(不可否认,这个例子需要许多行代码,并且大部分数据科学家很少有时间)。

更重要的是,我们可以编写一些相关的代码来设置默认的视觉设置。我们可以变得非常精细。不想让那个讨厌的盒子围着每一个情节?默认去掉。想使用你品牌的调色板,而不必每次都指定十六进制代码?默认设置它们。想在所有图表标签中使用漫画字体吗?寻求专业帮助(尽管你也可以默认设置,如果你坚持的话)。
处理色彩
尽管 Matplotlib 中有命名的颜色(如众所周知的颜色‘bisque’,‘lavender blush’和‘lightgoldendoryellow’),但绘图也将采用十六进制代码形式的颜色。如果我们想使用自定义调色板,这尤其有用。例如,我的 CB91 品牌使用一组预定义的颜色。

我们可以将它们设置为变量,将它们的六进制作为字符串传递:
*CB91_Blue = '#2CBDFE'
CB91_Green = '#47DBCD'
CB91_Pink = '#F3A0F2'
CB91_Purple = '#9D2EC5'
CB91_Violet = '#661D98'
CB91_Amber = '#F5B14C'*
注意——如果你想创建自己的调色板,网上有一些有用的工具可以帮助你。Colormind.io 特别酷——它使用深度学习从照片、电影和流行艺术中学习颜色风格,从而推荐搭配良好的色调和阴影。此外,我可以确认,作为一个英国人,在“颜色”和“色彩”之间不分青红皂白地切换已经导致了我这段时间内一些令人深感烦恼的代码错误。
我们可以将这些定义的颜色放入一个列表中,然后将这个列表传递到 Matplotlib 的颜色“cycler”中。
*color_list = [CB91_Blue, CB91_Pink, CB91_Green, CB91_Amber,
CB91_Purple, CB91_Violet]plt.rcParams['axes.prop_cycle'] = plt.cycler(color=color_list)*
现在,它将使用“CB91_Blue”作为笔记本中所有绘图的默认图表颜色,并在创建多类别绘图时按顺序在颜色列表中循环。

你也可以使用十六进制颜色列表来定义渐变,这可以在任何地方使用,只要 viridis 是一个有效的条目(例如 Seaborn heatmaps)。当然,为了让这些渐变更好更平滑,你需要在列表中定义很多十六进制值(根据我的经验,至少 40 个)。手动创建这么长的列表可能会很痛苦——我建议使用类似 colordesigner.io 这样的网站自动生成一个列表(只需选择你希望渐变过渡的颜色,最大化渐变步骤的数量,然后从结果 HTML 中提取十六进制代码)。
编辑:彼得·卡希尔写了一个 Python 函数,可以在两个颜色六边形之间用 n 步生成渐变列表——请看下面这篇博客的回复。
这是我品牌的两种颜色之间的渐变示例,以及它们在 matplotlib 图表上的外观。
***#A list of hex colours running between blue and purple**
CB91_Grad_BP = ['#2cbdfe', '#2fb9fc', '#33b4fa', '#36b0f8',
'#3aacf6', '#3da8f4', '#41a3f2', '#449ff0',
'#489bee', '#4b97ec', '#4f92ea', '#528ee8',
'#568ae6', '#5986e4', '#5c81e2', '#607de0',
'#6379de', '#6775dc', '#6a70da', '#6e6cd8',
'#7168d7', '#7564d5', '#785fd3', '#7c5bd1',
'#7f57cf', '#8353cd', '#864ecb', '#894ac9',
'#8d46c7', '#9042c5', '#943dc3', '#9739c1',
'#9b35bf', '#9e31bd', '#a22cbb', '#a528b9',
'#a924b7', '#ac20b5', '#b01bb3', '#b317b1']*

调整轴
Matplotlib 最好的特性之一是一个完全不同的包; Seaborn 。Seaborn 是一个使用 Matplotlib 作为基础的库,是创建更复杂图表类型的好方法,比如用一两行代码创建热图、小提琴和联合图表。

一个 Seaborn 热图的例子,它可以接受十六进制颜色列表作为它的 cmap 参数。
Seaborn 的一个鲜为人知的特性是它能够使用。set()方法。这是一个整理绘图的好方法,可以改变坐标轴的颜色和粗细(或者完全删除它们)以及默认字体。我们也可以使用。set_context()方法来微调字体大小设置。
下面是我如何使用所有这些的一个例子(一个完整的列表,列出了您可以使用。set()方法可以在 Matplotlib 的自带教程中找到关于此事的)。
***import** matplotlib.pyplot **as** plt **import** seaborn **as** snssns.set(font=’Franklin Gothic Book’,
rc={
‘axes.axisbelow’: False,
‘axes.edgecolor’: ‘lightgrey’,
‘axes.facecolor’: ‘None’,
‘axes.grid’: False,
‘axes.labelcolor’: ‘dimgrey’,
‘axes.spines.right’: False,
‘axes.spines.top’: False,
‘figure.facecolor’: ‘white’,
‘lines.solid_capstyle’: ‘round’,
‘patch.edgecolor’: ‘w’,
‘patch.force_edgecolor’: True,
‘text.color’: ‘dimgrey’,
‘xtick.bottom’: False,
‘xtick.color’: ‘dimgrey’,
‘xtick.direction’: ‘out’,
‘xtick.top’: False,
‘ytick.color’: ‘dimgrey’,
‘ytick.direction’: ‘out’,
‘ytick.left’: False,
‘ytick.right’: False})sns.set_context("notebook", rc={"font.size":16,
"axes.titlesize":20,
"axes.labelsize":18})*
把所有的放在一起
当然,如何构建回购是一件非常私人的事情。我发现把所有讨论过的代码放在一个 Jupyter 笔记本的顶部会很不整洁——特别是当你需要设置多个不同的渐变和它们相关的 40+十六进制代码列表的时候。此外,如果您在一个 repo 中有多个笔记本,如果您想要对可视化默认设置进行更改,保持一致性可能是一件痛苦的事情。
为了解决这些问题,我喜欢将所有与可视默认值相关的代码保存在 repo 中其他地方的一个单独的 python 文件中(名为' cb91visuals.py '),然后将它们作为标准导入的一部分导入到每个笔记本的顶部。因此,所有乱七八糟的十六进制代码列表都是隐藏的,如果您确实需要进行编辑,只需在一个地方完成,更改会根据需要自动反映在任何地方。
****#Bring in data visualisation libraries as usual***
**import** matplotlib.pyplot **as** plt
%matplotlib inline
**import** seaborn **as** sns***#Bring in our custom settings
#Assumes that cb91visuals.py is in the repo's root folder*
from** cb91visuals **import** **
杂项提示
还有一些我经常使用的不太为人所知的 Matplotlib/Seaborn 命令。我倾向于不将它们设置为默认值,但是它们仍然很有用。
- 图例框架:图例周围的小方框通常是不必要的,会增加视觉上的混乱。这些可以通过以下方式关闭:
*plt.legend(frameon=**False**)*
- 去自旋:有时候我们想要移除一个轴,比如在条形图上。这是通过 Seaborn 的 despine 方法完成的(根据需要指定左、右、上或下):
*sns.despine(left=**True**, bottom=**True**)*
- 条形图上的数字标签:一个应该作为软件包的一部分提供的特性,你可以用 for-looping 和 Matplotlib 在条形图顶部添加数字标签。text()方法。例如,下面的代码…
****#Here, 'labels' refers to the bigrams on the y-axis
#i.e. 'Look forward', 'Jó éjt', etc.
#and X is the list of values determining bar length******#Loop through these labels***
for n, i in enumerate(labels): #**Create an axis text object**
ax.text(X[n]-0.003, ***#X location of text (with adjustment)***
n, ***#Y location***
s=f'{round(X[n],3)}%', ***#Required label with formatting***
va='center', ***#Vertical alignment***
ha='right', ***#Horizontal alignment***
color='white', ***#Font colour and size***
fontsize=12)*
…将数字标签放在水平条形图上,例如几周前我的博客中的图。注意,为此我还使用了 sns.despine()方法来移除 x 轴,并传递了 plt.xticks([])来移除轴刻度。

感谢一路看完博客!我很乐意听到任何关于以上的评论,或者这篇文章涉及的任何概念。如果你还有其他的 Matplotlib 小技巧和窍门,欢迎在下面留言,或者通过LinkedIn联系我。
让麦当劳健康
用 Python 和 Pulp 实现数学优化的方法

Joiarib Morales Uc 在 Unsplash 上拍摄的照片
麦当劳是一个超级健康的选择!没有人曾经
如果你问任何人他们对在麦当劳吃饭的感觉,标准的回答是他们喜欢吃,但知道他们不应该一直吃。麦当劳被吹捧为众所周知的不健康,甚至导致摩根·斯普尔洛克拍摄了一部名为超码我的纪录片,讲述了每天在麦当劳吃饭如何导致非常严重的健康问题。
这是我的问题。当然,如果你一天吃三个巨无霸,你的心脏会爆炸,但这可能是许多餐馆的真实情况。我想要确定的是
麦当劳菜单项目的最佳组合实际上严格遵循了一些营养指南
这种健康组合会是什么样的呢?
为此,我求助于线性优化和 python 的威力。我们要彻底解决这个问题,所以坐好!
数据和假设
这个旅程的第一步是从麦当劳找到菜单数据。我看了一下 Kaggle,这是一个数据科学网络平台,有许多有趣的开源数据集。快速搜索之后,我可以很容易地找到一份表格格式的完整菜单[1]。它包括卡路里的数量、食物的种类(饮料、汉堡等)以及所有的宏量营养素,如钠、脂肪的含量。
第二部分是找到一个合法的来源,告诉我们什么是健康饮食。另一个快速的谷歌搜索,我能够找到 NHS 提供的营养分类。按照他们的说法,一个普通人每天需要的基本消耗量是:
能量:约 2000 千卡
总脂肪:< 70 g (Saturated < 20g)
Carbohydrates >260 克
糖:约 90 克+-10 克
蛋白质:约 50 克+-10 克
钠:< 6g
So now I have the menu and I have my nutrition targets. The question is how do I find the optimal combination of meal items to be health? Well, this is where the magic of Linear Programming comes in. It’s a nice technique that is adaptable to this problem and implemented in the 浆蟒包。我们真正需要知道的是你的极限是什么(上面的营养数据)和我们的变量宇宙(麦当劳的菜单项目)。谁渴望…真相!
篡改数据
首先,我们确保已经使用我们的老朋友 pip: 在 python 中安装了纸浆包
pip install **pulp**
安装完成后,我们可以继续导入我们的软件包:
import numpy as np
import pandas as pd
from pulp import *
import plotly.plotly as py
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import plotly.graph_objs as go
import matplotlib.pyplot as plt # matplotlib
import os
接下来,我们将简单地将数据集加载到 pandas 数据框对象中:
McData = pd.read_csv('../input/menu.csv')
只是为了好玩,我们可以使用 Plotly 包来了解数据。让我们来看一张碳水化合物与卡路里的图表,按菜单项类型进行着色。为此,我将首先定义一个新函数,用 Plotly: 制作一个散点图
**# The function creates a Scatter graph object (go) and uses the data frame .isin() selection to extract the requested information**
def make_scatter(McData,category,x_cat,y_cat):
return go.Scatter(
x = McData[McData['Category'].isin([category])][x_cat],
y = McData[McData['Category'].isin([category])][y_cat],
mode = "markers",
name = category,
text= McData.Item)
现在我们可以看看几个相互关系。正如我上面所说,让我们找到卡路里与碳水化合物:
**# Define our categories to plot** x_cat = 'Calories'; y_cat = 'Carbohydrates'**# Create a list of scatter plots to view all at once** data = [make_scatter(McData,cat,x_cat,y_cat) for cat in
McData.Category.unique().tolist()]**# Define the plot layout (title, ticks etc.)**
layout = dict(title = 'McDonalds Nutrition',
xaxis= dict(title= 'Calories',ticklen=5,zeroline= False),
yaxis= dict(title= 'Carbohydrates(g)',ticklen= 5,zeroline=False))**# Finally we will plot the data with the layout**
fig = dict(data = data, layout = layout)
iplot(fig)

似乎相当线性!
让我们再做一个。钠 vs 脂肪怎么样?

又是一个很好的线性关系!
现在我们对数据有了一个概念,我们可以继续设置优化代码来帮助我们从变量(菜单项)的离散集合中进行选择。
我们将使用线性规划作为优化方法。我在这里不再赘述细节,但当目标函数中没有高阶相关性时,这是一种非常快速的计算方法。
首先要做的是定义我们的目标函数。目标是我们试图最小化或最大化的东西。在这种情况下,假设我们想摄入所有的营养常量营养素,但是,我们也想减少卡路里。
我们的目标是尽量减少卡路里
接下来,我们必须定义我们的约束。因为我们知道每天的摄入量应该基于什么[2],我们可以将它们作为优化的约束条件。在一个完美的世界中,你将消耗零卡路里并获得所有需要的营养(显然这在许多方面是不现实的),因此为了将这一点纳入优化,我们定义如下:
将数据转换为字典,这是约束变量进入优化函数的方式:
**# Convert the item names to a list**
MenuItems = McData.Item.tolist()**# Convert all of the macro nutrients fields to be dictionaries of the item names**
Calories = McData.set_index('Item')['Calories'].to_dict()
TotalFat = McData.set_index('Item')['Total Fat'].to_dict()
SaturatedFat = McData.set_index('Item')['Saturated Fat'].to_dict()
Carbohydrates = McData.set_index('Item')['Carbohydrates'].to_dict()
Sugars = McData.set_index('Item')['Sugars'].to_dict()
Protein = McData.set_index('Item')['Protein'].to_dict()
Sodium = McData.set_index('Item')['Sodium'].to_dict()
如果我们打印出来,约束的格式应该是这样的;例如,钠:

约束字典的输出示例
现在我们已经有了正确格式的所有数据,我们可以继续设置优化器了!
设置优化器
在本例中,我们正在进行 最小化 优化:
**# Set it up as a minimization problem**
prob = LpProblem("McOptimization Problem", LpMinimize)
此外,我们可以告诉优化器我们只对整数解感兴趣。即。我们会说一个项目只有 0.5 是不可能的(没有半个芝士汉堡)。除此之外,我们还可以为解决方案选择最大和最小数量的项目:
MenuItems_vars = LpVariable.dicts("MenuItems",MenuItems,**lowBound=0**,
**upBound=10**,cat='**Integer**')
你看到我们如何给出 0 的下界和 10 的上界了吗?如果我们不这样做,菜单上可能会有 负 项。这就像通过…把你吃的东西还给你来抵消它。咱们别这样。然而上限有点宽松,只是说我们不会购买超过 10 的单一项目。
此时,我们可以继续将约束输入到运行中:
***# First entry is the calorie calculation (this is our objective)**
prob += lpSum([Calories[i]*MenuItems_vars[i] for i in MenuItems]),
"Calories"**# Total Fat must be <= 70 g**
prob += lpSum([TotalFat[i]*MenuItems_vars[i] for i in MenuItems]) <=
70, "TotalFat"**# Saturated Fat is <= 20 g**
prob += lpSum([SaturatedFat[i]*MenuItems_vars[i] for i in
MenuItems]) <= 20, "Saturated Fat"**# Carbohydrates must be more than 260 g**
prob += lpSum([Carbohydrates[i]*MenuItems_vars[i] for i in
MenuItems]) >= 260, "Carbohydrates_lower"**# Sugar between 80-100 g**
prob += lpSum([Sugars[i]*MenuItems_vars[i] for i in MenuItems]) >=
80, "Sugars_lower"
prob += lpSum([Sugars[i]*MenuItems_vars[i] for i in MenuItems]) <=
100, "Sugars_upper"**# Protein between 45-55g**
prob += lpSum([Protein[i]*MenuItems_vars[i] for i in MenuItems]) >=
45, "Protein_lower"
prob += lpSum([Protein[i]*MenuItems_vars[i] for i in MenuItems]) <=
55, "Protein_upper"**# Sodium <= 6000 mg**
prob += lpSum([Sodium[i]*MenuItems_vars[i] for i in MenuItems]) <=
6000, "Sodium"*
现在,我们运行求解器(希望)找到超级健康的最佳菜单项集!
***# Tadaaaaa** prob.solve()*
快速检查以确保它确实找到了解决方案:
*print("Status:", LpStatus[prob.status])*

休斯顿。我们有健康的麦当劳套餐。
终于!我们来看结果!
***# Get the total calories (minimized)**
print("Total Calories = ", value(prob.objective))**# Loop over the constraint set and get the final solution** results = {}
for constraint in prob.constraints:
s = 0
for var, coefficient in prob.constraints[constraint].items():
sum += var.varValue * coefficient
results[prob.constraints[constraint].name.replace('_lower','')
.replace('_upper','')] = s*
结果是……
总热量: 1430

我们的最终优化显示,一个 McHealthy 组合超级超级无聊!
有请麦克健康组合!主要是苹果、沙拉和燕麦片。确实很无聊。这表明,粉丝最喜欢的巨无霸和薯条不是超级健康的选择,因为它们富含特定的营养物质和高热量,会破坏整体优化。
这是一个非常有趣的项目,所以如果你有任何要求或想法,请让我知道!
参考和链接
[1]https://www.kaggle.com/mcdonalds/nutrition-facts
[2]https://www . NHS . uk/live-well/eat-well/what-are-reference-摄入量-食品标签/
[3]https://www . ka ggle . com/kapastor/optimizing-McDonalds-nutrition
制作模型:评估和内核的炸鸡
理解大数据

当我想到构建数据科学能力时,我经常会回到 Harlan Harris 2011 年的一篇文章。哈里斯提出,数据科学的职业道路是由来自不同学科的从业者定义的,其受欢迎程度与棒球(即钱球)中 sabermetrics 的兴起相同,即在定量分析中应用人才的异国组合可以产生优于直觉的结果。
我倾向于同意;数据科学是一个不寻常的领域。它是深度的(结合了研究方法、统计学、机器学习和计算机科学;大量定义性 论文 存在)和后果性(无论是指导性决策还是构建产品,数百万客户都受到影响)——但它也很容易理解。每一门学科,作为一门独立的专业,都需要数年才能掌握;然而,数据科学作为这些部分的总和似乎更容易参与——如今,新的从业者可以在训练营或 MOOC 后短短三个月内培养出来。
在一个具有如此多样从业者背景的领域中的能力发展引起了有趣的讨论。有多严谨才能在数据科学中有效?一个特别的问题不断出现——我们需要多深地理解一个分析模型的黑箱?
“但我们正在做所有正确的事情”
蓬勃发展的资源带来了一定程度的效率,一些人认为这消除了学术严谨的必要性。打包的框架、社区平台和现成的建模、技术形成了绕过正式培训、直接进入即插即用以获得即时模型满足的诱人主张。任何有网络连接的人都有大量的机会参与分析建模;事实上,在加入开源数据科学社区时,一个被 宠坏了选择;如今,构建一个合理的模型就像一个 jupyter 笔记本(和一些 StackExchange 线程)一样简单。
然而,值得注意的是这种简单的资源访问的副产品:过程建模——其中更加强调遵循过程而不是推理本身的质量。虽然有有用的教程可以帮助新的实践者通过普通的实践,但是它可能导致过程完成被误认为是好的建模。根据我的经验,许多人很好地描述了教科书式的过程,但在面对非教科书式的情况时却做出了特殊的选择——例如即使在有限的样本上也默认使用神经网络(因为“神经网络具有更强的预测能力”),或者得出水是湿的式的结论,如“任期是流失的最强预测因素”——这就提出了模型是否实际可用的问题。

概括地说,无数的建模技术,无论是用于统计还是数字用途,都是通过“模型”将输入信息映射到输出,即真实(未知)现象的表征。模型的可用性——无论是模型的准确性、解释力还是预测性能——都受到模型如何被估计的严重影响。所以让我们花点时间来解开这个谜团。*
果仁炸鸡
在估计过程中,数据通过算法程序运行,以获得一些映射,作为实际上链接输入和输出的看不见的关系的“最佳猜测”(或估计)。虽然有时被比作“机器学习”的“学习”部分,但“估计”和“学习”之间存在着的区别。在“估算”中,“估算者”可以被认为是一种获得估算值的算法方法。例如,最大似然估计(MLE)产生的模型参数最大限度地提高了观察到数据的概率,假设你的模型反映了现实(如果你觉得这是倒退,贝叶斯会同意)。
更粗略地说,我认为评估就像我认为对我喜欢的食物的配方进行逆向工程一样,比如说,肯德基。饥渴的建模者可以看两种***方法来做到这一点。
参数估计:
- 我们假设有 11 种药草和香料,并且我们知道它们是如何影响风味的(两个大的假设)。
- 然后我们运行一系列的测试厨师,品尝和调整我们对相对配料数量的猜测在每次品尝测试之后,基于我们假设的风味特征。
- 最终模型:根据假设的风味特征,该食谱尝起来与肯德基的(在所有测试中)差别最小吗
非参数估计:
- 我们不会假设有多少香草和香料,或者它们如何影响风味。
- 然后,我们运行一个(巨大的)系列测试厨师,从我们的餐具室中随机挑选配料和数量组合,而不假设任何特定的风味特征
- 最终模型:是我们所有口味测试的平均值,用我们认为每个尝起来像肯德基的程度来加权

图片作者。几年前我的非参数估计炸鸡。
不严格地说,参数估计是基于统计假设的,而非参数估计是从可用信息中强行提取结论。在这个例子中,负责解释为什么他们的食谱如此指定的建模者可能更喜欢参数方法,因为它用味道匹配的接近程度来换取对其结论的清晰解释。但是建模者只对与肯德基最接近的匹配感兴趣,并且财力雄厚,可能选择使用非参数估计。
根据各自的优缺点,每种估计方法产生不同的成分估计值。两个“模型”都不会完全复制原件;这种差异源于不完善的假设,不完全代表肯德基成分的样本,或者两者的结合。然而,普遍未知的是真正的肯德基食谱本身——我们建立的每个模型都是一个“知情的估计”,基于其制造商选择优先考虑的具体条件。
为什么估计性思维很重要
我认为理解评估的重要性与具体的技术细节关系不大,,而与深思熟虑地处理分析得出的决策关系更大。
仅仅接受所有模型都是现实的代理是不够的;相反,这一知识应该促使我们思考“炸鸡是如何制作的”以及如何使其食用安全。我想到了几件事:
- 考虑底层 数据生成过程【DGP】。在选择合适的估计量时,建模者还应该考虑他们正在处理的数据的性质。理解估计有助于指导将适当的工具应用于问题——例如,表现良好的现象(如保险问题中的风险率)非常适合参数方法;而消费者选择的高度可变性质可能要求使用非参数贝叶斯方法。
- 寻求暗示:决策者应该时刻注意他们的建模选择意味着什么。例如,劳动力计划经理应该记住 ARIMA 需求预测模型(由于简单的参数属性)在复活节等可变日期事件上的预测不如在圣诞节等固定日期事件上的预测。同时,如果使用稀疏数据,一个有见识的建模者将从评估参数模型相对于非参数模型的稳定性中获益。
- 谨慎的模型使用:由此可见,我们对评估的理解应该有助于提高我们使用模型的方式。例如,一个计划经理,在需求预测模型产生不良估计的条件下接受教育,可以在这些条件下建立替代决策规则。从模型管理的角度来看,技术度量——比如模型重新评估的性能阈值,或者模型接受的收敛标准——可以根据评估框架进行定制。

由克里斯·利维拉尼在 Unsplash 上拍摄的照片。让我想起了在时间序列数据中寻找平稳性。
也许最重要的是记住“所有的模型都是错的,但有些是有用的”。
远离象牙塔中的数学纯粹性;因为我们肯定无法描述现实,所以实践的严格性对于维持有意义的数据科学是必要的。随着它对商业和社会决策的影响越来越大,我们必须让我们的员工具备良好实践的基础。坚持培养好奇心——对于模型是如何建立的以及这对推理意味着什么——将保护我们远离程序建模,并让我们建立有用的模型。
*在这里,我们将参考有监督(与无监督相对)环境中的模型
**我不为肯德基工作,但我确实喜欢美味的炸鸡。
***在这两种方法之间还有半参数估计的怪异而奇妙的世界,但为了简洁(也为了理智起见),我们不会深入探讨。
使用 datasette 使开放数据更易访问

加利福尼亚州最近发布了与该州八大机构官员在 2018 年 7 月至 12 月期间进行的拦截有关的数据。这是将在未来几年生效的第一波数据发布。数据覆盖了全州 180 多万个站点。虽然这是朝着正确方向迈出的一步,但一个大约 640 兆字节、180 多万行和 140 多列的文件可能会让一些从探索这些数据中受益的人感到害怕:地方领导人、记者、活动家和组织者,等等。
开放数据宪章的第三个原则是数据应该可访问和可用。提供数据是第一步,但为了让大多数人能够使用和访问数据,我们不能简单地发布数据;我们必须考虑到用户体验,并开发出便于探索和使用这些数据的方法。
在本教程中,我分享一种方法:使用dataset,一种用于探索和发布数据的 python 工具。它帮助人们获取任何形状或大小的数据,并将其发布为一个交互式、可探索的网站和附带的 API。”
我们采用加州最近发布的警察停车数据,清理和转换数据,并向 Heroku 部署一个 datasette 实例。
目录
— 序幕
— 关于数据
— 关于数据集
— 分步
—获取数据
—准备数据
—服务数据
— 部署到 heroku
— 自动化一切
序言
探索这个数据集的想法来自于听 2020 年 3 月 3 日的一集 Pod 拯救人类
本周,DeRay、Clint 和 Sam 讨论了旧金山的量刑加重、弗吉尼亚州的儿童假释和选民…
阴. fm](https://overcast.fm/+I9KRmEwJc/04:12)
他们在上诉中提到了这篇文章:
布丹今天将宣布第二项指令,也由上诉机构审查,关于所谓的文本前拦截,其中一名官员因轻微违法或违规(如交通违规)而拦截某人,以进行无关的搜查,如枪支或毒品。根据新政策,当违禁品是由于与违规相关的停车而被收集时,“在没有其他明显的犯罪活动嫌疑的情况下”,地方检察官办公室将不会起诉持有违禁品的案件。任何与政策的背离都应以书面形式做出,并需要 DA 或刑事部门负责人的批准。此外,根据该指令,该禁令包括个人同意搜查的情况,“因为执法部门要求同意搜查的长期和有记录的种族和民族差异”。
--https://the appeal . org/San-Francisco-da-to-announce-sweeping-changes-on-pending-policy-and-police-stops/
在这一集里,萨姆提到黑人和棕色人种被拦截和搜查的比例更高,而且很多这样的搜查是他们所谓的“同意搜查”,这意味着警察实际上根本没有理由搜查这个人,除了问那个人他们是否可以搜查他们和那个据称同意的人。
这种严重的种族差异令人心碎,但并不令人惊讶。
当我第一次开始探索数据集时,我发现使用它很麻烦。数据集的大小使得那些没有使用付费资源(如 stata 和 sas)或开源资源(如 python 和 r)以编程方式分析数据的人很难做到这一点。这些信息不是为了方便研究而设计的,但有一些工具可以帮助他们。
💡该法案要求收集数据并向司法部长报告。这个数据集就是为这个目的服务的。
关于数据

来源:https://openjustice.doj.ca.gov/data
数据集由一个 641.4 MB 的.csv文件组成,该文件包含 180 万行和 143 列。每个停止实例都有一个惟一的DOJ_RECORD_ID,每个被停止的人都有一个PERSON_NUMBER。该数据集中总共有 1,708,377 个停靠点,涉及 1,800,054 人。
该数据集包括关于每个停留的基本信息(如持续时间、一天中的时间、最近的城市、机构名称)、感知的人口统计信息(种族/民族、性别、年龄、残疾),以及关于停留原因、搜查、扣押、停留期间采取的行动、发现的违禁品或证据等的信息。有关数据集的更多详细信息,您可以阅读司法部整理的自述文件和 2020 年年度报告。
这是未来几年将发布的一系列 RIPA 数据中的第一波。这一波发布的数据与加州 8 个最大的执法机构(执法机构)有关(这些执法机构雇佣了 1000 多名官员)。这些 lea(及其在总观测值中所占的份额)是:
关于 datasette
dataset是一个探索和发布数据的工具。它帮助人们获取任何形状或大小的数据,并将其发布为一个交互式的、可探索的网站和附带的 API。dataset面向数据记者、博物馆馆长、档案管理员、地方政府和其他任何希望与世界分享数据的人。它是一个更大的工具和插件生态系统的一部分,致力于尽可能提高结构化数据的工作效率。 -datasette . readthedocs . io
数据集是这个项目的引擎。简而言之,它抓取一个 sqlite 数据库,并创建一个交互式的、可探索的网站和附带的 API 。为了准备数据,我们使用了csvs-to-sqlite,这是来自dataset生态系统的另一个工具,它抓取 CSV 文件并从它们创建 sqlite 数据库。
你可以在 GitHub repo 的维基上找到一些公开数据集的例子。这里有一个服务于 FiveThirtyEight 发布的数据集(在他们的 GitHub repo 中找到):https://fivethirtyeight.datasettes.com/
主页显示了数据的许可、来源,并提供了对一些表格的快速访问。

如果你点击你的数据库名称,它会提供一个所有表的视图,并为你提供一个文本框来运行定制的 SQL 查询。这是使数据集成为如此强大的工具的特性之一。

如果您深入研究其中一个表,您会看到建议的方面、一个易于使用的过滤器按钮、一个 JSON 和 CSV 链接,它将提供这些格式中的一种格式的表(这意味着您可以将它用作 API),以及对表的描述。在这种情况下,描述包含一个带有标题和定义的 HTML 表。

如果您单击“查看和编辑 SQL”按钮,您将再次访问一个文本框,以便在上面编写您自己的查询。

datasette 是丰富的工具和插件生态系统的一部分。您可以添加 datasette-vega 插件( repo )来添加当前表格的交互式可视化(使用 altair 制作)

这就是一个基本的数据集网站的样子,但是 T2 的数据集是高度可定制的。以《巴尔的摩太阳报》的数据集为例,人们可以探索每年更新的公共工资记录。

这是在后台运行的数据集,但是他们添加了自己的模板/布局,css 和 javascript 文件。关于如何定制dataset的更多信息,请点击这里:https://dataset . readthe docs . io/en/stable/custom _ templates . html
按部就班的
这一部分是对该项目的技术性更强的描述。数据集的数据准备和部署非常简单,可以分为三个阶段:
—获取数据
—准备数据
—服务数据
获取数据
这些数据是从加州司法部的公开司法网站上获得的:https://openjustice.doj.ca.gov/data。网站提供了下载数据的链接(截止到 2020 年 5 月 5 日,我为这个项目下载的)。要了解更多关于数据本身的信息,你可以阅读项目 GitHub repo 上关于数据 的 部分。
准备数据
原始 CSV 文件的大小超过 650 MB,所以第一步是将分割成 15 个 CSV 文件,这样每个文件都可以上传到这个存储库中的 GitHub。
💡 为什么是?以防它神秘地从原始数据源中消失…
然而,因为数据集太大而不能作为一个单独的表(180 万行乘 143 列),所以它也被分解为更小的表。这意味着我们将相关变量(基于它们的后缀)提取到它们自己的表中。例如,从“主”表中提取与性别相关的变量,如G_FULL、G_MALE、G_FEMALE、G_TRANSGENDER_MAN、G_TRANSGENDER_WOMAN、G_GENDER_NONCOMFORMING和G_MULTIGENDER,并添加到数据库中的性别表中。可以使用分配给它们的 UNIQUE_ID 将它们连接回主表。
CA RIPA 2018 数据发布数据集。通过创建一个……为 chekos/RIPA 2018-dataset 的发展做出贡献
github.com](https://github.com/chekos/RIPA-2018-datasette/blob/master/src/data/break_down_database.py)
该数据集的每个观察或行被分配一个DOJ_RECORD_ID和一个PERSON_NUMBER。这些分别是停靠点和被停靠的人员所特有的。这意味着我们可以将它们组合起来,为每一行创建一个UNIQUE_ID,我们可以用它将表连接在一起。然而,这最终是一个 22 个字符的字符串,这是不必要的大。为了方便起见,每一行都分配了一个从 1,000,000 开始的数字 id。从一百万开始是完全随意的,我们可以从零开始,但是因为有 180 万行,我们决定让每个数字 id 都是七位数。这个数字UNIQUE_ID让我们将表连接在一起和在内存方面对数据库来说并不是一个很大的增加。
一旦创建了这个UNIQUE_ID,我们就可以从“主”表中提取列到它们自己的表中,并将它们保存为单独的 CSV 文件,确保每个观察都可以在这些新表中匹配。
然后我们使用csvs-to-sqlite创建一个 sqlite 数据库,其中每个 CSV 都是一个表。在这一步中,我们还包括从 DOJ 网站获得的附录 B 表 3.csv 文件,以及我们可能已经创建的伴随数据集的任何其他补充表。
csvs-to-sqlite data/processed/*.csv "data/external/Appendix B Table 3.csv" datasette/ripa-2018-db.db
提供数据
在准备数据和创建 sqlite 数据库之后,我们使用dataset作为一个交互式网站和 API。这和跑步一样简单
datasette ripa-2018.db
然而,对于这个项目,我们稍微定制了一下我们的dataset实例。
我们包括标题、描述、数据源 URL 和一些额外的 CSS 和 JS 资产。你可以探索dataset/metadata . JSON来找到细节。
我们还包括预设查询;查询默认包含在我们的实例中,显示在主页中,并带有自己的 URL 以方便访问。包含这些查询是因为它们是在数据中发现的有用和/或有趣的事实。其中一些是计算 2020 年年度报告中发布的特定事实的查询。
我们还从数据集中修改了一些模板,具体是base.html和query.html。第一个被修改为在<head>(网站预览描述等)中包含一些元数据。第二个进行了修改,在 SQL 文本框下面添加了一个按钮,用于提交用户刚刚在 GitHub 上作为建议运行的查询,以便于共享。
我们还更改了数据集的一些默认选项:
default_page_size:50-每页仅显示 50 个结果sql_time_limit_ms:30000- 30 秒限时计算查询(限时在 Heroku 上)facet_time_limit_ms:10000-dataset 应该花费在计算表的一个方面的时间限制(默认为 200 毫秒,但是因为我们的数据集非常大,所以我们将其扩展到 10 秒)
运行的结果代码是:
datasette ripa-2018-db.db \\
-m metadata.json \\
--extra-options="--config default_page_size:50 --config sql_time_limit_ms:30000 --config facet_time_limit_ms:10000"
部署到 heroku
以下是该流程的高级概述

https://github.com/chekos/RIPA-2018-datasette
到目前为止,我们使用了一些 python 代码来处理我们的数据(创建一个UNIQUE_ID并将包含 143 列的原始数据集分解成各种更小的.csv文件),我们还使用csvs-to-sqlite从这些.csv文件中构建了我们的ripa-2018-db.db数据库。到目前为止,我们一直通过运行运行本地服务器的命令datasette ripa-2018-db.db与我们的数据集进行交互。为了让我们的数据集对全世界可用,我们必须在线部署它,幸运的是这非常非常容易做到,因为数据集已经包含了一个publish命令。
使用dataset,可以直接发布到 Heroku 、 Google Cloud Run 或 Fly (从 0.42 版本开始)。因为我以前有部署 heroku 的经验,我发现这是三个中最简单的,但是它们都是很好的选择,文档也很容易理解。
部署到 Heroku 就像运行几乎相同的命令一样简单,该命令用于本地服务我们的数据集。
datasette publish heroku ripa-2018-db.db \\
--name ripa-2018-db \\
-m metadata.json \\
--extra-options="--config default_page_size:50 --config sql_time_limit_ms:30000 --config facet_time_limit_ms:10000"
💡 注意
--name标志,它指定了我们 heroku 应用程序的名称。这意味着它会发布到ripa-2018-db.herokuapp.com并且会覆盖之前的应用(如果有的话)。
要运行这个,你需要一个 heroku 账号并安装 heroku cli 工具。dataset(使用 heroku cli)将要求您登录并打开一个浏览器窗口。你登录后,它会处理剩下的事情。
利斯托。至此,我们已经成功地将我们的数据集发布到 heroku,我们可以访问ripa-2018-db.herokuapp.com或ripa-2018.datasettes.cimarron.io/

http://ripa-2018.datasettes.cimarron.io/
对许多人来说,这将是这个过程的结束。我们已经成功地获取和转换了一些数据,并将其部署到云中,供其他人探索和交互。我们还包括一个 HTML 描述,为用户描述我们的数据集,甚至还有一些预设查询,供人们重现 2020 年年度报告中公布的一些事实。
自动化一切
虽然您提供的底层数据可能不会经常改变,但是您可能会发现自己出于许多原因想要自动化部署您的dataset实例。例如,当我开始这个项目时,datasette】的版本是 0.40,而当我写这篇文章时,它的版本是 0.42。大多数版本你都不想更新你的 datasette 实例,但是 0.41 版本包含了创建自定义页面的能力( changelog )。
例如,添加一个名为
templates/pages/about.html的模板文件将导致在实例的/about处提供一个新页面。
这意味着我们可以在实例中为用户添加更多的上下文。也许包括一个帮助人们为项目做贡献的逐步指南,其他有用的链接,或者一个简单的介绍你自己的页面,这样使用这些数据的人可以更多地了解你。
你可能还想包含更多的固定查询或者修改你描述中的一个错别字。不管是什么原因,自动化部署很容易实现。最终你需要做的就是运行datasette heroku publish,这是 GitHub 动作的一个完美用例
🚨 警告/注意: 这下一部分变得技术性真快多了。GitHub Actions 是一个更高级的主题。如果您不需要/不想定期更新新部署的dataset实例,我不建议您现在就考虑 GitHub 动作。
GitHub 操作
GitHub 动作帮助您在存储代码和协作处理拉取请求和问题的同一位置自动化您的软件开发工作流程。您可以编写称为操作的单个任务,并将它们组合起来创建自定义工作流。工作流是定制的自动化过程,您可以在存储库中设置它,以便在 GitHub 上构建、测试、打包、发布或部署任何代码项目。
-https://help . github . com/en/actions/getting-started-with-github-actions/about-github-actions
在这篇文章中,我们不会深入讨论 GitHub 的行为。你需要知道的是,通过 GitHub 操作,你可以并行或按顺序运行任务,这些任务由 GitHub 事件触发,如推送到一个分支,打开一个拉请求,评论一个问题或多个问题的组合。
这些通常以 yaml 文件的形式存在于你的 GitHub repos 的.github/workflows/下。基本结构如下
name: Example of simple GitHub Actionon:
push:
branches: [master]jobs:
say-hi:
runs-on: ubuntu-latest
steps:
- name: Echo Hello World
run: |
echo "Hello World!"
每当主分支上有一个推送时,这个动作就会被触发,它将运行作业say-hi,该作业运行在最新的可用 ubuntu 虚拟机(VM)上。在那个虚拟机中,它将运行代码echo "Hello World!"
您可以在 repo 的操作选项卡上查看您的操作的输出/日志。

你可以很容易地改变echo "Hello World!"
datasette publish heroku ripa-2018-db.db \\
--name ripa-2018-db \\
-m metadata.json \\
--extra-options="--config default_page_size:50 --config sql_time_limit_ms:30000 --config facet_time_limit_ms:10000"
或者更好的办法是将代码保存在 bash 脚本heroku_deploy.sh中,然后像运行echo "Hello World!"一样运行sh heroku_deploy.sh
幸运的是,Heroku 已经安装在我们的 GitHub Action runner(Ubuntu-latest)中,所以我们需要做的就是登录,安装heroku-builds插件并运行我们的脚本heroku_deploy.sh。
💡在几次 GitHub 操作失败后,我了解到需要安装
heroku-builds。我不确定它是否记录在 datasette】或 GitHub Actions 文档中。
所以现在我们的 GitHub 动作应该是这样的
name: Example of simple GitHub Actionon:
push:
branches: [master]jobs:
publish-to-heroku:
runs-on: ubuntu-latest
steps:
- name: Publish to Heroku
run: |
heroku container:login && heroku plugins:install heroku-builds && sh heroku_deploy.sh
然而,这还没有准备好。为了自动登录,您需要包含环境变量HEROKU_API_KEY。这可以通过使用 GitHub 秘密来实现。
要创建 API 密钥,您需要在本地安装 heroku cli。运行命令heroku authorizations:create并将其添加到您的 repo 的设置>机密选项卡上。命名为HEROKU_API_KEY。
为了让您的 GitHub 操作能够访问它,您必须将下面一行添加到它的 yaml 文件中
name: Example of simple GitHub Actionon:
push:
branches: [master]jobs:
publish-to-heroku:
runs-on: ubuntu-latest
steps:
- name: Publish to Heroku
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
run: |
heroku container:login && heroku plugins:install heroku-builds && sh heroku_deploy.sh
利斯托。现在,每次你推 master,你都会部署一个新版本的 datasette】。这意味着你可以更新你的metadata.json,例如,用一个新的预设查询或者给你的templates/pages添加一个新页面。
对于这个项目,我有一些额外的步骤(也就是 GitHub 操作步骤),这些步骤处理数据,构建 sqlite3 数据库,并在每次需要 master 时将其部署到 heroku。我还包含了几个 python 脚本,它们读取一个单独的 yaml 文件,在这个文件中,我跟踪所有的固定查询,并将它们添加到一个updated_metadata.json。这是为了让事情更整洁,每个固定的查询都有一个标题、html_description 和一个长的 SQL 查询;在我看来,作为一个单独的文件更容易维护。
你可以在这里看到我的 GitHub Action yaml 文件:
https://github.com/chekos/RIPA-2018-datasette/blob/master/.github/workflows/main.yml
额外收获:使用 github 问题来建议查询
如果你访问ripa-2018 . datasets . cimarron . io并运行查询,你会注意到在 GitHub 上提交按钮

这是通过调整query.html模板来完成的。dataset在幕后使用jinja2,它实际上将 SQL 查询作为 url 查询参数传递,这意味着您可以使用request.query_string.split('sql=')[-1]来访问它
一旦您可以访问它,您就可以在您的回购上创建一个新发行的简单链接:
{% set link_to_new_issue = "<https://GitHub.com/><YOUR_USERNAME>/<YOUR_REPO>/issues/new?title=Query+suggestion&labels=suggestion&body=" + <QUERY_FOR_ISSUE> %}
花了多长时间
整个过程总共花费了大约 20 个小时,分散在 3-4 周内。大部分时间都是使用 GitHub Actions 来规划和协调整个自动化过程。我希望这篇教程能帮助你节省这些额外的时间。就像任何其他数据项目一样,最好花一些时间提前思考并勾画出过程的每一步。
行动呼吁
世界变了。这个项目的想法是在四月中旬的某个时候产生的,直到月底我才创建了 GitHub repo。我是五月下半月才开始写这个教程的。从那以后一切都变了。
每天在社交媒体上,我们都会看到有关当局滥用权力、对无辜民众实施暴力的视频和报道。不是全部,但也不应该是全部。
我相信数据是变革、问责和透明的工具。技术和数据永远改变了世界。读者们,作为一名技术专家、数据书呆子、政策专家,或者任何你们选择的自我标榜的标签,我们对我们的同行有责任使用我们的技能、我们强大的工具、我们的知识让世界变得更美好,因为我们可以。
我请你想一想你所扮演的角色。你能用你正在建造的工具让世界变得更美好吗?
我将从数据 4BlackLives 中摘录如下:
黑人生活数据是一项由活动家、组织者和数学家发起的运动,致力于利用数据科学为黑人的生活带来具体而可衡量的变化。自从计算出现以来,大数据和算法已经渗透到我们社会和经济生活的方方面面。这些新的数据系统有着巨大的潜力来增强有色人种社区的力量。统计建模、数据可视化和众包等工具,在合适的人手中,是对抗偏见、建设进步运动和促进公民参与的有力工具。但历史讲述了一个不同的故事,在这个故事中,数据经常被用作压迫的工具,加剧不平等和延续不公正。红线是一个数据驱动的企业,导致黑人社区被系统性地排除在主要金融服务之外。最近的趋势,如预测性警务、基于风险的判决和掠夺性贷款,是同一主题的令人不安的变化。今天,歧视是一个高科技企业。
——d4bl.org
用机器学习让个人数据有意义。
我们能理解自己的个人数据吗?我们知道保护或暴露我们的法律吗?

随着大数据、机器学习和人工智能领域的不断发展,并彻底改变我们所知的当前世界,以及在决定未来方面发挥重要作用,毫无疑问,围绕大数据革命的道德、治理、监管和隐私问题开始出现某些问题。乍一看,这些主题都可以被归类为人工智能和机器学习进步的荆棘,特别是因为大多数企业对该领域的商业利益更感兴趣,而不一定是劣势。
法规
然而,最近的活动和全球趋势开始显示,忽视试图从数据中赚钱的公司中一些看似棘手的问题可能会造成负面影响。欧盟是一个例子,说明政府如何开始优先考虑大多数科技公司以前没有关注的某些法规,从而影响他们的商业模式。脸书的约会应用本应在今天,情人节的前一天发布,但被欧盟禁止,因为脸书未能向监管委员会提供足够的必要文件。他们(脸书)在爱尔兰的办公室实际上被突击搜查,因为爱尔兰政府现在加强了对“大数据公司”的监控

伦理学
围绕人工智能的伦理问题也是这个相当新的行业中一个非常令人担忧的问题,其中大多数利弊尚未可知。制造自动驾驶汽车面临的挑战是,根据最近面部识别系统错误识别有色人种,特别是黑人女性的新闻偏见,如何对算法进行编程,来做出道德决策。
《纽约时报》上的一篇文章称,美国国家标准和技术研究所的研究人员发现,算法错误识别的非裔美国人和亚洲人的面孔比白人面孔多 10 到 100 倍
随着我对人工智能领域兴趣的增长,人工智能的治理和伦理是我想深入研究的一个话题,我的责任感也应该如此。然而,今天我决定看一看在我们自己的手段和控制范围内的一些事情;个人数据的所有权。
个人和私人数据:
你拥有在线账户的每家公司从你甚至你的朋友、同事和家人以及他们的朋友和家人那里收集的数据可以继续下去,直到你意识到公司可能拥有基本上每个人的个人和私人数据。关于这一点最令人不安的因素之一是,大多数用户不知道他们正在收集什么样的数据,更不用说这些数据被用于什么目的了。最近来自监管机构和公民社会的压力正迫使企业明确表示,不仅要允许个人知道他们的哪些数据正在被收集,而且如果可能的话,还要允许个人访问所有这些数据。
Linkedin 就是这样一个允许人们查看和访问他们数据的平台。只需进入你的 LinkedIn 个人资料隐私设置,你就可以从联系人、消息、赞、文章等下载你所有数据的副本。如下图所示:

链接的隐私设置页面的屏幕截图
作为数据科学家,访问个人数据可以让我们以一种有组织和有意义的方式对自己的个人数据进行更有意义的洞察。可以在 LinkedIn 个人数据等数据集上使用分层和 k-means 聚类以及自然语言处理等机器学习技术,来创建关于我们自己的个人数据的更深入的见解。以下是我从个人 LinkedIn 数据的初步分析中得到的一些见解。
1.标准化、计数和聚类公司、位置和连接的标题
来自社交媒体网络的数据往往不太结构化,因此不遵循相同的格式,这使得聚合类似的关联数据特征具有挑战性。例如,对于标题创建者,不同的用户可以将标题设为 1。创始人 2。联合创始人 3。创始人兼 CEO 4。创始人/首席执行官,使用数据标准化技术,可以将他们的专业知识和知识数据(如头衔、位置和公司名称)分组为有组织和结构化的数据,这将使其更容易应用于接近准确和有意义的聚类。以下是我整理我的联系人的头衔和公司的片段。

我的人脉半规范化 LinkedIn 职位

我的关系半规范化公司
我计划进一步应用多种聚类机器学习技术,使用位置、喜好、行业、角色重要性和专业领域等特征,从我的网络中提取更深入的见解。
总之,我敦促所有人检查你最常用的数字平台的隐私设置,并要求提供他们拥有你的什么数据的信息。数据科学家可以立即成为他们自己的个人数据的主题专家,这是自然语言处理等领域非常需要的一种品质,尤其是在实施标准化和相似性计算以及降维技术时。
让《朱庇特笔记本》的情节变得更美丽、更有意义
数据可视化
自定义 matplotlib.pyplot 以提高绘图质量

照片由 iambipin 拍摄
随着我们的世界变得越来越受数据驱动,那些可能对我们生活的世界产生巨大影响的人,如政府、大公司、政治家、商业大亨(你能想到的),他们的重要决策都会受到数据前所未有的影响。因此,数据可视化开始在日常事务中发挥比以往任何时候都重要的作用。因此,在这个领域获得技能越来越重要。
在数据科学领域,Python 是首选的编程语言(数据科学领域无可争议的领导者)。因此我们会考虑用 Matplotlib 来绘图。Matplotlib 是一个用于在 Python 中创建静态、动画和交互式可视化的综合库。 matplotlib.pyplot 是一个命令风格函数的集合,使 matplotlib 能够像 MATLAB 一样工作。 pyplot 函数可以创建一个图形,在图形中创建一个绘图区,在绘图区中绘制一些线,用标签装饰绘图等。使用 pyplot 可以快速生成可视化效果。
让我们在 Jupyter notebook 中创建一些代码来创建一个正态分布。对于外行来说,正态分布是实值随机变量的连续概率分布。通过钟形曲线(概率密度函数)及其对称性可以很容易地识别它。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
mu = 0
std = 1
x = np.linspace(start=-4, stop=4, num=100)
y = stats.norm.pdf(x, mu, std)
plt.plot(x, y)
plt.show()

图 1 :正态分布| iambipin 拍摄
该代码创建了一个简单的正态分布图,其中均值=0,标准差=1。因为我们主要关心的是如何让情节更漂亮,所以关于数学方面的代码解释将会非常简短。 np.linspace() 返回特定间隔[开始,停止]内间隔均匀的样本(样本数等于 num)。scipy . stats . norm()返回一个正态连续随机变量。scipy . stats . norm . pdf()针对给定的平均值(mu)和标准差(std)计算任意点的 PDF。
这张图表似乎显得过于普通和平淡。既没有标签,也没有头衔,向第三人提供一些有价值的信息。没有易于识别和关联值的网格。身材的大小也有点小合我意。
让我们通过利用 pyplot 的各种特性来使情节变得美丽。
添加网格线
网格有助于轻松识别和关联图中的值。 plt.grid() 配置网格线。它以默认设置显示网格。
plt.grid()
创建图形的简单代码如下:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes()
plt.grid()
plt.show()

照片由 iambipin 拍摄
plt.figure() 创建一个新的图形。 plt.axes() 给新图形分配轴,并使其成为当前轴(轴的复数)。Matplotlib 的图可以被认为是一个包含所有关于轴、图形、文本和标签信息的容器。轴可以被视为一个带有记号和标签的边界框,它将包含可视化的绘图元素。 plt.show() 显示所有图形,直到图形关闭
让我们来玩一下 网格() 的各个方面。从网格的颜色开始。
fig = plt.figure()
ax = plt.axes()
plt.grid(b=True, color='r')

照片由 iambipin 拍摄
颜色 是为网格指定颜色的关键字参数。可选参数 b 取布尔值(真或假)。如果设置为 False,网格将会消失。但是,如果存在任何关键字参数(如 alpha、color、linewidth 等),那么 b 将被设置为 True,而不管给定的 b 值如何。例如,如果更改了上面的代码片段:
fig = plt.figure()
ax = plt.axes()
plt.grid(b=False, color = 'r')
输出将是如上所示的带有红色网格的相同图。
对于 颜色 ,可以使用以下任意字符串作为值:
- 红色、蓝色、棕色、品红色等颜色的俗称。
color = '紫色' - 十六进制颜色代码#RRGGBB,取值范围为 00 到 FF。这里 r =红色,G =绿色,B =蓝色
color = '#e3e3e3' - 值从 0 到 1 的 RGB 元组。
color = (0.6,0.9,0.2) - 灰度值从 0.0 到 1.0。随着该值的增加,网格的黑线变暗。
color = '0.9' - RGB 和 CMYK 的短色码。这里 r:红色,g:绿色,b:蓝色,c:青色,m:品红色,y:黄色,k:黑色。
color='c' - HTML 颜色名称。你可以在这里找到更多的 HTML 颜色名称。
color= '番茄'
fig = plt.figure()
ax = plt.axes()
plt.grid(b=True, color='aqua', alpha=0.3, linestyle='-.', linewidth=2)

照片由 iambipin 拍摄
代码中各种关键字参数的属性如下所示:
- alpha 用于改变网格的不透明度。alpha 的零值将使网格消失。
- linestyle 或ls将设置网格线的样式。linestyle 的合适值是'-'、'-'、'-. ',':','','实线','虚线','虚线'等。
- 线宽或lw决定了网格线的宽度。
注意:可以使用相同的关键字参数,以与网格相同的方式设计绘图的曲线或线条。
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes()
x = np.linspace(0, 5, 100)
plt.plot(x, np.sin(x), color='Indigo', linestyle='--', linewidth=3)
plt.grid(b=True, color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
plt.show()

照片由 iambipin 拍摄
可以将 颜色 和 线条样式 参数组合起来,给出一个非关键字参数。例如,' c- -'相当于设置 color='cyan ',linestyle='-',如下面的代码所示:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes()
x = np.linspace(0, 5, 100)
plt.plot(x, np.sin(x), 'c--', linewidth=3)
plt.grid(b=True, color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
plt.show()

照片由 iambipin 拍摄
这种颜色和线条样式的组合对 grid() 不起作用。
主网格线和次网格线
通过向 plt.grid() 的 参数提供三个值中的任意一个,可以显示主网格线和次网格线。这三个值是主要值、次要值和两者。顾名思义,这些是不言自明的。值 主要 显示主要网格线,而 次要 显示次要网格线。值 both 同时显示主要和次要网格线。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 7, 100)
line1, = plt.plot(x, np.sin(x), label='sin')
line2, = plt.plot(x, np.cos(x), label='cos')
plt.legend(handles=[line1, line2], loc='lower right')
#major grid lines
plt.grid(b=True, which='major', color='gray', alpha=0.6, linestyle='dashdot', lw=1.5)
#minor grid lines
plt.minorticks_on()
plt.grid(b=True, which='minor', color='beige', alpha=0.8, ls='-', lw=1)
plt.show()

照片由 iambipin 拍摄
PLT . minor ticks _ on()显示坐标轴上的小刻度。缺点是它可能会降低性能。
为轴添加标签
首先向 x 轴和 y 轴添加标签。matplotlib . pylot . xlabel()用于给 x 轴添加标签。同样, ylabel() 用于给 y 轴分配标签。 fontsize 是 matplotlib 文本关键字参数(**kwargs),是用来控制标签字体的大小。
plt.xlabel('x', fontsize=15)
plt.ylabel('PDF', fontsize=15)
设置轴限制
如果没有特别提到轴限制,Matplotlib 设置默认轴限制。您可以使用 plt.xlim() 和 plt.ylim 分别设定 x 极限和 y 极限。

无轴限制|照片由 iambipin 拍摄
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes()
x = np.linspace(0, 5, 100)
plt.plot(x, np.sin(x), 'c--', linewidth=3)
plt.xlim(-1, 6)
plt.ylim(-1.25, 1.25)
plt.grid(b=True, color='aqua', alpha=0.3, linestyle='-.', linewidth=2)
plt.show()

带轴限制|照片由 iambipin 拍摄
刻度参数
我们已经看到了如何定制网格。尽管如此,有一个PLT . tick _ params()方法可以在一行代码中改变刻度、刻度标签和网格线的外观。不是很方便很强大吗?
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes()
x = np.linspace(0, 5, 100)
plt.plot(x, np.sin(x), 'c--', linewidth=3)
plt.xlim(-1, 6)
plt.ylim(-1.25, 1.25)
plt.tick_params(axis='both', direction='out', length=6, width=2, labelcolor='b', colors='r', grid_color='gray', grid_alpha=0.5)
plt.grid()
plt.show()

照片由 iambipin 拍摄
轴 参数指定要应用参数的轴(“x”、“y”或“两者”)。 方向 将刻度置于轴内、轴外或两者。参数 length 和 width 给出了刻度长度和刻度宽度(浮点)。 标签颜色 给刻度标签分配颜色。 颜色 参数设置刻度颜色和标签颜色。 grid_color 设置网格的颜色 grid_alpha 设置网格的不透明度。PLT . tick _ params()可以用来改变网格的重要属性,如 grid_color (color) 、grid_alpha (float) 、grid_linewidth (float) 和 grid _ line style(string)。
添加图例
图例是地图或图表上解释所用符号的文字。 plt.legend() 方法将图例放置在坐标轴上。
当一个图中出现多行时,代码与通常的做法略有不同。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 7, 100)
line1, = plt.plot(x, np.sin(x), label='sin')
line2, = plt.plot(x, np.cos(x), label='cos')
plt.legend(handles=[line1, line2], loc='best')
plt.grid(b=True, color='aqua', alpha=0.6, linestyle='dashdot')
plt.show()

照片由 iambipin 拍摄
图例 的位置也可以通过设置适当的值(‘右下’,‘左下’,‘右上’,‘左上’等)来改变。)到到 loc 到。
plt.legend(handles=[line1, line2], loc='lower right')

图例的位置更改为右下位置|图片由 iambipin 提供
让我们将所有这些函数添加到我们的代码中,看看图 1 是什么样子。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as statsmu = 0
std = 1
x = np.linspace(start=-4, stop=4, num=100)
y = stats.norm.pdf(x, mu, std)
plt.plot(x, y, label='PDF')
plt.xlabel('x', fontsize=15)
plt.ylabel('PDF', fontsize=15)
plt.grid(b=True, which='major', color='DarkTurquoise', alpha=0.4, linestyle=':', linewidth=2)
plt.minorticks_on()
plt.grid(b=True, which='minor', color='beige', alpha=0.2, linestyle='-', linewidth=2)
plt.legend()
plt.show()

地块 2 :正态分布| iambipin 拍摄
将图形保存到图像中
将绘图保存为图像的几种方法之一是右键单击绘图并选择“图像另存为”选项(任何网络浏览器的默认选项)。

照片由 iambipin 拍摄
另一个选择是使用 plt.savefig()方法。它将当前图形保存到当前工作目录。
plt.savefig('Normal Distribution.png')
为了验证图像已被正确保存,使用了ipython . display模块的 Image 对象。下面的代码将显示图像。
from IPython.display import Image
Image('normal_distribution.png')
增加图形的大小
默认情况下,Jupyter notebook 显示的绘图大小相当小。默认大小仅为 640x480。但是,保存的图像尺寸更小。

照片由 iambipin 拍摄
保存的文件尺寸为 433px * 288px。让我们调整设置,为地块定制大小。PLT . RC params[]就是为了这个特定的目的。一般语法如下:
plt.rcParams['figure.figsize'] = [width, height]
Matplotlib 使用 matplotlibrc 配置文件自定义各种属性,我们称之为‘RC 设置’或‘RC 参数’。Matplotlib 中几乎每个属性的默认值都可以控制:图形大小和 DPI、线条宽度、颜色和样式、轴、轴和网格属性、文本和字体属性等等。一旦找到 matplotlibrc 文件,它将不会搜索任何其他路径。通过键入以下命令,可以看到当前活动的 matplotlibrc 文件的位置:
import matplotlib
matplotlib.matplotlib_fname()
换算成厘米
这里需要注意的重要一点是, figsize 元组接受以英寸为单位的值。要转换成厘米(cm),将该值除以 2.54 即可,因为 1 英寸= 2.54 cm。
plt.rcParams['figure.figsize'] = [10/2.54, 8/2.54]
现在尝试使用 rcParams 自定义图 2 的尺寸。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
mu = 0
std = 1
x = np.linspace(start=-4, stop=4, num=100)
y = stats.norm.pdf(x, mu, std)
plt.plot(x, y, label='PDF')
plt.xlabel('x', fontsize=15)
plt.ylabel('PDF', fontsize=15)
plt.grid(b=True, color='DarkTurquoise', alpha=0.2, linestyle=':', linewidth=2)
plt.rcParams['figure.figsize'] = [10/2.54, 8/2.54]
plt.legend()
plt.show()

地块 3 :正态分布| iambipin 拍摄
设置样式
PLT . style . use()可用于切换到易于使用的绘图样式。样式包提供了一系列广泛的预设样式,从而使图形更具吸引力,尺寸更大。
plt.style.use('classic')
PLT . style . available命令列出了所有可用的各种样式。
print(plt.style.available)['bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark-palette', 'seaborn-dark', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'seaborn', 'Solarize_Light2', 'tableau-colorblind10', '_classic_test']
假设如果我们希望有一个黑暗的背景,那么PLT . style . use(' dark _ background ')将服务于这个目的。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
plt.style.use('dark_background')
mu = 0
std = 1
x = np.linspace(start=-4, stop=4, num=100)
y = stats.norm.pdf(x, mu, std)
plt.plot(x, y, label='PDF')
plt.xlabel('x', fontsize=15)
plt.ylabel('PDF', fontsize=15)
plt.grid(b=True, color='DarkTurquoise', alpha=0.2, linestyle=':', linewidth=2)
plt.legend()
plt.show()

地块 4 :正态分布| iambipin 拍摄
结论
Matplotlib 是事实上的 Python 可视化库。我已经涵盖了 Pyplot 的每个重要方面,以使您在 Jupyter notebook 中的情节脱颖而出。我相信在这里分享的信息会让你的情节更加有意义和美丽。
数据可视化见证了我打字时的变化。有人说得对,唯一不变的是变化本身。永恒是一种幻觉。许多新工具正在出现,如 Tableau、Bokeh、Plotly 等。也许在未来,一个功能更加丰富、技术更加成熟的工具可能会取代 Matplotlib 成为头号工具。到那时,快乐的编码!!!
参考
- https://matplotlib.org/
- https://matplotlib.org/tutorials/introductory/pyplot.html
- https://matplotlib . org/tutorials/introductive/customizing . html
- https://docs . scipy . org/doc/scipy/reference/generated/scipy . stats . norm . html
- https://matplotlib . org/3 . 1 . 1/API/_ as _ gen/matplotlib . py plot . xlabel . html
- https://matplotlib . org/3 . 1 . 1/API/_ as _ gen/matplotlib . py plot . grid . html
- https://matplotlib . org/tutorials/intermediate/legend _ guide . html
- https://matplotlib . org/tutorials/introductive/customizing . html # customizing-with-matplotlibrc-files
- https://matplotlib . org/API/_ as _ gen/matplotlib . axes . axes . tick _ params . html
- https://www.w3schools.com/colors/colors_names.asp
用数据做预言
时间序列预测和最近发展的高级技术介绍。
预测是许多行业常见的问题,通常部署在财务规划、销售/需求预测、营销活动分析、预测性维护和社交媒体分析等场景中。虽然它有时在围绕机器学习的讨论中被忽略,但事实上它可以从机器学习方法中受益,最近开发了新技术来提高其准确性和效率。
什么是时间序列?
一个时间序列由一个有序的时间间隔相等的值序列组成。
时间序列可以应用于连续或离散数据:波士顿每小时消耗的能源量,每天从纽约飞往旧金山的经济舱乘客数量,美国每月的国内生产总值,都是时间序列的例子。
时间序列的频率是季节模式重复之前的观察次数,例如,对于月度数据,频率为 12。

DC 华盛顿州自行车共享服务使用的自行车数量,每小时计算一次。上图显示了整个时间序列,从 2011 年 1 月到 8 月。下图放大了 2 月份的数据。该时间序列在每周和每天的水平上都显示了季节性:工作日显示两个高峰,大约在上午 8 点和下午 5 点,这时大多数人通勤上班;周末在一天的晚些时候,大约下午 2-3 点,是用户开始休闲活动的时候。
时间序列模式
时间序列通常显示有规律的模式:识别和分析这些模式可以更容易地选择合适的预测模型。
季节性分解
时间序列分解是指将时间序列分为趋势、季节和周期部分:
- 当观察水平长期上升或下降时,就会出现趋势。
- 当时间序列受到季节因素(如一年中的某个时间或一周中的某一天)的影响时,就会出现季节性模式。季节性总是有一个固定和已知的频率。
- 当数据以非固定频率的模式上升和下降时,出现一个周期。
分解时间序列意味着提取代表这些模式的成分。大多数时间序列分解模型将周期成分纳入长期模式,并提取趋势、季节和残差成分。当季节性波动的幅度不随时间序列水平变化时,分解被认为是可加的。当季节性波动似乎与时间序列的水平成比例时,使用乘法模型。

2011 年 2 月 DC 华盛顿州自行车共享服务活跃用户数量的时间序列的季节性分解。
自相关
相关性测量两个变量之间的线性关系,而自相关测量时间序列的滞后值之间的线性关系。
可以为每个滞后计算自相关系数,例如 r₁是每个观测值与前一个观测值的相关性。对于每小时的数据,我们将有 24 个系数,它们共同组成了自相关函数(ACF) 。由此产生的图也被称为相关图。

DC 华盛顿州自行车共享服务每小时用户计数的自相关函数(相关图)图。任何给定小时的活动用户数高度依赖于最近活动的用户数,因此单次滞后测量的自相关性最高。同时,有很强的每日季节性,当我们接近 24 小时滞后时,自相关性再次增加。
预测考虑
预测是指一套使用历史数据作为输入来对变量的未来值做出明智估计的技术。
在预测项目的早期阶段,必须根据以下方面做出决策:
- 细分:不同的组是否需要单独的预测,或者是否可以汇总?
- 预测范围:是否需要提前一个月、六个月或一年的预测?
- 频率:需要多长时间预测一次?
确认
常规交叉验证方法不能用于验证时间序列预测,因为它们没有考虑数据的时间结构。时间序列交叉验证涉及一系列成对的训练/测试数据集,其中训练集由在测试集之前发生的观察组成,测试集通常由单个观察形成。

单步时序交叉验证图,定型集用蓝色表示,测试集用红色表示。来源:https://robjhyndman.com/hyndsight/tscv/
经典预测方法
天真的预测
最简单的预测方法——通常令人惊讶地有效——是将下一次观测的预测设定为前 m 次观测的平均值。
这是一种单变量方法,也就是说,只有关于被预测变量的信息才用于产生最终预测。另一方面,多变量方法将来自其他“外生”变量的信息整合到它们的预测中。

对 2011 年 8 月 10 日 DC 华盛顿州自行车共享服务的简单预测(m=3,6)。
指数平滑法
使用指数平滑方法生成的预测是过去观测值的加权平均值,随着观测值变老,权重呈指数衰减。也就是说,观察越近,相关的权重越高。
霍尔特-温特斯法是一种特别流行的指数平滑法,它能捕捉季节性。

Holt-Winters 对 2011 年 8 月 10 日 DC 华盛顿州自行车共享服务的预测。
ARIMA 和季节性 ARIMA
ARIMA 代表自回归综合移动平均线。该模型实际上是一些更简单模型的组合:
- AR(p) 是阶为 p 的自回归模型,这意味着预测是使用变量过去值的线性组合进行的,其中 p 是模型中包含的最大滞后。
- MA(q) 是订单 q 的移动平均线。这一预测是基于类似回归模型的先前误差,其中 q 是考虑的最大滞后。
- I(d) 是积分的阶数,也就是使时间序列平稳所需的差数。
注意,当时间序列的属性不随时间变化时,时间序列是稳定的,即它具有恒定的均值和方差。差分是通过计算连续观测值之间的差值,将非平稳时间序列转换为平稳时间序列的实践。
将阿凯克信息准则(AIC) 最小化,以确定一个非季节性 ARIMA 模型的阶,记为 ARIMA(p. d.q)。
季节性 ARIMA 模型添加了一个用于模拟季节性的组件, S(P,D,Q,s) 其中 s 是季节性的长度或频率, P 是季节性组件上 AR 模型的最大长度,Q 是季节性组件上 MA 模型的最大长度,D 是季节性组件的积分阶,即从季节性组件中移除季节性组件所需的差数
结合一切我们得到 SARIMA(p,D,q)(P,D,Q,s)。SARIMA 有 7 个不同的参数可供选择,因此需要一名数据专家和深入的数据知识来创建有效的模型。
总的来说,ARIMA 和萨里玛模型可以非常精确,但它们的设置是耗时的,并且有效的模型需要专家的人工输入。

SARIMA(1,0,0)(2,1,2,24)2011 年 8 月 10 日 DC 华盛顿州自行车共享服务预测
最近的发展
近年来,已经开发了许多工具来自动化机器学习,其中一些现在专注于时间序列预测。
- AutoML 工具:这些工具,如 DataRobot 和H2O,通过尝试许多不同的特征变换、模型和超参数,使用强力方法来拟合预测模型。
- Prophet 和 Tangent Information Modeler (TIM)等自动化预测工具和库利用更加简化的算法,以极快的速度找到最佳模型和特征变换。
先知
Prophet 是由脸书开发的开源库。它支持单变量和多变量模型,具有加法和乘法季节性。默认情况下,Prophet 会自动拟合一个具有非线性趋势和每日、每周和每年季节性的模型,并为假期添加一个二进制标志。
该库旨在允许完全自动化,但手动参数调整会产生更好的结果。

预言家预测 2011 年 8 月 10 日华盛顿州 DC 的自行车共享服务。这两个模型都是多变量的,包括外部天气变量,如感知温度和风速。
切线信息建模器(TIM)
Tangent Information Modeler(TIM)是 Tangent Works 开发的预测程序。TIM 通过拟合广义加性模型(GAM)并将最佳特征变换集的选择视为优化问题来自动进行预测和异常检测。

TIM 预测 2011 年 8 月 10 日华盛顿州 DC 的自行车共享服务。该模型利用了 InstantML,一种全自动预测技术,并包括外部天气变量,如感知温度和风速。
潜在的假设是,选择正确的特征转换比选择模型重要得多。这是一种新颖的方法,利用信息几何进行优化,这使得该方法非常快速和准确。

表示由 TIM 算法创建的要素变换的树图,用于预测自行车共享服务的用户数量。一些特征与目标变量直接相关,另一些是目标变量和外生变量之间的交互项。例如,cnt(t-24)是预测时间之前 24 小时的用户计数,而 temp_o(t-72) & cnt(t-48)表示预测之前 72 小时的温度与目标的 48 小时滞后值之间的相互作用。
结论
预测是数据科学在商业中最常见的应用之一,在统计学和动态系统理论中有很好的理论基础。直到最近,与图像识别和自然语言处理等热门话题相比,它在某种程度上是一个被忽视的话题,但随着行业从经典的统计方法转向利用更加自动化的基于机器学习的方法,它现在变得更加重要。
参考
- 时间序列的交叉验证,罗布·J·海德曼,https://robjhyndman.com/hyndsight/tscv/
- 预测原理与实践,罗布·J·海曼和乔治·阿萨纳索普洛斯,【https://otexts.com/fpp2/
- 【https://facebook.github.io/prophet/
- https://www . bardess . com/what-we-do/tangent-works-tangent-information-modeler/
让 Python 程序快得惊人
让我们看看我们的 Python 程序的性能,看看如何使它们的速度提高 30%!
讨厌 Python 的人总是说,他们不想使用它的原因之一是它太慢了。不管使用何种编程语言,特定程序的速度是快还是慢在很大程度上取决于编写该程序的开发人员以及他们编写优化和快速程序的技能和能力。
所以,让我们证明一些人是错的,让我们看看如何提高我们的 Python 程序的性能,让它们变得非常快!

由 unsplash 上的 @veri_ivanova
计时和分析
在我们开始优化任何东西之前,我们首先需要找出我们的代码的哪些部分实际上减慢了整个程序。有时程序的瓶颈可能很明显,但如果您不知道它在哪里,那么您可以通过以下方法找到它:
注意:这是我将用于演示目的的程序,它计算*e**X*(取自 Python 文档)😗*
最懒的“侧写”
首先,最简单也是非常懒惰的解决方案——Unixtime命令:
如果你只是想为你的整个程序计时,这是可行的,但通常是不够的…
最详细的剖析
光谱的另一端是cProfile,它会给你太多的信息:
在这里,我们使用cProfile模块和time参数运行测试脚本,这样代码行按照内部时间(cumtime)排序。这给了我们很多信息,你在上面看到的线大约是实际输出的 10%。由此,我们可以看到exp函数是罪魁祸首(意外,意外),现在我们可以得到更多关于计时和分析的细节...
定时特定功能
既然我们知道了应该把注意力放在哪里,我们可能想要对慢速函数计时,而不需要测量代码的其余部分。为此,我们可以使用简单的装饰器:
然后,可以将这个装饰器应用于测试中的函数,如下所示:
这给了我们这样的输出:
需要考虑的一件事是我们实际(想要)测量的是什么样的时间。时间包提供time.perf_counter和time.process_time。这里的区别是perf_counter返回绝对值,其中包括 Python 程序进程不运行的时间,因此可能会受到机器负载的影响。另一方面,process_time只返回用户时间(不包括系统时间),这只是你的进程的时间。
让它更快
现在,有趣的是。让我们让你的 Python 程序运行得更快。我(大部分)不会向您展示一些能够神奇地解决您的性能问题的技巧、诀窍和代码片段。这更多的是关于一般的想法和策略,当使用时,可以对性能产生巨大的影响,在某些情况下可以提高 30%。
使用内置数据类型
这个很明显。内置数据类型非常快,尤其是与我们的自定义类型如树或链表相比。那主要是因为内置是用 C 实现的,用 Python 编码的时候我们在速度上确实比不上。
使用 lru_cache 进行缓存/记忆
我已经在之前的博客文章中展示过这一点,但是我认为有必要用一个简单的例子来重复一下:
上面的函数使用time.sleep模拟繁重的计算。当用参数1第一次调用时,它等待 2 秒,然后才返回结果。再次调用时,结果已经被缓存,所以它跳过函数体并立即返回结果。更多现实生活中的例子请看之前的博文这里。
使用局部变量
这与在每个作用域中查找变量的速度有关。我正在编写每个作用域的,因为这不仅仅是关于使用局部变量还是全局变量。实际上,查找速度甚至在函数中的局部变量(最快)、类级属性(例如self.name -较慢)和全局变量(例如像time.time(最慢)之间也有差异。**
您可以通过使用看似不必要的(直接无用的)赋值来提高性能,如下所示:
使用功能
这可能看起来与直觉相反,因为调用函数会将更多的东西放入堆栈,并从函数返回中产生开销,但这与前一点有关。如果你只是把你的整个代码放在一个文件中,而没有把它放入函数中,那么会因为全局变量而慢很多。因此,您可以通过将整个代码包装在main函数中并调用一次来加速您的代码,就像这样:
不要访问属性
另一个可能降低程序速度的是点运算符* ( .),它在访问对象属性时使用。该操作符使用__getattribute__触发字典查找,这会在代码中产生额外的开销。那么,如何才能真正避免(限制)使用它呢?*
当心绳子
当使用例如模数* ( %s)或.format()在循环中运行时,字符串上的操作会变得相当慢。我们还有什么更好的选择?根据 Raymond Hettinger 最近的推文,我们唯一应该使用的是 f-string ,这是最易读、最简洁和最快的方法。所以,根据那条微博,这是你可以使用的方法列表——从最快到最慢:*
生成器并不是天生就更快,因为它们是为惰性计算而设计的,惰性计算节省了内存而不是时间。然而,节省下来的内存可能会导致程序实际上运行得更快。怎么会?嗯,如果你有一个大的数据集,并且你没有使用生成器(迭代器),那么数据可能会溢出 CPUL1 缓存,这将大大降低在内存中查找值的速度。
就性能而言,非常重要的一点是,CPU 可以尽可能接近地保存它正在处理的所有数据,这些数据位于缓存中。你可以观看 Raymond Hettingers 的演讲,他在演讲中提到了这些问题。
结论
优化的第一条规则是不做。但是,如果你真的不得不这样做,那么我希望这几条建议能帮到你。然而,在优化你的代码时要小心,因为它可能最终使你的代码难以阅读,从而难以维护,这可能超过优化的好处。
**注:此文最初发布于martinheinz . dev
使用关联规则提出建议(R 编程)
购物篮分析简介
背景
零售商通常拥有大量的客户交易数据,包括客户购买的商品类型、价值和购买日期。除非零售商有忠诚度奖励系统,否则他们可能没有客户的人口统计信息,如身高、年龄、性别和地址。因此,为了对该顾客将来可能想要购买什么提出建议,即向顾客推荐哪些产品,这必须基于他们的购买历史和关于其他顾客的购买历史的信息。
在 协同过滤 中,基于发现客户购买历史之间的相似性,向客户进行推荐。因此,如果客户 A 和 B 都购买了产品 A,但客户 B 也购买了产品 B,那么很可能客户 A 也对产品 B 感兴趣。这是一个非常简单的例子,有各种算法可用于找出客户的相似程度,以便进行推荐。
一种这样的算法是k-最近邻 ,其中目标是找到与目标客户最相似的 k 个客户。它包括选择一个 k 和一个相似性度量(欧几里德距离是最常见的)。该算法的基础是空间上彼此最接近的点也可能彼此最相似。
另一个技术是使用 购物篮分析 或 关联规则。此方法的目的是找出哪些物品是一起购买的(放在同一个篮子里)以及购买的频率。该算法的输出是一系列 if-then 规则,即如果顾客购买蜡烛,那么他们也可能购买火柴。关联规则可以在以下方面帮助零售商:
- 修改商店布局,将相关商品存放在一起;
- 向客户发送电子邮件,根据他们之前的购买情况推荐要购买的产品(例如,我们注意到您购买了一支蜡烛,也许这些火柴会让您感兴趣?);和
- 对客户行为的洞察
现在让我们将关联规则应用到虚拟数据集
数据集
提供了 2,178,282 个观测值/行和 16 个变量/特征的数据集。
我对这个数据集做的第一件事是快速检查任何丢失的值或 NAs,如下所示。如下所示,没有发现缺失值。

现在,所有的变量要么以数字形式读入,要么以字符串形式读入。为了有意义地解释分类变量,需要将它们转换为因子。因此,进行了以下更改。
retail <- retail %>%
mutate(MerchCategoryName = as.factor(MerchCategoryName)) %>%
mutate(CategoryName = as.factor(CategoryName)) %>%
mutate(SubCategoryName = as.factor(SubCategoryName)) %>%
mutate(StoreState = as.factor(StoreState)) %>%
mutate(OrderType = as.factor(OrderType)) %>%
mutate (BasketID = as.numeric(BasketID)) %>%
mutate(MerchCategoryCode = as.numeric(MerchCategoryCode)) %>%
mutate(CategoryCode = as.numeric(CategoryCode)) %>%
mutate(SubCategoryCode = as.numeric(SubCategoryCode)) %>%
mutate(ProductName = as.factor(ProductName))
然后,所有的数字变量被总结成五点总结(最小值,中值,最大值,标准差。和平均值)来识别数据中的任何异常值。通过运行此摘要,发现功能商品类别代码、类别代码、和子类别代码包含大量 NAs。经进一步检查,发现这些代码值大多包含数字;但是,转换为 NAs 的文件包含“运费”或字母“C”等字符。由于这些代码与客户购买无关,这些观察结果被删除。
负总销售额和负数量表示错误的值或客户退货。这可能是有趣的信息;然而,它与我们的分析目标无关,因此这些观察结果被省略了。
数据探索
探索数据,看看能否在数据集中发现任何趋势或模式,这总是一个好主意。稍后,您可以使用算法/机器学习模型来验证这些趋势。
下图显示,交易数量最多的是维多利亚州,其次是昆士兰州。如果零售商想知道在哪里增加销售,那么这个图可能是有用的,因为在所有其他州,销售数量都是成比例的低。

下图向我们展示了大多数总销售额在 0-40 美元之间(中位数为 37.60 美元)。

我们也可以按州看到如下图。然而,维多利亚州和昆士兰州的交易似乎掩盖了其他州的信息。箱线图可能更便于可视化。

下面的箱线图(虽然很难看到,因为异常值扩大了范围)显示,所有州的大多数销售额都接近整体中位数。NT 和 VIC 都有异常高的异常值。出于我们的目的,由于我们只对了解客户一起购买了哪些产品感兴趣,以便进行推荐,因此我们不需要处理这些离群值。

既然我们已经看了各州的销售情况。让我们试着更好地了解客户购买的产品。
下图根据每件商品的购买频率进行着色。较浅的蓝色表示较高的频率。
一些关键要点是:
- 在澳大利亚首都地区、新南威尔士州、南澳大利亚州和西澳大利亚州没有团队运动产品的销售,可能是因为这些产品没有库存,或者可能需要更好地营销
- 在澳大利亚首都地区、新南威尔士州、南澳大利亚州和西澳大利亚州没有销售滑雪产品。我觉得这很令人震惊,因为新南威尔士州和 ACT 离一些主要的滑雪胜地很近,比如 Thredbo。奇怪的是,在一年四季都经历温暖气候的 QLD 有滑雪产品销售。这些产品要么贴错了标签,要么没有储存在新南威尔士州和澳大利亚首都地区。
- 仅在西澳大利亚销售油漆和面板。
- 仅在维也纳国际中心销售自行车。
- 露营和服装在维也纳的销售额最高,其次是汽油、燃料和烧烤用品。

由于销售是按产品和州分布的,所以我们提出的任何关联规则似乎都将主要基于 VIC 和 QLD 的销售。此外,由于不是所有的产品都在所有的州有库存/销售,所以预期关联规则将限于非常少数量的产品。不过,既然我已经走上了这种分析模式,那就继续看看我们得到了什么。
我们有两年的数据,2016 年和 2017 年。所以,我决定对比一下这两年的销售总数。
尽管 2016 年的交易数量有所增加(是 2017 年的 2.5 倍),但 2017 年的平均总销售额仍高于 2016 年。这似乎很违背直觉。因此,我决定通过查看月销售额来更深入地研究这个问题。
交易年份 2016 年平均总销售额(美元)1481922 $69.02017 593315 $86.0
2016 年,1 月和 3 月的销售数量最高,9 月至 11 月急剧下降,然后在 12 月出现增长。然而,2017 年交易量继续下降,12 月(圣诞季)有所增加。
扣除 :由于销售额最高的是露营、服装和烧烤&汽油,这些产品在节日期间的销售额高是有道理的
推荐 给零售商:可能想了解商店在 12 月至 1 月是否有足够的库存,因为这些产品最受欢迎。
:尽管交易数量稳步下降,但平均销售总额继续逐月增长,2017 年 12 月最高。这表明购买了更高价值产品的顾客减少了。
购物篮分析/关联规则
让我们回到我们的目标。
目的 :判断哪些产品是顾客有可能一起购买的,以便推荐产品
我使用了 arules 包和 read.transactions 函数将数据集转换为 transaction 对象。该对象的摘要给出了以下输出
***## transactions as itemMatrix in sparse format with
## 1019952 rows (elements/itemsets/transactions) and
## 21209 columns (items) and a density of 9.531951e-05
##
## most frequent items:
## GAS BOTTLE REFILL 9KG* GAS BOTTLE REFILL 4KG*
## 30628 11724
## 6 PACK BUTANE - WILD COUNTRY SNAP HOOK ALUMINIUM GRIPWELL
## 9209 7086
## PEG TENT GALV 225X6.3MM P04G (Other)
## 6948 1996372
##
## element (itemset/transaction) length distribution:
## sizes
## 1 2 3 4 5 6 7 8 9 10
## 546138 234643 109888 55319 30185 16656 9878 6018 3716 2332
## 11 12 13 14 15 16 17 18 19 20
## 1611 993 751 490 353 237 157 140 99 88
## 21 22 23 24 25 26 27 28 29 30
## 53 48 28 31 20 13 12 15 8 1
## 31 32 33 34 35 36 37 38 39 40
## 4 2 4 3 4 1 4 2 1 4
## 43 46
## 1 1
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 1.000 1.000 2.022 2.000 46.000
##
## includes extended item information - examples:
## labels
## 1 10
## 2 11
## 3 11/12***
基于上面的输出,我们可以得出以下结论。
- 有 1019952 个收藏(篮)的物品,21209 个物品。
- 密度测量稀疏矩阵中非零细胞的百分比。它是被购买的项目总数除以矩阵中可能的项目数。您可以使用密度计算购买了多少件物品:1019952212090.0000953 = 2061545**
- 元素(项集/事务)长度分布:这告诉你 1-项集、2-项集等等有多少个事务。第一行告诉您项目的数量,第二行告诉您交易的数量。
- 大多数购物篮(87%)由 1 至 3 件物品组成。
- 购物篮中的最小项目数= 1,最大项目数= 46(只有一个购物篮)
- 最受欢迎的项目是气瓶,气瓶填充,gripwell,和 peg 帐篷。
我们可以通过绝对频率和相对频率图来查看这些信息。
两个图都是按照购买频率降序排列的。绝对频率图告诉我们,销售额最高的是与气体相关的产品。相对频率图显示了条形图中彼此接近的产品的销售额如何相互关联(即相对)。因此,我们可以向零售商提出的建议是,将这些产品一起存放在商店中,或者向客户发送 EDM,对图中相关但客户尚未购买的产品提出建议。


下一步是为我们的事务对象生成规则。输出如下。
***## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.5 0.1 1 none FALSE TRUE 5 0.001 1
## maxlen target ext
## 10 rules FALSE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 1019
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[21209 item(s), 1019952 transaction(s)] done [2.52s].
## sorting and recoding items ... [317 item(s)] done [0.04s].
## creating transaction tree ... done [0.84s].
## checking subsets of size 1 2 done [0.04s].
## writing ... [7 rule(s)] done [0.00s].
## creating S4 object ... done [0.25s].***
上面的输出显示生成了 7 条规则。
这些规则的详细信息如下所示。
***## set of 7 rules
##
## rule length distribution (lhs + rhs):sizes
## 2
## 7
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2 2 2 2 2 2
##
## summary of quality measures:
## support confidence lift count
## Min. :0.001128 Min. :0.5458 Min. : 26.30 Min. :1150
## 1st Qu.:0.001464 1st Qu.:0.6395 1st Qu.: 80.36 1st Qu.:1493
## Median :0.001650 Median :0.6634 Median :154.58 Median :1683
## Mean :0.001652 Mean :0.6759 Mean :154.48 Mean :1685
## 3rd Qu.:0.001668 3rd Qu.:0.7265 3rd Qu.:245.30 3rd Qu.:1701
## Max. :0.002524 Max. :0.7898 Max. :249.14 Max. :2574
##
## mining info:
## data ntransactions support confidence
## tr 1019952 0.001 0.5***
现在,这些规则都有支持、信心和提升值。
让我们从 support 开始,它是用于生成同时包含两个项目的规则(即 1,019,952)的所有事务中的事务的比例(即 1190/1019952 = 0.0011 或 0.11%,其中 count 是包含这两个项目的事务的数量。
置信度 是两个商品一起购买的交易占购买其中一个商品的所有交易的比例。由于这些是先验规则,购买商品 B 的概率是基于购买商品 a 的。
从数学上讲,这看起来如下:
置信度(A= > B) = P(A∩B) / P(A) =频率(A,B) /频率(A)
在上面的结果中,置信度值的范围从 54%到 79%。
顾客带着信心一起购买商品的概率在 54%到 79%之间,其中购买商品 A 对购买商品 B 有积极影响(因为提升值都大于 1)。
注意:当我运行该算法时,我试验了更高的支持度和置信度值,就好像数据集中一起购买两件商品的交易数量越多,置信度就越高。然而,当我以 80%或更高的置信度运行该算法时,我获得了零个规则。
这是预料之中的,因为常见物品的数据很少,其中 1 个物品的篮子最常见,大多数购买的物品与露营或气体产品有关。
因此,该算法在以下参数下运行。
***association.rules <- apriori(tr, parameter = list(supp=0.001, conf=0.5,maxlen=10))***
举 表示两个项目如何相互关联。正的 lift 值表示购买项目 A 可能会导致购买项目 b。数学上, lift 计算如下。
Lift(A =>B)= Support/(Supp(A) Supp(B))*
我们所有的规则都有正的提升值,表明购买商品 A 可能会导致购买商品 b。
规则检查
现在让我们检查一下规则。
***lhs rhs support confidence lift count
## [1] {GAS BOTTLE 9KG POL CODE 2 DC} => {GAS BOTTLE REFILL 9KG*} 0.001650078 0.7897701 26.30036 1683
## [2] {WEBER BABY Q (Q1000) ROASTING TRIVET} => {WEBER BABY Q CONVECTION TRAY} 0.001127504 0.6526674 241.45428 1150
## [3] {GAS BOTTLE 2KG CODE 4 DC} => {GAS BOTTLE REFILL 2KG*} 0.001344181 0.7308102 154.58137 1371
## [4] {GAS BOTTLE 4KG POL CODE 2 DC} => {GAS BOTTLE REFILL 4KG*} 0.001583408 0.7222719 62.83544 1615
## [5] {YTH L J PP THERMAL OE} => {YTH LS TOP PP THERMAL OE} 0.001667726 0.6634165 249.13587 1701
## [6] {YTH LS TOP PP THERMAL OE} => {YTH L J PP THERMAL OE} 0.001667726 0.6262887 249.13587 1701
## [7] {UNI L J PP THERMAL OE} => {UNI L S TOP PP THERMAL OE} 0.002523648 0.5458015 97.88840 2574***
第一条规则的解释如下:
如果顾客购买了 9 公斤的气瓶,有 79%的可能性顾客也会购买它的填充物。这是为数据集中的 1,683 笔交易确定的。
现在,让我们直观地看看这些图。
所有规则的置信度值都大于 0.5,提升范围从 26 到 249。

七条规则的平行坐标图显示了一种产品的购买如何影响另一种产品的购买。RHS 是我们建议客户购买的项目。对于 LHS,2 是购物篮中最近添加的商品,1 是客户以前购买的商品。
查看第一个箭头,我们可以看到,如果顾客的购物篮中有 Weber Baby (Q1000)烘焙三脚架,那么他们可能会购买 Weber Baby q 对流托盘。
如果我们能看到多于两个项目集的篮子,下面的图会更有用。

包扎
现在,您已经学会了如何根据先验规则向顾客推荐最常一起购买的商品。然而,关于这个分析,有一些重要的事情需要注意。
- 最流行/最频繁的项目在某种程度上混淆了分析,看起来我们只能有把握地对七个关联规则提出建议。这是因为购物篮中的项目数量按频率分布不均匀。
- 客户细分可能是该数据集的另一种方法,其中客户按支出(销售总额)、产品类型(即类别代码)、状态商店和销售时间(即月/年)分组。然而,在客户身上有更多的功能来有效地做到这一点将是有用的。
参考:https://www . data camp . com/community/tutorials/market-basket-analysis-r
【https://github.com/shedoesdatascience/basketanalysis】代码和数据集:
让 RNN 模型学习算术运算
使用 RNN 的文本预测
问题:
给定短语“34+17”,模型应该预测序列“51”中的下一个单词。输入和输出是一个字符序列,依次是两个数及其结果的算术表达式。因此,我们的数据被表示为两个单词的序列表达式和结果。
动机:
由于递归神经网络(RNNs)最适合处理顺序数据,我们将建立一个简单的 RNN 模型来解决这个问题。
这可以通过 6 个步骤实现:
- 生成数据
- 建筑模型
- 矢量化、去矢量化数据&移除填充
- 创建数据集
- 训练模型
- 预言
导入必要的库
步骤 1:生成数据
我们需要为输入和输出字符串定义一个包含所需字符集的词汇表。因此,词汇表由 0 到 9 位数、+、-、*、/和十进制(.)符号。
我们正在构建的 RNN 模型需要张量中的数值作为输入。这个字符序列的一个合适的表示是独热编码矢量。向量的维数应该等于词汇的长度,也就是特征的总数。需要创建一个字典来将字符标记为数值。此外,创建另一个字典,将索引作为键,将相应的字符作为值,以便在后面的步骤中使用。
现在让我们生成数据,它是一个单一的表达式、和结果对。为了做到这一点,首先创建两个随机整数‘first’和‘second’,然后创建 表达式 作为字符串转换后的数字的串联,结果 是字符串转换后的计算结果 first+second 。该函数应返回创建的表达式、和结果对。
第二步:建立模型
该模型是由编码器和解码器两部分组成的 keras 序列模型。编码器部分是一个 SimpleRNN 层,hidden_units=128,num_features。它是一个完全连接的 RNN 层,这些单元的输出反馈到网络,它默认使用“tanh”激活。该层的输出将是单个矢量表示,为了实现整个输出的单个矢量表示,我们将使用 RepeatVector()层,重复“max_time_steps”。
这个矢量表示被输入到解码器部分。解码器由另一个 SimpleRNN 层组成,它采用输入的矢量表示并生成预测序列。因此,用“hidden_units”定义这个层,并将“return_sequences”设置为“True”。
该 RNN 的输出是一个序列,该序列将进入具有“softmax”激活功能的密集层。所以,在每个时间步,对于不同的字符,输出会有不同的可能性。
由于我们需要将密集层应用于各个时间步长,我们将把密集层封装在 TimeDistribute 层中,不同时间步长的隐藏状态是不同的。我们需要我们的角色的概率分布‘num _ features’。

RNN 模型的编码器和解码器部分
步骤 3:矢量化、去矢量化数据&移除填充符
为了对给定的表达式和结果进行矢量化,定义了以下函数。
要将“表达式”和“结果”反向矢量化,请使用“index_to_char”字典和相关索引创建一个列表。使用“np.argmax()”通过枚举“expression”或“result”来选取最大索引值。
如果生成的(表达式,结果)是(' 3–34 ','-31 '),那么它的去矢量化形式应该用零填充,如' 03–34 ',' 00–31 '。我们可以在显示输出结果时删除填充。
第四步:创建数据集
我们已经定义了一个函数来创建一个(表达式,结果)对。现在创建一个包含许多这样的(表达式,结果)对的数据集来训练模型。
第五步:训练模型
创建 50,000 个样本的数据集,并使用 20%的验证拆分来训练模型。定义一个回调函数来监控“val_loss ”,如果连续 10 个时期没有观察到变化,则停止模型训练。
第六步:预测
现在创建一个包含 20 个样本的测试数据集,并使用训练好的模型预测结果。
输出:
下面给出了 20 个测试数据样本的预测,我们观察到 70%的预测是正确的。由于测试数据集是随机生成的,预测序列的准确性每次都会发生变化。

预测结果
在数百个模型和研究论文中理解冠状病毒预测
理解和解释冠状病毒感染和死亡人数的预测。

来源:联合国新闻
在本文中,我将尝试帮助您在世界各地产生的数百种估计和模型中,以统计和现实的方式浏览新冠肺炎疫情。我将解释一下这些模型的架构,它们的主观性,以及解释它们的估计的过程。
在过去的两个月里,我们都看到了冠状病毒增长的多种估计和模型。其中许多,例如的最新模型预测到今年夏天结束时 84,000 美国人死亡,特别令人担忧。国家过敏和传染病研究所的福奇博士的另一个模型预测,如果不采取行动,在最好的情况下,大约 20 万美国人死亡,在最坏的情况下,大约 220 万美国人死亡。
但是所有这些模型都有意义吗?这些预测正确吗?如果不是,鉴于从 10 万人死亡到大约 220 万人死亡的预测,我们如何对当前的全球形势做出明智的判断?本文旨在回答其中的一些问题。
预测模型的架构
生成模型是旨在预测未来结果的模型,是给定历史数据和当前环境的未来情景的近似。模型可以简单到线性回归,也可以复杂到由数千层神经网络试图准确预测这些数字。每个模型都有特定的输入,例如关于人口的信息和关于病毒的信息。
每个模型的动态都是利用我们已知的冠状病毒信息构建的。例如,一个人可以在一天内感染多达六个不同的人。因此,在一个非常简单和不知情的模型中,我们将简单地将感染人数乘以 6 来获得第二天的估计值。但是生活没那么简单。关于人性和互动,有无数不同的复杂性需要在模型中加以考虑。例如,有一个人际交往的范围:一些外向的人一天与 20 个人交往,而一些人一周几乎不与 5 个人交往。
在建立模型时,设计了许多参数(例如相互作用的次数、病毒的寿命、传播的概率、人类使用口罩的概率等。)并且每个参数被分配一个“分布”值。这些分布反映了我们对正常人类生活中所代表的一系列价值观的信念。在统计学术语中,它们被称为我们模型的先验。

这是外向者和内向者的简单分布。在左图中,我们假设一个简单的钟形曲线来表示这个分布。在右图中,我们假设了一个双峰分布,其中外向者和内向者的数量有一个峰值,而光谱中的其他人数量较少。(来源:兴旺图)
所有这些先验分布连同所有这些参数之间相互作用的假设动力学一起被输入到模型中。一个数据科学家决定每个参数对我们因变量(感染人数)的可能影响。该模型接受我们的假设和分布以及历史数据,并根据我们对感染增长和输入参数的假设,尝试获得感染数量的最佳估计值。
但这里有一个问题:如果这些模型依赖于这样的主观假设,数据科学家可以定义不现实的假设,并预测一些根本不现实的感染/死亡。那么我们如何确保模型是可靠的呢?
评估模型的可靠性
每个模型的可靠性都受到模型中编码的假设和动态的影响。如果假设一个简单的指数增长,模型结果将会比实际结果膨胀得多。与此同时,如果我假设一个人只能影响另一个人,我会看到过于乐观的估计。(这种估计叫做贝叶斯推断。如果你有兴趣,可以在这里阅读更多关于贝叶斯推理及其主观性的内容。)那么,这为什么这么难呢?在我们回答这个问题之前,有一个有趣的事实:
所有的模型都是错的,但有些是有用的。
上面的引用仅仅意味着我们对冠状病毒感染和死亡人数的预测永远不会正确。这仅仅是因为自然不会告诉我们不同输入因素如人口密度和输出变量之间的确切关系。如果大自然能说话,我们就能揭开它所有的秘密,但遗憾的是事实并非如此。
每一个模型和模拟都是试图根据我们收集的历史数据和信息来估计自然关系。不可能有一个“正确”的模型。因此,模型永远不可能完全正确。但这不代表模特帮不上忙。
模型有什么帮助?
模型不能给我们精确的结果,这意味着只针对一个正确估计的确定性模型是不可靠的。但是评估最好的情况和最坏的情况是很有价值的。如果你回到我在第一段中链接的文章,这些文章实际上提供了这些估计的界限。福奇博士的模型实际上预测,在最好的情况下,夏季会有 10 万到 20 万人死亡,在最坏的情况下(如果我们不采取任何行动),会有 160 万到 220 万人死亡。
为什么这些估计区间这么大?如果再小一点,理解和规划就容易多了。但这就是问题所在——我们对冠状病毒、它的毒株、它的能力、它的生长模式、它的死亡率等知之甚少。来预测比这更确定的估计。这并不意味着我们不应该尝试建立模型。但是我们应该小心我们的知识差距对我们的模型的能力的影响。
这些模型帮助我们评估形势的深度,并做最坏的打算。当谈到拯救生命时,考虑最坏的情况并为其做好计划是非常重要的,因为在最坏的情况下,社会付出的代价远远高于一般情况。
在某些情况下,不确定性比确定性更好,尤其是当涉及到诸如拯救生命这样的关键问题时。这听起来违反直觉,因为你想要确定一个场景,对吗?不完全是。
确定的成本和敏感度
在统计模型中,我们评估每个场景的效用。一个场景比另一个场景成本高多少?当政治家和公共卫生官员依赖近似模型的估计时,回答这样的问题在决策过程中是非常重要的。
但是这种成本的敏感性随着环境的变化而变化。在一个试图预测向你推荐的产品的在线市场的背景下,预测一个错误的推荐产品不会对你对该网站的忠诚度产生巨大的影响,所以这对公司来说是一个非常小的损失。因此,公司官员很少关注评估他们预测推荐产品的绝对最坏情况。
但是当涉及到公共卫生时,事情就没那么简单了。如果一个国家为一个并非最坏的情况做打算,他们就会拿成千上万人的生命冒险。尽管人们对一条生命的成本存在巨大争议,但人类生命的成本大约为 1000 万美元。(注意:我不完全同意给生命贴上价格标签,但你应该读一下这篇文章。)
为生命定价的原因之一是为了突出公共健康规划的重要性。如果一个在线市场由于对其产品的错误预测而失去了一个客户(这是极不可能的),总的利润损失将少于 100 美元。另一方面,由于错误的卫生规划而失去的每一个生命都会给国家带来 1000 万美元的损失。
重要的不是预测,而是对这些预测的解释和衡量不同情景的方法。
除非有人从零开始建立模型,否则大多数现有模型不会衡量其最坏情况,而是将它们的估计值作为从最好情况到最坏情况的区间。
需要准确权衡这些情况,并考虑它们的敏感性。让我们在这里做一点数学计算。如果我们使用我们对生命成本的估计,仅在美国,我们就在人类生命方面损失了大约 1-2 万亿美元(这还不包括仅在美国估计约 3 万亿美元的经济损失)。哦,等等!这绝对是最好的情况。最糟糕的情况是,仅人类生命一项,我们就损失了 16—22 万亿美元。如果我们不能恰当地计划和实施每一项我们可能采取的干预措施,我们将在最好的情况下损失 1 万亿美元的基础上,再损失 15 万亿美元的生命。
给人的生命定价是困难的。这些估计被称为“估计”是有原因的,因为它们并不真实。他们是不正确的,因为你无法量化一个人的死亡对其整个家庭和其他人的情感、精神和经济负担。但是这些估计对于量化如果我们现在不采取行动可能遭受的损失是很重要的。
在数据科学的世界里,你可以尽可能地建立最奇特的模型,并添加多层神经网络。但是如果你不能将你的估计量化为现实生活中的成本,从而引导决策走向正确的道路,那你就大错特错了。
理解预测并告知自己
您可以采取以下一些步骤来评估您所阅读的预测的质量:
- 确保这些预测是由国家认可的合法来源提供的。必须由了解公共卫生和数据科学的专家提供。
- 仔细阅读模型的假设和融入其中的复杂性。如果有人只是简单地模拟指数增长曲线,而不了解人类互动和冠状病毒的复杂性,您可以立即关闭标签。
- 处理最坏的情况。这很重要。对公共卫生规划持乐观态度是一个严重的错误。这意味着你需要提前采取预防措施(自我隔离、社会距离、隔离、保持卫生等)。)并遵循公共卫生指南。不要被看起来太好的预测所左右。
- 最重要的是,不要认为预测是骗局。这些预测是为了帮助你了解我们可能失去生命的程度。你们今天的行动将决定我们在未来几个月将遭受的人类生命损失(以万亿美元计)。
如果您有任何问题或希望与我联系,这是我的 LinkedIn 个人资料。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
理解新冠肺炎预测数据
IHME 天气预报是怎样做的,它们显示了什么?

IHME 模型被称为白宫冠状病毒特别工作组的首选模型
如果你想在我们讨论之前看一下数据,你可以在已知冠状病毒数据中心找到可视化的预测模型。
白宫的首选模式——但它有什么好的吗?
卫生计量与评估研究所,或 IHME,最近因其新冠肺炎预测模型而备受关注。他们的模型甚至被称为白宫冠状病毒特别工作组的首选模型。但是这些模型也引起了很多关于它们的有效性和如何使用它们的怀疑和担忧。在本文中,我们将快速浏览这些模型中的一些数据,并尝试给出它们是如何创建的以及它们的局限性的适当背景。
IHME 模式
首先,值得注意的是,IHME 模型不是一个流行病学模型。它既不是一个 SIR 模型,也不是一个计算更密集的基于代理的模型。IHME 预测是一个实证模型,它采用其他国家的死亡曲线形状,并试图将当前数据拟合到这些曲线上。IHME 模型从新冠肺炎病毒早期爆发的地区的数据开始,如武汉以及西班牙和意大利的一些城市。然后,他们使用自己的基于 Python 的开源曲线拟合工具(恰当地称为 CurveFit )将美国的死亡数据与武汉和其他选定地区的死亡率曲线进行拟合。
IHME 预测是一个实证模型,它采用其他国家的死亡曲线形状,并试图将当前数据与这些曲线拟合
这个模型假设了什么?
这里最大的假设应该有些显而易见;该模型假设疾病在美国人群中的发展与在其他地区的发展相似。
这一点引起了最多的警报,因为正如批评者所说,美国各州都有不同程度的限制,没有一个州像武汉那样 100%封锁。
IHME·新冠肺炎预测
这些预测大致可分为两类:死亡预测和医院资源预测。
在所有这些图表中,x 轴显示日期,y 轴显示计数(例如,在每日新增死亡预测图表中,y 轴显示死亡人数)。红蓝线显示了截至当前日期的实际值。在这一点上,我们正在寻找预计的价值。对于预测值,粉红色部分显示上限和下限,直线显示预期值。
死亡预测
第一类是死亡预测。这里的目标是简单地预测每天预计的新死亡人数,假设全国各地完全就地隔离。

作者提供的图片(参见完整可视化此处
每日新增死亡预测图表显示每天的死亡人数(不要与下一个图表混淆,下一个图表显示的是累计死亡人数)。这份每日新增死亡人数预测显示了美国死亡率的增长曲线,也是决定曲线平滑程度的最重要的视觉工具。如果你仔细观察这张图表,你会发现这张图表显示美国的死亡人数在 4 月底 5 月初达到高峰,然后急剧下降,直到 5 月底。但是和所有的 IHME 视觉化一样,不确定性是巨大的。高峰时,上下限从 8000 人死亡(一天内)到 1000 人以下。

图片由作者提供(参见完整可视化此处)
第二个死亡图表是总死亡人数-预测图表,显示了总的累积死亡人数。正如你从第一张图表中所猜测的那样,随着每日新增死亡人数的骤降,累计死亡人数也趋于平稳。但是,这里的不确定性是巨大的。总死亡人数的上限和下限从大约 40,000 到 140,000,极大地限制了该模型预测美国新冠肺炎死亡人数的实用性。
医院资源预测
第二类是医院资源预测。正如 IHME 在其网站上提到的,这篇文章的最初目标是预测医院的资源需求。他们希望创建预测来帮助医院管理者预测新冠肺炎带来的资源需求。
因此,这些模型试图预测对 ICU 病床、非 ICU 病床和有创呼吸机的需求——所有这些都适用于新冠肺炎病例。

作者提供的图片(参见完整可视化此处)
新的 ICU 每日图表显示了全美 ICU 入院的预期需求。该曲线的形状与每日死亡曲线的形状非常相似——这似乎是符合逻辑的,因为大多数新冠肺炎死亡病例可能会在 ICU 度过一段时间。

图片由作者提供(参见完整可视化此处)
呼吸机预测图表显示了新冠肺炎病例对有创呼吸机的预期需求。

作者提供的图片(见完整可视化此处)
入院预测图表显示了非 ICU 新冠肺炎病例的预计病床需求。
对 IHME 模式的担忧
“所有的模型都是错误的,但有些是有用的”——这是乔治 E.P 博克斯的统计格言
如上所述,IHME 模型使用武汉的数据进行预测,这一事实引起了强烈的批评。
虽然流行病学标准是使用 SIR 模型或基于代理的模型,但 IHME 模型是纯统计的。它是通过将新的数字与现有的分布(如武汉或意大利)进行拟合而创建的。这意味着该模型现在允许根据领域专长调整参数(如死亡率)。
这并不是说 IHME 模式没有价值。像 IHME 这样的纯经验模型可能是强有力的预测工具——特别是当像传染率和特定人群死亡率这样的因素没有被很好地理解时。但是,任何参考 IHME 模型的人都必须小心考虑所涉及的假设,并且只在适当的背景下使用它们。
大外卖
最重要的一点是,记者(和美国政府)在使用和报道这些 IHME 模式时需要谨慎。他们需要对模型中的假设以及这些假设带来的限制保持敏感。不同的模型适用于不同的领域。在疫情期间,对模特的误解可能是生死攸关的事情。
了解更多信息并查看数据
如果你想亲自看看 IHME 的预报数据,你可以在 Knowi 冠状病毒数据中心找到实时的可视化效果。

IHME 在 Knowi 冠状病毒数据中心的预测截图(图片由作者提供)
IHME 资源公司
IHME 在 Medrxiv 预印本服务器上发表了一篇描述这些预测的科学论文。这意味着它还没有经过同行评审,而是正在接受整个科学界的检查。
点击 Medrxiv 阅读 IHME 论文全文
放弃
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
理解共轭先验
了解在某些情况下,如何手动计算后验分布!

假设你扔了一枚硬币 1000 次,得到了 292。你想知道通过一次抛硬币获得正面的概率是多少——但是你不仅仅想要一个估计值,你想要整个分布。如果你定义
- y :你获得的人头数
- θ :一次掷硬币获得正面的概率
然后将 y 建模为二项式分布,其中 n=1 ,000 ,那么后验分布很容易获得,只需几行代码:

作者图片
但是…如果没有 PyMC3 的帮助,我们能分析计算出这个分布吗?
贝叶斯定理
从贝叶斯定理,我们得到:

作者图片
将此应用于我们的问题,我们得到

作者图片
代入这两种分布的定义,我们可以把右边的重新写成

作者图片
去掉常数(不依赖于θ),我们可以把它代入上面的方程,得到

作者图片
我们可以(通过观察)将其识别为贝塔分布 (292+1,1000–292+1)。因为我们的后验和先验来自同一个家族,所以贝塔分布被称为二项分布的共轭先验。
如果我们尝试使用 scipy 绘制这个图,我们将得到 PyMC3 为我们计算的相同分布:

作者图片
这就是共轭先验的好处:它们使得后验概率易于分析。
手动计算后验概率是加深理解的绝佳练习。然而,一般来说,我们不会发现自己处于如此幸运的境地——这时我们需要 PyMC3 这样的工具。
进一步阅读
为了获得优秀实用的贝叶斯统计指南,我推荐阅读用 Python 进行贝叶斯分析和收听学习贝叶斯统计播客。
理解文本聚类
数据科学/文本挖掘
又能有多大用处?

文本无处不在,社交媒体是其最大的发电机之一。人们不断在许多平台上分享它们。我们可以使用文本挖掘方法将它们加工成有用的东西,而不是听之任之。一个著名的应用是情感分析,我们可以识别文本的观点是积极的、消极的还是中立的。但是在这里,我们将讨论另一种方法并理解它:文本聚类。
作为无监督学习的一部分,聚类用于对相似的数据点进行分组,而无需知道数据属于哪个聚类。所以从某种意义上来说,文本聚类就是关于相似的文本(或句子)是如何分组在一起的。但是,我们究竟如何确定一些文本是相似的呢?怎样才能告诉机器“树”这个词和“植物”相似?
把无监督学习想象成一种“物以类聚”的数学版本— 卡西科兹尔科夫
对于那些不了解文本数据处理但和我在一起的人来说,这可能是压倒性的,我不会进入许多复杂的细节,而只是覆盖容易理解的重要点。
如果你不是一个程序员,你可以跳过代码部分。对于感兴趣的人,你可以访问 GitHub 上的完整代码。
事不宜迟,我们开始吧!
让我们开始了解数据
我们将使用可以从 Kaggle 下载的开源数据。感谢 Dody Agung 创建了这个 印尼交通事故 数据集。
完整的数据集包含超过 150,000 条推文(语言为印度尼西亚语),关键字为“kecelakaan”(意思是事故)。它包含推文 id、推文发布时间、抓取时间、推文发布者的用户名和完整推文。
手动标记的数据集也是由创建者提供的,包含 1000 条推文及其标志,无论推文是否指示真实的事故。标志 1 表示事故,标志 0 表示非事故。我们将尝试使用这个带标签的数据集进行文本聚类。下面看一下数据。

文本预处理
如上所述,如何确定某些文本是否相似?计算机只计算数字,所以我们把文本翻译成数字!
在我们开始之前,我们需要净化我们的文本。以这句话为例,让我们看看为什么我们需要清理它们:
安全驾驶对我们每个人来说都是必须的🚌公交车,🚗车,🚛卡车或🛵两轮车..!!😱😱😱
过滤和外壳折叠
表情符号不是文本,符号和特殊字符也不是,比如“.”, "!"、“~”等。我们将过滤这些数据,使其成为纯文本。
做案例折叠也是因为可能会有带“开车”、“开车”、“开车”字样的推文。我们将所有文本都小写,以使它们具有相同的格式。
在我们应用过滤和大小写折叠后,句子看起来会更清晰:
无论是驾驶公共汽车、卡车还是两轮车,安全驾驶对我们每个人来说都是必须的
词干和停用词移除
词干化(或者我们可以使用词汇化)是将一个单词简化为其基本形式的过程。这里的要点是单词“drives”、“driving”、“driven”有相同的上下文,所以我们使用它的基本形式“drive”。参见词干化和词条化的区别,这里。
另一件事是删除停用词,如“是”、“和”、“或”等。停用词指的是我们语言中最常见的词。我们经常看到它们,它们是多余的,所以它不能提供真实的信息。因此,我们完全删除它们。
在我们应用词干并删除停用词后,句子将如下所示:
驾驶安全的道路必须我们每一个人是否驾驶公共汽车卡车两轮车
为了进行前面提到的预处理, NLTK (自然语言工具包)是语言处理的常用工具,但是因为语言是印度尼西亚语,所以我们使用 Sastrawi 来代替。
文字嵌入
这一部分是直观理解文本聚类如何工作的关键。我们可以很容易地找到一组整数/数的和、平均、计数,但是文本呢?在这一部分,我们将它们转换成数字。
有像 CountVectorizer 和 TF-IDF 这样的一键编码方法,但是我们将在这个实验中专门使用单词嵌入。基本上,单词嵌入所做的是将单词表示为空间中的向量,在空间中,相似的单词被映射到彼此附近。
这是一个三维空间中单词向量表示的例子。

来源:机器学习速成班
为了将单词嵌入应用到我们的数据集,我们将使用 fastText 库。他们提供了印度尼西亚语的预训练模型,但相反,我们将尝试使用可用的 150,000+tweet 作为我们的语料库来训练我们自己的单词嵌入模型。我已经预先处理了文本,并将其保存在twitter.txt中。
默认情况下,fastText 的train_unsupervised将使用 skipgram 模型并输出 100 维向量。这些向量表示一条推文在 100 个维度内的位置。
如果你注意到我们没有对句子进行分词,原因是有了get_sentence_vector,它会自动对句子进行分词(将文本拆分成块)。更多细节可以从这里了解车型。
FastText 还计算单词之间的相似性得分。使用get_nearest_neighbors,我们可以看到最相似的前 10 个单词以及每个相似性得分。分数越接近 1,该单词与给定单词越相似。
这是来自 fastText 网站的演示。
model.get_nearest_neighbors(‘accomodation’)
[(0.96342,'容纳'),(0.942124,'容纳'),(0.915427,'容纳'),(0.847751,'容纳'),(0.794353,'容纳'),(0.740381,'容纳'),(0.729746,'便利设施'),(0.725975,'餐饮'),(0.703177,'容纳'),(0.
他们预先训练好的模型甚至知道accomodation的上下文可以是catering和hospitality。现在它更强大了,因为您注意到输入是对accommodation的拼写错误(是的,它可以处理错别字)。
我们的模型怎么样?我们去看看。
# Motorcycle in Bahasa Indonesia
model.get_nearest_neighbors(‘motor’)
[(0.776196300983429,' sepedamotor '),(0.7229066491127014,' motor '),(0.7132794260978699,' sepeda '),(0.69809305678772,' motore '),(0.6889493465423584,' motor '),(0.6859888988)。
# Car in Bahasa Indonesia
model.get_nearest_neighbors(‘mobil’)
[(0.7426463961601257,'林塞克'),(0.7367433905601501,'塔布拉克'),(0.7266382575035095,'美孚'),(0.7141972780227661,'美孚哇'),(0.7097604274749756,'林塞克'),,
看起来不错!如果你是印度尼西亚人,你会清楚地说这些单词在同一语境中。像mobilio、pajero、fortuner、mpv这些词在印尼其实是家喻户晓的车模。
一旦训练完成,该模型将用于将每条推文转换成 100 维向量。这里有一个矢量推文的例子:
[-0.03824997, 0.00133674, -0.0975338 , 0.07422361, 0.04062992, 0.15320793, 0.0624048 , 0.08707056, -0.04479782, 0.01363136, 0.17272875, -0.03097608, 0.05366326, -0.09492738, 0.06163749, 0.04166117, -0.0779877 , 0.11031814, 0.04414257, -0.04424104, 0.02991617, -0.02359444, 0.08660134, -0.01918944, -0.02529236, -0.06084985, 0.00374846, 0.07403581, 0.03064661, 0.0105409 , 0.02821296, -0.08867718, -0.00845077, -0.04583884, -0.03845499, -0.04432626, 0.08085568, 0.0762938 , -0.03690336, 0.00286471, 0.05640269, 0.08347917, -0.12400634, 0.06856565, 0.09385975, 0.07298957, -0.03306708, 0.07894476, -0.03820109, -0.05187325, -0.08153208, -0.05167899, -0.07915987, 0.05901144, 0.00445149, -0.14628977, 0.04536996, 0.12275991, 0.14212511, -0.04074997, 0.04834579, 0.1293375 , 0.13116567, 0.10201992, -0.1010689 , -0.01407889, -0.01707099, 0.13866977, 0.03039356, 0.08307764, 0.06886553, 0.08681376, 0.02241692, -0.0974027 , -0.02969944, -0.06031594, 0.07977851, 0.09534364, -0.0803275 , -0.18087131, 0.00296218, 0.06247464, -0.00784681, -0.0209177 , 0.10568991, -0.06968653, -0.07200669, 0.06571897, 0.01448524, 0.15396708, 0.00435031, 0.02272239, 0.05981111, -0.03069473, -0.11629239, -0.11808605, -0.01497007, -0.00028591, 0.02116462, -0.11837215]
那是一堆数字,不是吗?别试图在脑子里想象 100 个维度,好吗?人类不行(至少目前不行?),但我们的计算机可以处理得很好!现在我们已经创建了单词 vectors,我们如何将相似的 tweets 聚集在一起呢?
文本聚类
对于刷新,聚类是一种无监督学习算法,用于将数据聚类到 k 个组(通常数量由我们预先定义),而无需实际知道数据属于哪个组。聚类算法将尝试自己学习模式。我们将使用最广泛使用的聚类算法: K-means 。该算法可以根据推文与聚类质心的距离对推文进行聚类。
我们已经存储了 tweet 所属的集群输出。我们试着把它画出来,但是怎样才能把 100 个维度可视化呢?
主成分分析(PCA)来拯救。这是一种常用的降维技术。并非所有的数据都代表了全貌,一些数据可能解释了一些事情,而另一些则不能。PCA 背后的思想是提取数据的主成分。这些主成分可用于可视化我们的数据,因为它们代表了我们的大部分数据。
很好,现在让我们用 2D 散点图来形象化它。

一些数据点相互重叠。如果我们用 3D 投影呢?

漂亮!
但是等等,
你们中的一些人注意到了吗,我们可以只建立一个三维单词嵌入模型而不是一个 100 维模型,然后对它使用 PCA。让我们试试那个。
但是,我们如何比较哪种单词嵌入模型能够更好地聚类相似的推文呢?这就是我们使用手动标记的数据集来预测聚类的原因。我们可以检查真实的事故推文是否分组,是否与非事故推文在同一个簇中。
实验结果
我们来看看每个集群的标签比例。第一张图使用 3D 单词嵌入,而第二张图使用默认的 100 维。集群 0 的创建方式有很大的不同。

使用 3D 单词嵌入,聚类 0 正确分组了 87%的事故,聚类 2 正确分组了 97%的非事故。

使用 100D 单词嵌入,聚类 0 正确分组了~99%的事故,而聚类 2 正确分组了 97.5%的非事故。
有了更多的维度,单词嵌入模型可以捕捉更多的信息,生成更好的聚类分组。使用 PCA 的可视化只是为了直观的理解。更优选的是能够准确聚类具有相同属性/特征的文本!
现在,让我们看看每个集群是否有某种特征。我们将从每个集群中看到一些样本。我将为非印度尼西亚人描述每个集群的特征(或者您可以使用翻译)。
聚类 0-事故-红色点
推文特点:可信用户的现场报道。
23.27:@ PTJASAMARGA:Kun ciran KM 14—KM 16 arah Bitung PADAT,ada penanganan kecelakaan kendar aan truk fuso di 胡巴路,”,
20.35 WIB # Tol _ Japek Kara Wang Timur KM 51-KM 52 arah Cikampek PADAT,ada Evakuasi Kecelakaan kenda raan Truk di la jur 1/kiri 和胡巴路,
'♻️ @SenkomCMNP: 5:09 Wib。行驶里程超过 16+600 公里。Masih Penanganan Petugas。第一次和第二次是在莱瓦蒂。(uda)@ sonorafm 92 @ RadioElshinta【https://t.co/9QqgdoBzQW',
聚类 1 —绿色聚类—随机
Tweet 特征:随机用户的随机 tweet,通常讲述他们的个人故事。
剧情转折:我不知道阿比斯·凯瑟拉肯是谁,他可能是 UGD,也可能是其他人。\n\nTapi ya ga masalah sih。Yg 是一家专业的服装公司。https://t.co/0e2zHaMkCo',
在 Margonda 的视频会议上,..你是阿拉..sedih liatnya..\n\nSudah biasa liat yg ky gt..Ga serem,tp sedih iya..图鲁特·贝尔杜卡..😦\ n \ n 最后一个是伊格·巴瓦·坎达兰,约恩·卢帕·贝尔多阿·贝佩吉安,哈特 2 和帕图希·兰布·阿雅..',
'👦:“Abis kecelakaan dimna lo?”\n\n👧:" Gue GK kecelakaan kok aman 2 aja " \ n \ n👦:" trus itu knapa 卡姆 lo ancur"\n\nSABAR。卡姆·杰莱克·艾芒,
集群 2——紫色集群——并非偶然
Tweet 特性:包含新闻和信息(不是关于实时事故,而是过去的事件)
rekaman CCTV Kecelakaan Motor di PIK,潘德 Taman Grisenda:\ nht TPS://t . co/gmhlep 9 ivz mhmmdrhmtrmdhn \ n 访问精彩# MRahmatRamadhan ',
波音公司老板 Minta Maafhttps://t.co/wLRhFy8oYE',
台湾议会也增加了贫困人口的数量。https://t.co/GSWqziaKDN',
那么,下一步是什么?
请记住,我们没有将标志数据提供给模型,但是一半的数据被正确地分组(~99%)到真实事故和非事故的箱中。了解了这一点,我们可以使用聚类方法来标记未标记的数据。标记数据集的最初目的是解决分类问题(监督学习),但是正如我们所看到的,聚类技术可以用来进一步丰富它。
“我们没有更好的算法。我们只是有更多的数据。”彼得·诺维格
有时候,更多的数据(当然是质量数据)比一个算法的改进有用得多。有了更多更好的数据,即使是简单的算法也能给出很棒的结果。在我们使用 3D 与 100D 单词嵌入模型的实验中,我们也可以看到这种现象,对吗?
这是我的一个类比:
一辆好的赛车可能足够快来赢得你的比赛,但你只能用一辆更好的车来取得更好的成绩。
你的驾驶技术就是算法,车就是数据。
因此,我希望阅读这篇文章的人能够对我们如何处理文本数据并将其用于文本聚类有更多的了解。如果有任何错误,请随意评论或指出。
谢谢大家!祝大家平安健康。
参考
[1] Saputro,D. A .,& Girsang,A. S .,使用来自社交媒体的机器学习对交通事故信息进行分类 (2020),《国际工程研究新兴趋势杂志》,8(3),630–637
[2] Cassie Kozyrkov,无监督学习去神秘化 (2018),黑客正午
[3]博雅诺斯基,皮奥特&格雷夫,爱德华&茹林,阿曼德&米科洛夫,托马斯。,用子词信息丰富词向量 (2017),计算语言学协会汇刊
[4] 嵌入,机器学习速成班
特别感谢 奥马尔·阿卜迪拉阿德里安·阿尔法里斯纳迪娅·毛利·阿文塔斯蒂芬妮·苏吉哈托 ,以及 拉哈真·仁德萨里**
使用社区检测算法理解权力的游戏世界
社区检测算法非常准确,而且非常容易使用
我越来越多地研究图表。当您分析连接和社区时,图表特别有用,并且是存储数据的一种非常有效的方式。有时我会使用图形数据库来获取数据,因为它比传统的关系数据库更快。
在这篇文章中,我想把重点放在社区检测算法上,它有很多实际用途。它们可以帮助识别一组交互中的结构,这可以应用于组织设计,但也可以用于数字通信和犯罪调查等其他领域——例如,著名的 Panama Papers 调查主要使用了图表和社区检测。
什么是社区检测?
如果社区存在于一个网络中,你会认为两个联系更紧密的节点(比如人)更有可能是同一个社区的成员。根据这一原理,存在各种算法,这些算法迭代网络中的节点和节点组,并试图形成节点的最佳分组,使得组内的连接是密集的,而组间的连接是稀疏的。
当然,大型网络是复杂的,所以通常很难找到完全独立的社区。社区可以大量重叠,算法主要关注优化。从视觉上看,在这些情况下,最终结果看起来有点混乱是很常见的,但是视觉化不是重点。通过执行社区检测,我们可以获得有价值的信息,这些信息可以帮助我们采取行动来提高效率。例如,我们可以建立一个正式的组织结构,与真实的工作流程更加一致,或者我们可以重新配置服务器集群以加快信息流动。
权力的游戏网络
为了说明社区检测算法的威力,我将采用《权力的游戏》第 1-8 季中所有角色互动的网络,看看我能找到哪些社区。我从来没有看过这个节目,所以不知道结果会有多直观——也许一些读者在看到结果后可以给出一个观点。
在这个网络中,任何两个角色如果在同一个场景中出现过,就是连接的,而连接的强度是由他们一起出现的场景数量决定的。
首先,让我们建立网络。非常感谢 Github 用户 mathbeveridge,他在这里为网络创建了每一季的 edge lists:https://Github . com/mathbeveridge/gameoftrones/tree/master/data。我将直接从 github 中获取这些边列表,并将它们构建到一个编译好的边列表中,使用 r 中的igraph包创建网络。
library(tidyverse)
library(readr)
library(igraph) # get s1 edgelist edgefile_url "https://raw.githubusercontent.com/mathbeveridge/gameofthrones/master/data/got-s1-edges.csv" edgelist <- readr::read_csv(edgefile_url) # append edglistists for s2-8
for (i in 2:8) {
edgefile_url <- paste0("https://raw.githubusercontent.com/mathbeveridge/gameofthrones/master/data//got-s", i, "-edges.csv") edges <- readr::read_csv(edgefile_url) edgelist <- edgelist %>%
dplyr::bind_rows(edges)
} seasons <- 1:8 # <- adjust if you want to focus on specific seasons edgelist <- edgelist %>%
dplyr::filter(Season %in% seasons) # create igraph network with weighted edges edgelist_matrix <- as.matrix(edgelist[ ,1:2]) got_graph <- igraph::graph_from_edgelist(edgelist_matrix, directed = FALSE) %>%
igraph::set.edge.attribute("weight", value = edgelist$Weight)
好了,我们已经建立了我们的关系网。就这么简单。让我们快速浏览一下。
l <- igraph::layout_with_mds(got_graph)
plot(got_graph, vertex.label = NA, vertex.size = 5, rescale = F, layout = l*0.02)

这看起来像一个有很多连接的非常繁忙的图表,很难看出任何有意义或有帮助的结构。但我们不会花太多时间来解决这个问题。
使用卢万社区检测算法
Louvain 社区检测算法是一种在复杂网络中创建最佳社区结构的公认算法。它不是唯一可用的算法(一种叫做 Leiden 算法的相当新的算法被认为性能稍好),但是在igraph包中有一个 Louvain 算法的简单实现,因此我们可以用一个快速的单行命令运行社区检测。让我们这样做,将所有节点分配到各自的社区,看看我们的社区有多大
# run louvain with edge weights louvain_partition <- igraph::cluster_louvain(got_graph, weights = E(got_graph)$weight) got_graph$community <- louvain_partition$membership sizes(louvain_partition) %>% knitr::kable()

我们这里有几个非常小的社区——让我们看看谁在其中。
membership(louvain_partition)[which(membership(louvain_partition) %in% c(6,7))]## BALON_DWARF ROBB_DWARF RENLY_DWARF STANNIS_DWARF JOFFREY_DWARF BLACK_JACK KEGS MULLY
## 6 6 6 6 6 7 7 7
因此,快速的在线研究表明,这些是一次性的社区,出现在非常具体的《GoT》剧集中,几乎完全相互互动——五个小矮人在第四季中扮演五个金,黑杰克、小桶和穆利的三人组也出现在同一季中。虽然这些外围社区被识别出来是令人欣慰的,但在我们这里讨论的主要问题中考虑它们可能没有帮助,所以在我们继续讨论时,我将把它们放在一边。
主要社区的特征
我们希望找到一种方法来描述我们的主要社区。一种方法是确定每个社区中的重要节点——在该社区的整体连通性中,角色是如何重要的。
首先,我们可以找到每个社区中与其他节点连接最多的节点。让我们这样做,通过创建每个社区的子图,并迭代一个向量,该向量包含每个社区中度数最高的节点的名称。
high_degree_nodes <- c() for (i in 1:8) {
subgraph <- induced_subgraph(got_graph, v = which(got_graph$community == i)) degree <- igraph::degree(subgraph) high_degree_nodes[i] <- names(which(degree == max(degree))) } high_degree_nodes[c(1:5, 8)]## [1] "DAENERYS" "SANSA" "CERSEI" "JON" "THEON" "ARYA"
因此,我们可以看到,不出所料,六个联系最紧密的字符是主要字符,它们帮助我们描述我们检测到的社区的特征。我们还可以尝试通过节点来描述每个社区,这个节点是其他节点的最佳连接者,这是一种称为介数中心性的度量。
high_btwn_nodes <- c() for (i in 1:8) { subgraph <- induced_subgraph(got_graph, v = which(got_graph$community == i)) btwn <- igraph::betweenness(subgraph) high_btwn_nodes[i] <- names(which(btwn == max(btwn))) } high_btwn_nodes[c(1:5, 8)]## [1] "JORAH" "SANSA" "TYRION" "SAM" "ROBB" "ARYA"
我们可以看到,对于一对夫妇的社区,中心特征是相同的,但对于其他人来说是不同的——这可能有助于进一步描述社区的特征。
可视化社区
尽管如此大规模的网络可能非常复杂,但查看网络通常是有帮助的。通过对社区中的节点和边进行颜色编码,我们可以更好地区分它们,然后我们还可以标记最中心字符的节点。另一种选择是根据节点在整个网络中的重要性来调整节点的大小。
首先,我们可以生成一个漂亮的球形网络。
# give our nodes some properties, incl scaling them by degree and coloring them by community V(got_graph)$size <- degree(got_graph)/10
V(got_graph)$frame.color <- "white"
V(got_graph)$color <- got_graph$community
V(got_graph)$label <- V(got_graph)$name # also color edges according to their starting node edge.start <- ends(got_graph, es = E(got_graph), names = F)[,1] E(got_graph)$color <- V(got_graph)$color[edge.start] E(got_graph)$arrow.mode <- 0 # only label central characters v_labels <- which(V(got_graph)$name %in% high_degree_nodes[c(1:5, 8)]) for (i in 1:length(V(got_graph))) {
if (!(i %in% v_labels)) {
V(got_graph)$label[i] <- ""
}
} # plot network l1 <- layout_on_sphere(got_graph)
plot(got_graph, rescale = F, layout = l1)

这很漂亮,但是对可视化独立的社区没有帮助。为此,最好使用多维标度,以确保距离较远的节点连接较少。
l2 <- layout_with_mds(got_graph)
plot(got_graph, rescale = F, layout = l2*0.02)

不错!当然,在这里我们可以做更多的事情来分析和描述社区,但是我想让你看到,用几行代码实现这种类型的分析是非常容易的,而且这些算法检测真实社区的能力是相当了不起的!我鼓励你考虑在工作或学习中使用这种技术。如果你能想到这个的好用途,请留言。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或Twitter上找我。也可以看看我在drkeithmcnulty.com的博客。
用 Python 制作简单的游戏
交互式 python 代码,用于井字游戏、点和盒子游戏以及蛇和苹果游戏
在本文中,我将详细介绍如何使用 Tkinter 包在 python 中创建简单的游戏,如井字游戏、点和盒子游戏以及蛇和苹果游戏。文章分为以下内容
- Tkinter 简介
- 游戏流程图
- 代码的结构
- 例如,井字游戏、点和方框游戏、蛇和苹果游戏



使用 Tkinter 的 GUI
Tkinter 是 python 的标准 GUI 框架,与 python 3 捆绑在一起。一个伟大的初学者教程可以在这里找到。本教程的重点不是 Tkinter,而是如何使用它来创建简单的游戏。我们将使用的两个主要部件是
- 画布:在窗口上绘制游戏图形
- 绑定:捕捉用户输入。
画布部件:
Tkinter 上的 canvas 小部件用于在窗口上绘制几何对象。它有画各种形状的方法。简单游戏最常用的方法如下
- Create_line(): 绘制线条
- Create_oval(): 画圈
- Create_text(): 在窗口上打印文本
- delete(): 清除窗口中的绘制对象
绑定小部件:
Bind 用于接收鼠标点击事件的输入。可以在 bind 方法中使用以下参数来标识鼠标单击的类型
- <按钮-1 > : 识别鼠标左键点击
- <按钮-2 > : 识别鼠标中键点击
- <按钮-3 > : 识别鼠标右键
bind 方法将上述参数作为第一个参数,将模块名作为第二个参数。当参数定义的鼠标点击事件被识别时,该模块被调用。
游戏流程图:
现在我们已经对 Tkinter 有了一个基本的概述,下面我们来画一个简单游戏的基本流程图。

根据一些游戏参数(如网格大小、颜色、文本和其他初始化特征),游戏将初始化,然后开始寻找用户输入(以鼠标点击的形式)。一旦接收到,网格位置(鼠标点击的窗口的 x,y 坐标)将被转换成游戏相关的逻辑位置。然后,这些逻辑位置将用于更新在 python 中作为变量存储的游戏内部状态,并使用 canvas 方法更新游戏图形。这个过程会一直重复,直到游戏结束(这将取决于鼠标点击和游戏的内部状态)。游戏的结果将会显示出来。鼠标点击事件将被添加到结果屏幕,供用户选择他或她是否想再次玩游戏。
代码结构:
为了让代码有一个更好的逻辑组织,我们将功能分为三类。
- 初始化功能
- 绘图功能
- 逻辑函数
初始化功能:
这些函数负责设置游戏的初始状态。这些包括定义游戏变量、初始化游戏图形、游戏结束时重置游戏变量、定义画布和绑定小部件等。初始化功能将主要处理在新游戏开始或游戏结束并需要再次玩的情况下设置游戏。
绘图功能:
顾名思义,这些函数将负责在 Tkinter 窗口上绘制基于游戏的图形元素。基于上面提到的基本画布绘制方法,我们将创建特定于我们游戏的高级绘制功能。这些高级绘图功能将被用作更新游戏图形的构建模块。
逻辑功能:
这些功能将与游戏图形无关,将处理游戏逻辑。这些包括但不限于跟踪游戏状态、接收用户输入、更新游戏状态、检查当前移动是否合法、跟踪玩家分数、检查游戏是否结束、决定游戏结果等。
既然我们已经讨论了一些游戏元素的基础知识,让我们来看看一些带有工作代码的例子
示例 1:井字游戏:
游戏代码:
工作代码可以从 这里 下载
游戏截图:

游戏预览:

控件:
- 玩家 X 开始游戏
- 单击每个网格放置一个符号
- 游戏的结果会在游戏结束时显示
- 保持对玩家分数的跟踪
- 单击结果屏幕上的任意位置再次玩游戏
演练:
该代码使用大小为 3x3 的数组来跟踪游戏,即棋盘的状态。“x”标记为-1,而“O”标记为 1。所有未被占用的盒子被标记为 0(零)。用户在一个框内单击,用 bind 方法“click”捕获事件。然后,网格位置被转换,以标识发生单击事件的盒子。基于玩家,只有当盒子还没有被占用时,代码才在识别的盒子中画一个“X”或“O”。电路板状态也会更新。每一回合,代码都会检查是否有玩家赢了。这是通过在板状态的 3x3 阵列中寻找模式来完成的。当任何一方获胜或所有盒子都被占据时,游戏结束。在这个阶段,产生显示获胜者和每个玩家的分数的结果屏幕。
示例 2:点和方框:
游戏代码:
工作代码可以从 这里 下载
游戏截图:

游戏预览:

控件:
- 指定游戏的大小
- 玩家 1 开始游戏
- 单击边缘来标记它们
- 如果做了一个盒子,它会用玩家指定的颜色变暗
- 当所有的边都被标记后,结果显示在结果屏幕上
- 单击结果屏幕上的任意位置再次玩游戏
演练:
该代码使用一个大小为(num _ dots-1)x(num _ dots-1)的数组来跟踪每个框的标记边数。每当玩家 1 标记一个盒子的边缘时,与该盒子相关联的数组的值减 1,并且当它被玩家 2 标记时,它增加 1。每当这个数组中的任何一个元素的值达到-4(或 4)时,这表明玩家 1(玩家 2)已经成功地创建了这个盒子。
玩家点击圆点之间的边缘来激活/标记它们。仔细计算每条边的激活面积,激活面积对应于位于边中间的正方形,其面积为盒子面积的 1/3。一旦标记了边缘,网格位置就被转换以识别对应于该边缘的框,并且对应于这些框的数组的值被递增/递减。当所有的边都被标记后,游戏就结束了。结果屏幕然后显示赢家和每个玩家标记的方块数。
例 3:蛇和苹果:
游戏代码:
工作代码可以从 这里 下载
游戏截图:

蛇和苹果游戏
游戏预览:

控件:
- 游戏从一条等待用户输入的长度为 3 的蛇开始
- 键盘上、下、右和左用于导航
- 游戏的结果会在游戏结束时显示
- 单击结果屏幕上的任意位置再次玩游戏
总结:
讨论了使用 Tkinter 包在 Python 中制作简单游戏的基本概要。提供了三个带有代码的示例,为用户提供了创建其他简单游戏的起点和基本理解。该代码可从以下链接获得
如果这篇文章对你有帮助,欢迎鼓掌、分享和回复。如果你想了解更多关于机器学习和数据科学的知识,请关注我@Aqeel an war或者在LinkedIn上与我联系。
实现从公共云到内部的人工智能之旅
从一个深度学习团队学到的经验教训
与 法尔汉阿布罗尔 联合发文。

阵列遥测的机器学习
我们 Pure Storage 的一个机器学习团队致力于一系列预测、回归和分类问题。我们构建的核心技术是为客户提供预测性能规划器。它对存储阵列进行建模,并根据来自其上运行的工作负载的信号预测其性能。这些信号包括读写带宽、IOSize、重复数据删除率、模式等。
在高层次上,我们的系统收集了过去 1 到 12 个月的时间序列数据,用于 N 特性,并预测系统在未来 1 到 12 个月的性能。然后,根据多个系统瓶颈(如 CPU、SSD、I 端口等)的导数来分析计算性能。(统称为“负载”)。
我们当前的模型将问题分成两部分:第一部分预测特性的时间序列,第二部分使用回归模型预测相关的负载。
时间序列预测基于 ARIMA 和其他一些去趋势统计技术——即而非深度学习。我们发现,如果不进行重大调整,这个模型很难在大量情况下表现良好。作为一个开发团队,我们的目标是开发一个高度精确的模型,然后可以部署到生产中。
我们决定尝试基于深度学习的模型,看看我们是否可以通过从时间序列中直接预测负载来改善我们的时间序列模型或我们的整个管道。

数据集由从我们的遥测系统( Pure1 )提取的约 25GB 的时间序列数据组成,并存储为 csv 文件。Pure1 每 30 秒从我们部署的系统中传输一次遥测数据。今天,我们每天捕捉大约 600 亿个事件。
在本帖中,我们将回顾我们所面临的一些挑战——从数据集规模到软件堆栈再到基础架构。
站在巨人的肩膀上…或者不是
当我们开始这个项目时,我们找到的最好的文献是来自优步的一篇论文。他们使用编码器-解码器架构来学习时间序列的结构,然后使用单独的神经网络进行推理。
我们试图复制这篇论文,但遇到了几个问题。这篇论文是每日的单变量时间序列预测,我们试图做每小时 N 到 1 的多变量时间序列预测。我们得到的模型只能学习预测值的平均值,并且具有较高的训练和测试误差。
最终,我们意识到我们建模的数据比论文中使用的数据要大得多,也复杂得多。
这提出了一系列我们必须回答的问题。首先,我们必须了解不同的层次如何学习时间序列的特征。第二,我们必须评估哪种层和拓扑能够提供更好的准确性。最后,我们必须探索层神经元获得良好性能所需的规模。
所有这些意味着我们需要更多的实验,我们需要它们更快地给我们答案。
更多的实验,更快的实验
我们对开发环境的主要要求是让我们的数据科学家更有生产力——这意味着消除他们实验速度的任何瓶颈。对我们来说,解决这个挑战意味着什么
➊提高硬件灵活性
➋转向全天候测试
我们的数据科学家已经做了很好的工作,但是他们只在白天工作(当然!),他们不得不通过比我们喜欢的更慢的基础设施来满足他们的培训工作。
我们以前在公共云中运行所有的培训工作,但这在两个方面都限制了我们。
问题 1:硬件灵活性(计算和存储)
在公共云中,更高的 GPU 数量很快变得昂贵,并且 GPU 分配没有我们想要的那么精细。比如在 AWS 中,单个 V100 GPU 实例一次只允许 1 个作业;运行多个并发作业意味着管理多个 GPU 实例和更高的成本。
作为公共云 GPU 的替代方案,我们转向了两个 Nvidia DGX-1 服务器形式的本地 GPU(使用 FlashBlade 存储系统为本地数据提供服务)。由于每个 DGX-1 包含 8 个 GPU,开发人员可以通过定位特定的 GPU 来管理单个 DGX-1 服务器内的多个并发作业,这对于探索几个超参数设置非常有用,或者他们可以将两个 DGX-1 结合起来,在 16 个 GPU 上运行更大规模的培训作业。
在切换到 16 个本地 GPU 而不是各种单 GPU 公共云实例后,我们每月的计算成本明显降低了。
从我们转换时开始的成本比较。注意:我们可以使用一个更大的 AWS 实例(p3.8xlarge 和 4x Tesla V100 是 12.24 美元/小时),但是这限制了并发作业数量的灵活性。当前 AWS 定价为此处。假设每个本地 DGX-1 的初始成本为 15 万美元。
即使假设我们只使用 DGX-1 一年,这些本地 GPU 的每小时“费率”也比公共云中的低。如果我们纵观 DGX-1 的多年使用情况,每小时的“费用”甚至会更低。
问题 2:每天 24 小时测试
为了从基础设施中获得最高的效率,我们切换到两阶段开发工作:。白天,当我们有人类的眼睛在测试时,我们通过调整超参数快速迭代模型实验。晚上,我们采用一天中最好的模型,通过使用更大的数据集和更多时期的训练来进行更艰苦的测试。
部分解决方案是有两个训练数据集:一个较小的每日日志集和一个较大的每小时日志集。我们不需要对日志中的每一个数据点进行训练,以便快速排除新网络架构的故障,但我们确实希望在解决问题时对每一个数据点进行训练,以获得最高的准确性。整夜运行真实数量的数据提供了更真实的测试。
每小时数据集的巨大规模意味着在公共云上训练它将会太慢和太昂贵。使用我们的本地硬件,我们能够整夜运行 12 小时、16 个 GPU 的作业,而不用担心内存管理或内存/GPU 成本。
虽然我们成功地切换到每天 24 小时的实验,但我们还没有达到理想状态。这个特殊的团队及其硬件和数据集目前足够小,我们可以手动管理作业。这个团队的最佳状态是使用某种资源调度器来管理作业,这将提供更紧密的基础设施利用率,并确保我们永远不会有用户引起的作业冲突。
今天存在几个机器学习平台,像 Kubeflow 、 MLflow 和 H2O.ai 。如今,这些平台都不是通用的一站式解决方案,所以一些公司更喜欢简单地建立 Slurm 作为他们的资源管理器。
问题 3:大型数据集需要内存管理
我们在公共云中的最初实验是围绕这些实例中可用的固定内存设计的。借助我们的本地基础设施,我们可以获得更多的 HBM 和 DRAM,并且我们甚至可以根据需要扩展到 NFS,因此我们的实验可以更加雄心勃勃。然而,有时我们和硬件之间的软件堆栈会成为障碍。
例如,对于多 DGX-1 (16 GPU)作业,我们使用基于 Horovod 的设置,该设置使用 Docker 在计算节点之间进行通信。不幸的是,内存管理对于这些有几层内存参数的工作流来说有点棘手:DGX HBM、Docker 容器内存、Docker 交换驱动器等。
这个问题在技术上对我们来说是最容易解决的。有几个参数可以根据工作负载微调内存限制,比如增加 shm 大小和增加一个临时 fs 。
对我们的团队来说,更难的改变是重新训练一个习惯:如何让开发人员摆脱受内存容量限制的工作负载。在 AWS 中,我们为每个实例选择了特定的内存大小,这一硬性限制影响了我们团队进行实验的方式。在未来,既然我们已经调整了应用程序堆栈以支持大量可用内存,我们就可以开始测试更复杂的模型架构和更大的训练数据集。
我们学到了什么?
深度学习在许多方面仍然是一个新兴领域,将深度学习应用于非传统问题的文献很少。为了有效地将深度学习应用到新的领域,数据科学家需要在模型架构、大小和超参数上进行大量迭代,以获得最佳结果。
我们需要基础设施的灵活性,以便高效和有效地进行实验,并获得最终的生产就绪模型。
迁移到本地 GPU 集群有助于解决我们的一些测试规模和成本问题,但世界的现状远非理想。我们希望有一个更好的实验管理平台,一个更好的作业调度器来保持集群大规模忙碌,以及一个更好的内存管理工具包,在我们使用的机器学习库中。
虽然我们在内部不断迭代我们的人工智能开发平台,但我们已经将这个特定的人工智能项目投入生产。要阅读更多关于我们的最终模型以及客户如何使用它来模拟工作负载的信息,请查看这篇博客文章。

充分利用有限的硬件进行计算机视觉竞赛
关于在只有少量资源的情况下训练和改进计算机视觉模型的一些想法。
神经网络在过去几年中一直是计算机视觉任务的重要组成部分,自从现在臭名昭著的 2012 年 AlexNet 日以来,它们已经改变了不同图像识别任务的完成方式:对象检测,图像分类,语义分割,一直到创建新图像或用 GANs 修改现有图像。有无数的博客帖子、文章和关于他们历史的讨论,以及关于如何用几行代码构建一个简单模型的教程。
然而,这些工具需要越来越多的计算能力,因为学术界和研究机构似乎非常倾向于创建越来越深的模型,这些模型有大量的参数,除了最大的实验室和公司之外,它们需要不切实际的计算量。作为个人,甚至是一个小团体,这些都是完全够不着的;虽然有很多很棒的教程、介绍等等。我已经写了一些关于如何开始使用 X 或 Y framework 的文章,但感觉似乎缺少“实用”指南,如何帮助那些没有最新最好的计算机硬件的人。
希望这篇文章能为如何降低一些计算机视觉任务的计算预算提供一些思路。这篇文章主要围绕 Kaggle 竞赛,但也可以推广到许多不同的应用。Kaggle 是一个学习数据科学和计算机视觉的好地方,但可能会非常令人生畏,尤其是在刚开始的时候,而且自从 Kaggle 引入了每周 30 小时的 GPU 使用时间限制以来,情况就更是如此。起初,这听起来更像是一个挑战,与以前的比赛相比,资源有限,在以前的比赛中,一个人可以旋转 4 个 GPU 笔记本电脑实例来通宵运行(现在我想起来,这可能是限制的原因,但更实际的是阻止人们挖掘密码和其他非故意的用途)。
我必须先说一些背景情况:由于我的工程背景,我在数学和物理方面有相当扎实的背景,但在数据和计算机科学方面,我几乎是自学的。其中很大一部分要归功于 Kaggle,以及我们可以在几乎无限的时间内免费获得的计算资源(这是大约一年前写这篇文章的时候)。这允许许多错误和修补,而不必担心浪费或必须密切跟踪宝贵的 GPU 资源。希望这可以帮助那些在他们自己的旅途中不再奢侈但仍然想学习这个的人(过度?)在深度学习的时代,计算机视觉是一个时髦但非常有趣的领域。
这里有一个前提:对于几乎任何相对复杂的计算机视觉任务/比赛来说,深度学习都是当今的艺术状态。深度学习非常需要 GPU 来进行训练。这个想法是,我们如何分解一切,只在我们需要的时候使用 GPU,而不再使用?(在更广泛的范围内,这也适用于现实世界应用程序的深度学习模型的实际开发,在这些应用程序中,当用 GPU 打包时,旋转云实例的成本要高得多)。
数据科学,尤其是计算机视觉任务、竞赛、问题等。需要创建一个模型,该模型获取(大部分时间是带标签的)数据,并从中“学习”以识别标签中的任何模式。这意味着传递图像(或任何其他类型的数据),并不断调整和改变模型的内部结构,以最好地减少损失函数。虽然我们不会在这里详细讨论为什么和如何做(同样,网上有足够多的书面主题),但记住大图仍然很重要。传递数据和调整模型的这一步需要繁重的 GPU(或 TPU)处理。然而,这只是制作模型的步骤之一,有限的原始计算能力意味着我们必须尽可能多地从训练前后的所有步骤中挤出时间。预处理和错误分析是我们将在这里讨论的前后步骤的两个例子。

清理数据代表了数据科学家的大部分工作。虽然这对竞争机器学习来说不一定是真的,但在一些竞争中仍然有一些空间
当进行 Kaggle 比赛时,这些 30 小时的 GPU 时间意味着当你将笔记本电脑切换到使用 GPU 时,时钟正在滴答作响,即使你所做的都是 CPU 绑定的。从那里,我试着只在 CPU 上做一些明显的任务,比如数据准备/探索。但我试图更进一步,尽可能减少所有可以删除的非 GPU 操作。这主要适用于可以在图像上进行的任何预处理。我说的不是数据扩充,而是调整图像大小、裁剪、居中、标准化等。我通常用这些预处理过的图像创建一个新的数据集,这样我只需要将它们加载到一个模型中,就可以开始了。
最初,在尝试微调模型之前,我想确保我的模型确实在工作。过早优化是浪费时间,也是浪费 GPU 时间。当我开始一个新项目时,我总是试图创建一个微小的分层数据集,代表我的更大的数据集,以使训练花费很短的时间(我在这里说的是几秒钟)。我真的很喜欢这篇推文&关于“10 秒规则”的文章,我会尽可能地应用它。我们的想法是尽可能快地让事情运转起来。此时模型的输出并不重要,它只需要输出一些东西。这意味着要注意校正形状、尺寸、张量输入/输出等。这通常需要一点时间,如果我也能在 CPU 上完成,那我就去做。我发现许多在线教程和讨论向您展示了如何制作模型,但从未展示如何从数据集开始创建模型(这是假设您首先有一个数据集,很多时候大量工作实际上是在创建它)。然而,似乎大部分时间都花在了调试上,试图找出模型不输出的原因,试图找出一个人的 GPU VRAM 可以容纳多大的批量,等等。所有这些步骤要么不需要 GPU,要么可以用原始数据集的很小一部分来完成。
另一个技巧是试图减少图像本身的大小,而不仅仅是用于测试的数量。我甚至可以更进一步,将我所有的图像转换成一个单一的通道(灰度)而不是 RGB,但这将扰乱模型的架构,所以我通常保留 RGB,但显著减小图像的大小。最棒的是,如果你把高度和宽度减少 2,你就把图像的尺寸减少了 4。这意味着(大约)4 倍的训练速度。显然,您会损失一些信息(从而损失性能),但是以我个人的浅见,首先尝试和测试这些东西是值得的。我也开始研究一些降维方法,或者图像的压缩算法,试图在保持尽可能多的信息的同时减小图像的大小。主成分分析(PCA)常用于表格数据,可用于图像;我以前在处理卫星图像时使用它来减少总的数据集大小。简而言之,一些卫星图像有多达 13 个波段(与通常的 3 个波段,红、蓝和绿形成对比),但使用 PCA 将这些波段减少到 3 个,可以在该任务中产生更好的结果和更快的训练。可能有更聪明的方法来做到这一点,这是一个例子,表明有许多方法来减少数据集的大小,同时试图保留尽可能多的有用信息。
当在训练一个更好的模型的过程中,我也通常不在 GPU 上做任何推断。一旦我有了一个训练好的模型,我就保存它,但之后我通常会移动到我的笔记本电脑上的一个本地实例(在 2Gb VRAM mx150 上这也很棘手,但它总是比 CPU 好)。对来自验证集的一些图像进行推断,以查看模型的结果实际上是什么样子,并了解模型学习得好还是不好。推断比训练快得多,因为在训练模型的过程中,通常也只有较少的图像可以推断。这是一个较长时间不成问题的步骤,因为它可以在模型在 GPU 上训练时完成。由于某种原因,错误分析似乎相当被忽视,至少从 Kaggle 比赛中可以找到的公众评论和笔记本来看是如此。然而,了解模型的正确之处和错误之处是非常有益的。我有物理学和机械工程的背景,几乎每一个现象都有物理定律,这让我深深地理解为什么事物会以这样的方式反应。然而,似乎我们仍然有一个非常试错的方法来进行深度学习微调。深入的错误分析,除了看假阳性和假阴性之外,似乎很容易被忽视,但我认为这对于竞赛和现实世界的应用来说是很有价值的。例如,类激活图 (CAMs)提供了对图像的哪些部分用于进行预测的洞察。假设你有猫的室内图像和狗的室外图像,并且正在为猫和狗制作二元分类器。如果你所有的猫图像都在室内,所有的狗图像都在室外,我们怎么知道模型是在分类猫&狗还是室内&室外?一种方法是从户外的猫和室内的狗那里获得更多的数据,但是摄像头也可以提供一些答案。这些不需要太多的处理能力,也不需要额外的数据。

孟加拉文字游戏的多输出分类器上的类激活图示例。这些可以让我们看到模型在进行预测时使用最多的图像区域(红色)。
还有一些事情,比如试图找到最有效的架构,但通常,这些想法会被广泛地探索。该领域正从 ResNets 转向高效的网络架构、更好的性能、更快的培训和双赢!如果没有像样的 GPU,这些很难评估,而且又一次不得不与所有能够访问它们的人竞争。无法访问高端计算意味着试图在模型架构微调之外的其他主题中改善结果。
直到最近,在 Kaggle 上,在笔记本上运行一个模型意味着必须重新运行它来提交它,或者在完成后下载它(但这意味着让浏览器标签一直打开,有崩溃的风险,并可能失去几个小时的宝贵培训时间。但是如果你犯了,在完成之前你根本不知道发生了什么。如果,在 3 个时代之后,你的模型在做垃圾但是仍然运行,你不一定知道。这在做 k 倍训练时更糟糕,从而不得不训练多个模型。因此,为了解决这个问题,我和一个朋友花了一些时间利用 Slack Python API ,在每个模型训练结束时向我们发送一条消息(我计划在每个时期结束时实现它,但还没有这样做)。每次训练结束后,我都会给自己发一条信息,上面有损失+指标、训练时间等图表。这样,如果我有一个 5 折模型培训,第一折后不如我想象的好,我就可以手动停止提交,防止我的配额白白减少。
使用 Slack API 发送消息(一旦设置正确)非常简单:
def send_message_to_slack(channel,
message):
slack.chat.post_message(channel=channel,
username='YourName',
text=message)message = 'Message to send'
send_message_to_slack(channel = 'kaggle_notification', message=message)
在这个例子中,我在我用于个人项目的 Slack 上创建了一个# kaggle_notification通道,我在每个 epoch、fold 或任何其他地方的末尾调用send_message_to_slack。例如,通过一些修补,还可以发送日志或预测的图像。请注意,您当然需要您的脚本来访问互联网。

在为孟加拉文字游戏比赛训练多输出 EfficientNet 分类器时,我会给自己发送一个 Slack 消息的例子。这里是第 4 个时期所有 3 个输出的结果。
没有最新最棒的计算并不意味着无法为一个试图获得最佳结果的团队做出贡献。在最近的一次计算机视觉中,我加入了一个团队,该团队在没有提供太多模型微调支持的情况下,而是通过在预处理和错误分析上花费时间,取得了前 3%的成绩。除了在 GPU 上运行更大模型的更暴力的方法之外,还有许多更有趣的主题可以挖掘。这意味着试图理解我们的模型是如何学习的,它在哪里出错了,多久出错一次,它在哪里做对了,等等。这使我们能够知道调整学习率优化或改变模型中的一个层首先是否有意义。
尝试不同的模型、架构并花些时间对它们进行微调仍然很重要。Google Colab 是一个很好的开始方式(他们的付费层对于一些很棒的资源来说是相当实惠的!),并找到一些其他的技巧来充分利用它。就像 Kaggle 笔记本一样,当试图在相对较大的数据集上训练大模型时,这些都有其局限性。但同样地,寻找技巧来最大限度地利用它们也是乐趣的一部分。
最后,有些事情我也想做得更好,但我认为对整个数据科学来说相当棘手:跟踪实验及其结果,模型超参数的每个变化如何影响结果。我多次重复做一个实验,因为我没有正确地记录以前测试过的所有东西。注释代码和使用 git 看起来在十几个实验中工作得很好,但是不能扩展到更多。作为一个团队在一个单一的模型上工作也是很棘手的,这是我想更好地在上面浪费更少的时间和资源。几个月前(撰写本文时),安德烈·卡帕西就这个主题做了一次精彩的演讲。
最后,我真的认为对硬件访问的严格限制会引发一些创造性思维,问问自己为什么要做你正在做的事情,如果没有 GPU 来扔模型,你怎么工作。然而,我也认为这种方法有一些限制。到目前为止,你只能使用 CPU 或低端 GPU,而且你仍然需要更强大的硬件来完成计算机视觉任务。我认为记住这一点很重要,尽管我很喜欢不怎么使用 GPU 的失败者的故事。最终,当我有钱时,我会给自己买一个 GPU,因为我确实认为它释放了很多潜力。但我也很高兴我在没有强大硬件的情况下开始了数据科学,尤其是计算机视觉!我认为这是一个很好的锻炼,我觉得这对我的专业工作有很大的帮助。了解如何找到瓶颈,如何用一小部分数据在几个小时内运行一个非常基本的模型;所有这些都是很好的学习练习。
充分利用你的第一次数据科学实习

今年早些时候,我在一家可再生能源公司进行了为期 15 周的第一次数据科学实习。有些事情进展顺利,有些事情进展不顺利。有很多机会我本可以利用得更多。我希望通过在这里以结构化的方式记录我的思考,它将帮助我回顾未来,并在我开始其他冒险时吸取这些教训。
我想分享的 3 个要点是:
- 领域知识——如何尽快获得知识
- 你在工作中学习——但并不是所有的学习都必须在工作中进行
- 建立在线形象的重要性
前两点探讨了这样一个问题:“在我与他们相处的短暂时间里,我如何为公司增加尽可能多的价值?”第三点是关于利用机会推动我们在实习之外的职业发展。
我想说的是,在我实习期间,我在这些方面并不出色——这就是这篇文章的重点。这些是我想提高的地方,也是我未来的指南。
1。领域知识——如何尽快获得知识
如果您熟悉数据科学家的角色,那么您应该听说过领域知识对他们有多重要。领域知识是指你所处理的数据所属领域的知识。对我来说,我需要学习的领域知识包括国家能源市场如何运作,我们的资产如何产生能源背后的工程,以及企业如何运作的背景知识。
如果没有对你所从事的行业的深刻理解,就很难知道要调查的重要问题是什么,识别数据中的任何异常,并解释你的发现的重要性。你越早获得领域知识,你就能越早开始解决对企业有意义的问题。 这里是一篇关于领域知识对于数据科学家的重要性的优秀文章。
在我实习期间,我天真地认为领域知识是“随着时间的推移会自然而然产生的东西”。这在某种程度上是对的,但是如果没有开发领域知识的集中意图,这个过程是缓慢的。没有正确的领域知识,我的角色,也就是我被要求去发现我自己的问题,去调查那些对业务有增值作用的问题,突然感到困难得多。
以下是我在下一次实习中会更加关注的三件事。
1.1。寻找内部资源
当你进入一个全新的行业时,一定要仔细阅读公司为新实习生准备的现有资源。问问你的同事在哪里可以找到他们——如果他们没有,他们会向你推荐最好的在线资源。重要的是,不要一开始就花时间在网上寻找自己的资源。这将不必要地延长这个过程,并使其压力更大。你的公司可能已经收集了最好的资源,并以一种与你的业务相关的方式规划出来。当你对这个行业更加自信和熟悉后,这可能是你开始自己探索外部资源的好时机。
但是这里的关键是效率——记住你可能只有几个月的实习期。思考如何尽可能有效地获取领域知识,这样你就可以开始独立地为组织做出贡献。
1.2。与周围的人交谈业务
作为一名数据科学家,您希望了解整个公司的员工都面临着哪些业务挑战,以便您能够决定要解决的最具附加值的问题。做到这一点的最佳方式是与整个企业的人交谈,了解他们做什么,他们面临的挑战是什么,以及您如何能够提供解决该问题的解决方案。
这也是一个极好的机会去认识公司里的其他人,向业内的佼佼者学习!我个人认为认识新朋友是实习中最棒的部分。
如果你像我一样,害怕接触新朋友,这里有 3 个建议。
- 大多数时候,人们喜欢帮忙——尤其是对一个新实习生。提醒自己,礼貌地请求别人给你 15 分钟时间来讨论你如何能为他们提供价值,不应该惹恼他们。
- 通过 LinkedIn 了解他们在做什么,然后问自己:“他们职业生涯的哪一部分让我感兴趣?我想更多地了解这个人及其工作的哪些方面?”回答这些问题将有助于你与他们进行真实而舒适的对话。
- 有人让你负责。我记得我给自己设定了一个目标,每两周去接触公司里的新同事,然而大多数时候我发现自己给自己找了一个借口,不让自己走出自己的舒适区。试着找一个你经常见到的人——朋友、家人或你的上司,让你保持责任感。
1.3。跟上潮流
不管你做了多少,学习永远不会停止。世界在不断变化,你所在的行业也在不断变化。每天至少拨出 15-30 分钟来阅读关于你所在行业和研究领域的新闻,从而跟上最新的趋势。在午休时间和你的同事聊聊,了解公司的最新动态。如果你仍然沾沾自喜,你富有成效的贡献能力将开始贬值。
2。你在工作中学习——但并不是所有的学习都必须在工作中进行
我参加了我的第一次数据科学实习——对这份工作的技能要求很低。虽然我很感激我在实习期间学到的所有技能,但并不是所有的技能都必须在工作中学习。
实习开始前,我花了很多时间自学 Excel 和 Python,每天至少花一半的时间试图弄清楚数据透视表、VBA 和操作数据框。但这些都是我本来可以在实习前自己学会的技能。事后看来,在实习开始前花些时间学习 Excel 和 Python 本来可以节省我很多时间,让我在实习期间做更多增值的工作。
我强烈建议在实习前花些时间提升自己的技能。如果可以,提前联系你的经理,了解他们使用什么样的工具,这样你就可以开始熟悉他们。如果这对你来说是不可能的,Excel、SQL 和 Python 是一些非常安全的赌注,在大多数数据科学角色中会派上用场。
这是我个人最喜欢的三个提升自我技能的免费资源。
- Data Camp 有一个自由层计划,允许您访问大量数据科学家需求工具的在线课程。这包括 Python、SQL 和 r。对于以前没有太多编程经验的人来说,这是一个很好的资源。还有一个选项是付费进入 Data Camp 的全部课程。虽然我喜欢 Data Camp,也不会反对人们付费完成整个课程,但我个人的建议是,一旦你熟悉了免费层上的这些技术,就去看看接下来的两点。
- InsideSherpa (最近更名为草料)是一个免费平台,让大学生在一些领先的全球公司完成虚拟实习。具体来说,他们有一个 Quantium 的虚拟数据分析实习计划,在那里你可以将你的 Python 或 R 技能应用到实际项目中。
- 整个互联网!一旦你感觉更有信心,试着利用互联网进行你自己的数据分析项目。YouTube 和 Stack Overflow 将会是你一生中最好的朋友,不管你有多有经验。实习结束后,我在 YouTube 上学习了一些网络搜集,以获取自己的数据,并使用 Python 为我最喜欢的视频游戏制作了一个分析工具。做自己的项目,在奋斗中学习,总会得到最大的回报!
你永远不会后悔花时间投资自己。你现在学得越多,你在实习期间就有越多的时间去解决更大更有意义的问题。
3。建立在线形象的重要性
现在你的实习期即将结束,下一步是什么?我们生活在一个如此有趣的时代,科技让我们可以做很多事情。通过像 LinkedIn 这样的平台,你真的有能力和全世界的人说话!这包括你梦想中的公司的招聘经理,你的榜样和其他人。
这就是为什么建立一个在线的存在,或者为你自己建立一个个人品牌是非常重要的。如果你做得对,外面有很多机会等着你。怀疑这能让你走多远?我的朋友最近写了一篇文章,讲述了她如何利用自己的网络影响力在一家初创企业 unicorn 获得实习机会——我强烈推荐这篇文章。
到目前为止,网上形象是我个人需要改进的地方——我想我们很多人在把自己放在网上的时候都会怀疑自己。我肯定也是这些人中的一员。以下是你可以在 LinkedIn 上采取的一些小步骤。
- 建立你的 LinkedIn 个人资料,开始接触你的人际关系。当你越来越舒服的时候,试着去接触那些你还没有见过,但是想要接触的人。向他们发送个性化的连接请求,介绍您自己以及为什么您希望被添加为他们的联系人。谈一谈你自己的背景,以及你对他们的哪些方面感到钦佩或感兴趣,展示你如何在两个方向上都增值。关于如何优化你的个人资料,在 LinkedIn 上接触新朋友的最佳方式以及注意事项,有很多文章。我发现这些事情非常主观,所以我建议你自己做研究,跟随你觉得对的事情。
- 拥有一个有很多人脉的好档案,光靠它是不会让你走得很远的。要真正利用这个平台,你需要开始与人们互动。即使只是简单地喜欢和评论人们的帖子,也会有助于让你留在人们的脑海中。当你感觉更自信时,和新认识的人聊 15 分钟来了解他们。如果你以正确的方式去做,你会惊讶地发现有多少人乐意给你一些时间。同样,围绕这一点,有许多该做的和不该做的事情需要注意——确保你阅读了各种各样的意见,并就此做出自己的判断。
- 一旦你感到更加自信,试着发表自己的帖子。你可能觉得自己还没有太多东西可以分享,但这不是真的——你可以从每个人身上学到新的东西。分享你的学习,表扬你在工作中感激的人,或者写一些你热爱的事情。这篇文章是我这样做的第一步。我们正处于职业生涯中如此激动人心的时刻,我们第一次做某事,每天都在学习新的东西——把这作为你的优势,让自己因某事而出名。
你的第一次实习是一个绝佳的机会,让你开始尝试你自己的个人品牌战略,并利用它来寻找你的下一个机会。
结论
我想把我在这篇文章中谈到的一切归功于我的老同事、朋友和导师,他们在我今年早些时候的第一次实习中指导了我。我总是感谢他们一路上的建议和反馈。希望通过写下这些教训,它将帮助我记住它们,并在未来更加积极主动地对待它们。最后,我想说的是我们完全可以控制我们的实习如何进行****——所以我们应该尽最大努力充分利用它们!
还在争论页面速度的价值和影响吗?
使用机器学习对 Google PageSpeed Insights 进行逆向工程

米卡·鲍梅斯特在 Unsplash 上的照片
爱立信消费者实验室经常引用的统计数据显示,在移动设备上等待一个缓慢加载的网页所产生的压力相当于观看一部恐怖电影。Cloud Flare 的一项研究显示了网页速度和网站转化率之间的联系,如果一个网页在移动设备上的加载时间超过 4 秒,转化率就会下降到 1%以下。
页面速度是一件重要的事情,尤其是现在移动网络已经变得越来越普遍。自 2009 年以来,谷歌一直声称他们的目标是“让网络更快”,从那时到现在,谷歌已经发布了一系列不同的计划来帮助网站管理员在考虑速度的情况下建立他们的网站。
谷歌鼓励网站所有者考虑页面速度的最大方法之一是公开声明页面速度是一个排名因素(即网页越快,它在谷歌排名靠前的机会就越大)。谷歌所有帮助网站所有者生存的资源都在让网络更快网站上。
Google PageSpeed Insights API
Google PageSpeed Insights API 是一个工具,可以让您在每个 URL 的基础上以编程方式查询 Google PageSpeed 数据,它从两个数据源获得结果。第一个来源是 Chrome 用户体验(症结)数据集,这是一个真实世界的网页性能数据数据集,匿名来源于选择加入谷歌 Chrome 的用户。
第二个数据来源是开源的 Lighthouse 项目,这是一个预测网页页面速度性能并给出如何改进建议的工具。可以通过多种方式访问它,包括通过网页,命令行工具或者通过谷歌 Chrome 中的开发者工具。
PageSpeed Insights API 返回了 80 多个不同的结果,作为一个 JSON 对象,包含来自 CRuX 和 Lighthouse 的数据。这些数据中有很多都源于网页速度指标的测量方式。
如何测量网页速度
谷歌创建了一些页面速度指标来衡量页面速度性能,其中最重要的可以在下图中看到:

这些是谷歌页面速度工具中最重要的指标(来源:【https://developers.google.com/speed/docs/insights/v5/about】T4)
速度指数
为什么这很重要?
建立一个企业网站既复杂又昂贵,如果网站在搜索中表现不佳,会对网站所代表的业务底线产生不利影响。如果一个网站已经上线,但页面运行速度很慢,那么重新上线并进行更新以提高性能的成本可能会很高。
在竞争激烈的商业环境中,资源是有限的,这将有助于知道在哪里投入预算,而不是在你知道会获得最大利益的地方进行修复。我决定进一步研究这个问题,第一步是建立一个页面速度性能与排名的数据集,然后使用机器学习来尝试更好地理解数据并获得洞察力。
我建立了一个包含 10 万个网站的数据集,使用了谷歌上最受欢迎的前 1000 个搜索短语,并通过 serpapi.com 的 T2 得到了每个关键词前 100 个网站的位置。然后,我用的 Pagespeed Insights API 查询了这 10 万个网站,从中提取出最重要的指标进行分析。
有趣的是,在 Google 上查看数据集的前 10 个位置的位置与平均速度指数的图表:

谷歌前 1000 个关键词的速度指数与位置
请记住,速度指数越低越好,可以看出,除了位置 1 之外,速度指数和位置之间有明显的关系(即页面越快,位置越高)。如果说速度指数驱动位置(从位置 1 可以看出),那就太简单了,但是这里有一些东西需要研究。
探索数据
我需要能够从 PageSpeed Insights API 获得响应,并尝试提取能够洞察如何以最佳方式构建页面以提高性能的功能。我决定用速度指数来预测这些特征。这将是一个回归问题,因为速度指数是一个连续变量。
此外,因为我希望能够尝试并从我创建的模型中获得洞察力,所以我决定使用更传统的建模方法,因为这将允许我查看模型中系数的强度,以尝试并建立业务洞察力。因此,我没有使用神经网络。
使用速度指数作为连续预测变量,我选择了以下可能对页面速度有最大影响的功能:
- First-Contentful-Paint—First-Contentful-Paint 标记第一个文本或图像被绘制的时间。了解更多。—单位:毫秒
- 交互时间—TTI 指标测量从页面开始加载到其主要子资源已经加载并且能够快速可靠地响应用户输入的时间。了解更多。—单位:毫秒
- 首字节时间 —首字节时间标识服务器发送响应的时间。了解更多。—单位:**毫秒**
- DOM Size—DOM Size 指的是 HTML 文档中元素的数量以及它们之间的关系。大型复杂的 DOM 会降低网页的处理速度。了解更多。—单位:元素个数
- 启动时间 —这是解析、编译和执行 JavaScript 所花费的时间。较小的 JavaScript 有效负载有助于这一点。了解更多。—单位**毫秒**
- 首次有意义绘制 —首次有意义绘制测量页面的主要内容何时可见。了解更多。—单位**毫秒**
- **总阻塞时间**——当任务长度超过 50 毫秒时,从第一次内容绘制到交互的时间总和,以毫秒表示。—单位 ms
- 网络请求 —页面加载期间发出的网络请求数量。—单位**请求数量**
- Total-Byte-Weight —页面下载中请求的所有元素的大小总和。了解更多。—单位**字节**
对于回归模型,我们必须尝试控制多重共线性,因为这可能会使我们的模型在统计上非常不可靠。查看我们所有特征的关联矩阵,我们看到以下内容:

数据集中要素的皮尔逊相关矩阵
可以看出,数据集中的要素之间没有高度的相关性,因此多重共线性不是问题。如果我们查看所有特征与预测值的配对图,我们可以看到:

预测值对特征的配对图
我们可以看到大多数特性都有很高的线性度,尤其是第一内容绘制、第一字节时间和交互时间。这意味着我们最有可能使用回归模型来精确地模拟这些数据。
为了准备用于建模的数据,需要对其进行清理(移除异常值、移除空值、检查数据类型是否一致)、缩放和重复数据删除(同一页面可能会针对多个关键字进行排名)。
一旦完成所有这些步骤,数据集就有 72,218 行,包含 13 个要素。在这些特征中,10 个是数字特征——一个是预测特征,另外 9 个是建模特征。
建模数据
首先要做的是将数据集随机分成三个独立的部分:一个训练集、一个测试集和一个最终验证集,在选择候选模型之前不会用到最终验证集。
为了评估候选模型,我还需要建立一个基线模型,以便能够准确地检查成功。由于这是一个回归问题,而且许多关系似乎是线性的,那么一个“简单”的线性回归模型似乎是一个很好的第一步。我把“简单”这个词用引号括起来,因为它是 9 维的线性回归。
确定模型表现如何的成功指标是 r2 误差,在训练模型后,我得到以下结果:
线性回归模型代码和输出
可以看出,在训练期间,该模型在 K 倍内获得了 0.76 的 r2 分数,这意味着该模型没有过度拟合,并且表现良好。当在测试集上调用 model.predict() 时,r2 值为 0.77,因此这是评估其他候选模型的起点,而且还不错。
我测试了各种其他模型,取得了不同程度的成功:决策树回归器(严重过度拟合,直到正则化)、随机森林回归器、支持向量机线性回归器和支持向量机多项式回归器(更多是出于兴趣,而不是实际应用)。

测试的其他模型及其 R2 分数
可以看出,随机森林回归器表现最好,r2 为 0.78,这是很好的。下一步是优化这个结果,尝试得到一个性能更好的模型。
模型优化
下一步是使用 gridsearch 交叉验证(GridSearchCV)优化模型超参数,以将模型调整到最佳水平。
经过几轮 GridSearchCV 后,最佳模型是一个随机森林回归器,max_depth = 23,min_samples_leaf = 3,该模型的 r2 值为 0.79,这是迄今为止最好的,比未优化的模型稍有改进。
当优化的模型与未接触的验证数据集相匹配时,我继续得到 r2 值 0.79,这意味着该模型在 5 次中正确预测了 4 次速度指数,这是一个非常好的结果。
解释模型
真正的商业洞察力来自于能够查看模型中的系数,从而能够决定哪一个对网页的速度影响最大。最好的执行模型是随机森林回归器,因为它可以调用 model . feature _ importances _方法来查看哪些特征对模型的贡献最大。****
根据我为此数据制作的最佳模型,我们可以看到以下内容:

最优随机森林回归模型的特征重要性
可以看出,在构建快速网页时,交互时间是影响性能的主要因素。这似乎是显而易见的,但是,如果你跟随直觉,如果你的互动时间很快,那么其他一切都会很快,但不一定相反。
例如,如果你在即使不能交互也至少让内容可见的基本原理下,优化了第一次有意义的绘制(当内容可见,但你不能与之交互时)——你的页面加载速度会更慢,用户体验会更差。
时间对第一个字节的贡献也很重要,因为这是页面加载时发生的第一件事,所以如果这很慢,那么它将对其他所有事情产生连锁反应。
结论
如果你想建立一个快速的网页,那么根据谷歌上最受欢迎的 1000 个关键词和谷歌 PageSpeed Insights API 的数据,你需要优化你的构建过程,使页面尽可能快地具有交互性。如果你这样做了,页面就会变得很快,其他的事情也会随之而来。
除此之外,还要确保您的服务器基础架构速度很快,这样就不会出现瓶颈。否则,这将降低整个页面的加载速度。
为了进一步扩展这个项目,看看其他目标变量会很有意思。谷歌刚刚推出了它的核心网站指标系列,作为量化用户页面体验的一种方式。研究这些会很有趣,看看“用户友好”和搜索位置之间是否有联系。
如果你有兴趣查看这个项目的代码,它在我的 Github 简介中。
创造机会
从贝叶斯到必发:简史

照片由来自 Unsplash 的 Richard Boyle ( hellorich )拍摄
编者注: 本文仅供教育娱乐之用。如果你想用这个模型进行真正的下注,那么你要自担风险。请确保这是符合你的庄家的条款和条件。
当星期六到来时
现在是星期六下午三点差一刻。你已经放弃了周末足球比赛的门票,决定不跟随你的父亲去球场,因为你晚上晚些时候有另一个约会(至少这是你告诉他的——事实是,你不能再看你的球队踢垃圾球了)。
不过开球前还有一件事要做。拿出你的手机,打开* 在此插入最喜欢的博彩公司的名字 应用程序,查看博彩公司为你的球队在本周末赢得的赔率。毫不留情地,你翻阅着投注券,看着全国许多球队的比赛赔率。突然,你经历了一个好奇的时刻,想知道(不是第一次)"为什么这些几率是这样的*"。如果能多了解一点这些比赛定价的思路和过程就好了,因为你总是试图在每个周末选出赢家。
无论如何,你为累加器选择你的三个队。15/2 时 10 分。这就是那个。
下午 5 点,结果出来了——两个队赢了,第三个队带着一个不幸的平局离开了。你的 acca 被毁了。怒火中烧,你把手机放在一边,准备晚上的约会。你的室友感觉到了失望,提醒你“三分之二不算太坏”。你试图在接下来的一天里转移自己对坏结果的注意力。现在,你根本不在乎那些该死的几率。
遇见你的创造者
虽然上面的情节读起来更像是一个负责任的赌博广告,而不是一个关于概率概念的帖子的开头,但我提到的两件事实际上与这个故事的其余部分有关联。第一,许多人对体育、政治和娱乐结果的赔率是如何产生的感到好奇——他们不断被告知,博彩公司总是赢,你赌他们输,后果自负。第二个是“庄家让你的球队赢的赔率是多少”这句话。一个价值数十亿英镑的行业真的不依靠员工简单地“凑数”吗?为了回答这个问题,我们需要看看一些概率历史和理论(我绝对意识到这是我开始在社交媒体上失去大多数猫视频读者的地方)。
让我们从简单的抛硬币开始。假设硬币是公平的,那么如何推导正面或反面的概率呢?一半是经典的正面一半是反面,对吗?
你当然是对的,但也许不是你想的那样。我们都知道在掷硬币中 50/50 的几率实际上是它的理论概率。给定一个公平的硬币,我们假设硬币有两种同样可能的落地方式,并且只有一种方式得到正面或反面。证明这一点的唯一方法是进行大量独立的掷硬币试验,从这些结果中获得正面和反面的结果,然后——根据大数定律——我们估计正面或反面的真实概率为 50%。够简单吧?
类似的过程重复很多次后,事件的概率等于其相对频率的想法实际上被称为 频率主义者 对概率的解释。数学家们的这种思维方式产生于 19 世纪,主要是由过去的实验和关于机会游戏的论文中的问题和悖论所推动的。它的根源甚至比 19 世纪还要深——你可以从亚里士多德那里找到一段引文,他提到
…最有可能发生的是…
很难与数学和哲学的名人录进行辩论。然而,有一个问题,主要是当处理明确定义的随机实验时,频率主义者只讨论概率。
如同黑夜跟随白昼一样确定
博彩公司开始舔嘴唇了。考虑日出问题:“明天太阳升起的概率是多少?”现在没有人能接触到实验。这是给我们的棋子不是吗?

来自un slash的 James Peacock ( jimmyp9751 )的照片
谢天谢地,两位数学家(嗯,一位数学家和一位……牧师)为这个解决方案做出了贡献。首先,皮埃尔·西蒙-拉普拉斯分两部分回答了这个问题。第一部分是我们现在所知的无差别原则,或不充分理性原则。为了便于讨论,假设你在两千年前的某一天中午醒来。在一顿美好的午后晚餐和咖啡后,你看着太阳下山——谢谢今天。它会回来吗?我们还没有看到太阳升起,也没有特别的理由相信它会升起或不会升起。所以,我们认为这两种可能性(太阳会升起吗/不会升起)是一样的——也就是说,一半的可能性是太阳会升起,另一半是太阳不会升起。
现在来看拉普拉斯回答的第二部分。如果说过去是未来的指南,那么太阳每天升起都会增强我们的信心,让我们相信它会继续升起。因此,两千年后,明天太阳升起的概率应该非常接近 1,但不完全是,因为我们不能完全确定。拉普拉斯从这个思想实验中推导出了连续法则,估计太阳在升起 n 次后再次升起的概率为

当 n 为零时,这只是二分之一,随着 n 增加到无穷大,概率趋近于 1。比扔硬币的例子更详细一点,但仍然很简单。
或者是?
你注意到我们是如何得出太阳会再次升起的一半初始概率的吗?
这是凭空捏造的。没有进行实验。没有从整体上计算结果。 我们编造了 。它可能是三分之一,四分之三,事实上是 0 到 1 之间的任何值。由于英国长老会牧师托马斯·贝叶斯的数学著作,这种做法是可以接受的。)从十八世纪开始。他将概率描述为一种信任度,而不是一种频率。通过贝叶斯推理,当新的证据出现时,你可以更新你现有的信念,以获得你的后验信念(很像太阳升起的例子)。
事实上,贝叶斯去世时并没有发表使他出名的定理,但是他的足够多的弟子挖掘出了他的著作,这些著作在接下来的 200 年里使整个行业受益。它甚至被用来解决改变历史的实际问题——二战期间,德雷福斯上尉的辩护者用它来证明自己的清白,而艾伦·图灵用它来解码英格玛机器。Bayes 备受尊崇,以至于“Bayesianism”在数学和科学领域的成员中获得了近乎宗教般的追随者。
让我们在 2000 年见面吧
不管怎样,既然我们已经给“有根据的猜测”这个短语赋予了意义,我们回到博彩公司如何给事件和结果定价的问题上来。当这个行业为某个特定事件雇佣“交易者”时,他们真正的意思是雇佣在某个主题或运动上有广泛领域知识的人,他们的意见有希望比一般人更有价值。简而言之(我一点也没有贬低这个职业),交易者是真正的专业猜测者。本周末利物浦赢伯恩茅斯的可能性有多大?八比一,他们真的很好,而另一个队不是。谁赢得了今年的追逐赛冠军?可能是短跑运动员萨克,三比一,他状态很好。谁将成为下一任美国总统?出于这样或那样的原因,唐纳德·特朗普是二对一。

约克赛马场。照片由克里斯·肯德尔(克里斯·肯德尔)来自 Unsplash
作为一个交易者,你希望你的知识能让你在为一个事件定价时比其他博彩市场更有优势。当你因为任何原因改变赔率时,你实际上是在利用贝叶斯推断随着更多信息的到来更新最初的假设(主要是“跟随金钱的重量”,这是每当讨论博彩时经常出现的另一个短语)。但是,如果一个交易者对自己的胜算不够自信怎么办?
如果你知道,你就知道,如果你不知道,那么..缺少一个 P45,答案是让某人更精明弥补赔率。2000 年 6 月,一家名为 Betfair 的博彩交易所成立,其理念是让客户的博彩更加公平,但也部分出于这个目的。任何人现在都可以请求一个尚不存在的市场(足球比赛结果、英国下任首相、年底比特币的价格),弥补自己的赔率,并根据他们对事件将发生的信心进行相应的下注(例如,100/5/1 比 2/5/1 表示更相信某事会发生)。接下来就要看其他人是否接受赌注的另一方了,一旦有一大笔钱在数千(如果不是数百万)投机者之间转手,你就会突然对某个结果有非常好的概率估计。无论博彩公司或下注者知道与否,他们都在一夜之间开始从事贝叶斯定理的巨大概念证明。
最后一点,但必发在首次推出时实际上收到了很多负面宣传,因为传统博彩公司对他们的选择的口号不是很满意,并游说禁止交易所-引用各种借口,从作弊到洗钱。如今,有三四家大型博彩交易所,许多高街博彩公司在承诺任何事情之前都在等待他们的赔率。有时候事情会变得很有趣。
#RequestABet
每一部历史作品通常都以某种对我们所学知识的回顾和对未来的预测作为结尾。嗯,我们刚刚讨论了贝叶斯,我不知道接下来会发生什么。我们的朋友拉普拉斯可能会要求对未来十年必发的情况进行预测,在他认为最有可能的选择上下注,并定期登录直到 2030 年,看看他是否正确。那对我来说真是太好了——比起不得不自己猜测一个结果来结束一篇博文,我会更喜欢这样。
其他文章
为什么赢得超级碗的球队比英超多?
towardsdatascience.com](/randomness-in-sport-6e60c6132838) [## 用 GgPlot2 预测足球比分
使用泊松帮助可视化足球正确的分数在 R
towardsdatascience.com](/forecasting-football-scores-with-ggplot2-949de7c1cb52)
让你的损失函数有价值
有些错误比其他错误代价更高;你的模型学习的方式应该反映这一点
乔治·奥威尔的中篇小说《动物庄园》中有一句令人难忘的台词…
所有动物都是平等的,但有些动物比其他动物更平等
奥威尔可能一直指的是社会中的虚伪、权力和特权,但如果你用 错误 取代 动物 ,它就开始变得与机器学习非常相关。
既然我已经假装博学多闻了,那就来点具体的吧。
了解你的错误
解释误报和漏报的概念是一个常见的面试问题,因为它们在实际应用分类算法时非常重要。
我有时仍然会发现自己在开会前匆忙查阅维基百科,反复检查我是否使用了像 precision 这样的术语,并回忆起正确的方法。对于这篇文章,你应该只需要记住…
- 假阳性是指模型预测到某个条件存在,但实际上并不存在(例如,没有火灾时火警响起)。
- 假阴性是指模型预测该条件不存在,但实际上却存在(如发生火灾时,烟雾报警器未能响起)。
先不说定义,让我们假设你在一家银行工作,你的老板要求你建立一个模型来识别欺诈客户。在进行任何建模之前,重要的是要问…
如果我的模型出错了会怎么样?
我的意思不是从统计的角度问这个问题,而是真正理解这对业务意味着什么。
您得到的答案将决定您如何评估和部署您的模型。

代表欺诈检测模型输出如何使用的两个场景。图片作者。
在场景 1 中,您的模型在将客户标记为欺诈时不需要如此自信,因为接下来会进行更详细的人工审查,并且您会期望欺诈团队过滤掉误报。
相反,在场景 2 中,当客户被标记时,风险更大,因为他们被自动暂停。如果有太多的误报漏网,那么你就是在让无辜的顾客暂停服务,给他们一个不愉快的体验,并产生负面影响。
确定模型应该有多严格或多宽松的最佳点是一个相当平衡的行为,因为以减少假阳性为目标必然会导致假阴性的增加,反之亦然。
找到正确的平衡

考虑到假阳性率和假阴性率之间的权衡,可以更有创造性地使用模型的输出。
二元分类模型通常会对概率超过 50%的任何事物进行分类,但是如果您担心误报率过高,您可以使用更高的阈值,例如,仅当欺诈客户的预测概率超过 80%时才对其进行分类。
或者业务可以遵循场景 1 和 2 之间的混合方法,其中预测概率为 80%或以上的客户被自动暂停,而任何在 50%和 80%之间的客户都与欺诈团队共享,以进行更严格的审查。
这种策略通常足够有效,但最终它们涉及训练一种机器学习算法,该算法假设所有类型的错误都同等重要,然后调整其输出以纠正这种假设。
幸运的是,它可以直接影响各种机器学习算法的学习方式,并更加重视特定的错误类型。处理类不平衡的一些技术也可以达到类似的目的,即确定误报或漏报,但是本文主要通过损失函数来实现这个目标。
接受损失

汤姆·普姆福德在 Unsplash 上拍摄的照片
当涉及到深度学习时,损失函数决定了算法在学习和迭代改进时试图最小化的内容。损失函数通常默认为均方误差(回归)和交叉熵损失(分类),但是有大量的 funkier 选项可以在某些用例中更好地工作。
然而,不管函数本身如何,它们都有一个共同的目的,即它们为模型提供了一个反馈机制,以检查其性能如何,找到损失函数的梯度,并使用该梯度更新网络的权重,以尽快减少损失。
即使我们现在在谈论深度学习和更复杂、更强大的模型,他们仍然无法区分他们犯下的错误类型。
幸运的是,TensorFlow 允许您控制这一点。
获得机器学习的适应性
在我们进入代码之前,让我们看一个新的场景(我保证这是最后一个)。
你在一家休闲中心工作,那里的客户按月付费,但他们可以在每个月底更改他们订阅的价格等级。

健身房会员,每月价格计划。作者图片。
与大多数企业一样,了解客户随着时间的推移支出是增加还是减少,并预测他们未来可能会做什么是有帮助的。
为了提供这种能力,您需要构建一个模型,该模型可以从客户的特征中学习,并预测他们是否会提高、降低或保持相同的价格计划。
通过拍摄过去行为的快照,即与上个月相比,客户使用健身房的次数是多了还是少了,以及他们在同一计划上花了多长时间,可以训练一个模型来预测客户下个月将做的三个类别中的一个:
- 花费更多和交易上升****
- 保持相同的计划并保持稳定****
- 减少花费,降低价格

特性和目标变量。图片作者。**
自然,您会希望模型在所有方面都尽可能准确。然而,该模型的输出结果可能会被财务团队用来确定有多少收入会进来,以及他们有多少能力进行再投资。
在这种情况下,过高估计有多少客户会进行升级更具破坏性,因为企业期望的收入将超过它实现的收入。虽然高估客户的交易量并不好,但至少它让财务团队处于一个更有利的位置,可以获得比预期更多的收入。

与模型正确与否相关的风险。图片作者。**
有了这个商业背景,您可以直接操纵模型如何训练来反映财务团队所期望的谨慎。
弯曲张量流向你的意志

乔纳森·比恩在 Unsplash 上拍摄的照片
我们将使用 TensorFlow 和 Keras API 来演示如何实现这一点。如果你想跟随并自己执行代码,你可以遵循这里的指令。
阅读下面的代码,感受一下 Tensorflow 的灵活性。
不会忘记
希望这有助于演示您可能需要自定义损失函数的情况,以及如何实现它。
但更重要的是,永远不要忘记关键问题…
如果我的模型出错了会怎么样?
记住这一点,你就会从一个在理论上工作出色的数据科学家转变为一个在实践中工作出色的数据科学家。
当你在这里的时候
请随意查看我的其他文章:
参考
[1] G .奥威尔。《动物庄园:一个童话故事》(2018)。伦敦:企鹅图书公司。
从用户命令中提取信息
制作自己的 Alexa
Alexa 怎么知道你想让她弹哪首歌

在过去的几年里,虚拟助理风靡了全世界。从像 Alexa 和 Google Assistant 这样的虚拟家庭助手,到更专业的助手,比如美国银行的 Erica 。这些助手的迅速崛起表明,我们与机器互动的方式正在发生变化和演变。
在这个由 3 部分组成的系列文章中,我们将介绍如何使用 Amazon Alexa 使用的域无关解析器的一个较小版本和一个命令分类模型,在 Keras 中自下而上地编写自己的简单虚拟助手或聊天机器人。
阅读完本系列后,您将学会如何创建自己的虚拟助手,该助手足够简单,可以在 Raspberry Pi 或 AWS Lambda 上运行,但功能足够强大,可以用作企业解决方案的基础。
概观
该系列将分为三个部分:
- 从用户命令中提取重要的值和信息
- 意图分类
- 语音命令、唤醒词、知识图表和应用程序
每篇文章将涵盖一个单独的主题,这是制作语音导航虚拟助理不可或缺的。这第一篇文章将教你如何从用户发送的命令中提取实体。第二部分将教你如何构建一个网络,对命令进行分类,以便它们可以被发送到正确的意图处理器,允许你的助手处理多个意图。第三部分将介绍一些不同的想法,关于如何在你的助手中加入对语音命令的支持以及其他各种改进。
背景
想象一下,你在一家银行工作,你的工作是为客户在账户之间转账。一天,一位顾客走进来,提出了以下要求:
"你能从我的储蓄账户转 50 美元到马克的账户上吗"
为了能够满足这个请求,作为一名工作人员,您需要能够从请求中提取三个关键值。您需要提取:
- 他们想转账多少(50 美元)
- 从哪个账户(你的储蓄账户)
- 谁应该收到钱(马克)
由于我们从出生起就被训练从语言中提取信息,这项任务对一个人来说很容易,但对一台计算机来说却很棘手。模拟这一过程并准确提取这一信息是我们的模型将面临的挑战。为此,我们将使用命名实体识别。
命名实体识别
命名实体识别(NER)是信息抽取的一个子任务,它试图在非结构化文本(或半结构化文本)中定位命名实体。NER 的目标是给序列中的每一个单词加上标签,代表这个单词所属的实体的种类。

图 1:给音乐服务的命令中的命名实体的例子
图 1 展示了一个通过 NER 模型解析的句子的例子。使用 IOB 方案(内部-外部-开始)标记句子中的每个单词,并附加一个连接标签来标记用于连接不同命名实体的单词。这些标签然后被用来从我们的命令中提取实体。从图 1 中的标签,我们可以提取出我们希望服务播放的歌曲是“波西米亚狂想曲”,艺术家是“女王”。
既然我们知道了问题以及我们将使用什么方法来解决它,那么是时候开始编码了!
履行
数据
在我们写真正的代码之前,我们需要一些实际的数据来处理。幸运的是,我们准备了示例数据,我们将在本文中使用这些数据。
{
"labels": [
"O",
"CC",
"B-song",
"I-song",
"B-artist",
"I-artist",
"B-playlist",
"I-playlist"
],
"training_data": [
{
"words": [
"play",
"don't",
"pan",
"me",
"by",
"alberta",
"hunter"
],
"labels": [
"O",
"B-song",
"I-song",
"I-song",
"CC",
"B-artist",
"I-artist"
]
}
]
}
上面的摘录展示了我们将要使用的数据模式的一个例子。我们已经将该命令所有可能的标签编译到labels 中,并将所有命令标记化并标注到training_data中,其中training_data['words']是模型的输入序列,training_data['labels’]是预期的输出序列。
准备数据
正如任何涉及神经网络的项目一样,我们需要在使用它们之前准备好序列。神经网络不喜欢被输入字符串或字符。他们喜欢冷冰冰的硬数字!
所以首先,我们需要建立一个词汇表。词汇表是我们网络中所有已知单词的容器。这个词汇表将被我们的模型用来创建一个嵌入层(稍后会详细介绍)。
你可以使用一个预建的词汇和标记器,比如 FastText 或 SentencePiece 来为你的模型提供词汇,但是对于小型虚拟助手来说这是不必要的,只会导致模型变得臃肿,而不会有任何有意义的准确性增加。只有当您的用例需要更大的词汇表并从它们的包含中受益时,才使用它们!
例如,在我们对 FastText 的实验中,其中一个模型的大小约为 1GB。但是,对于较小的自定义词汇表,模型大小约为 15MB。两个版本在准确度、精确度和召回率上的差异几乎不存在。
也就是说,让我们创建自己的自定义词汇表吧!
dataset = [Dataset](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/datautils.py#L9)(schema_path, name)
labels, data = dataset.get_data()X = [x['words'] for x in data]
y = [x['labels'] for x in data]# Word vocabulary
word_vocab = [Vocabulary](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/datautils.py#L83)()
word_vocab.build_vocab([w for command in X for w in command])# Character vocabulary
char_vocab = [Vocabulary](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/datautils.py#L83)()
char_vocab.build_vocab([ch for w in word_vocab for ch in w])
在上面的代码中,我们加载数据,并从数据集中的命令中收集所有唯一的单词和字符。除了所有的单词之外,我们还为以前没有见过的单词和字符在词汇表中添加了<unk>和<pad>标记。<unk>令牌允许我们将词汇量保持在一个固定的大小,它允许模型处理它不认识的单词。<pad>标记允许我们屏蔽序列中的填充,这样它就不会被误认为是命令的一部分。这个标记是必要的,因为我们的命令的长度可以变化,但是模型期望它们都是相同的长度。

图 2:一个映射函数的例子
现在我们有了词汇表,我们需要创建一个映射函数来从单词映射到整数。这允许我们将数据集中的单词序列转换成整数序列。幸运的是,当单词被添加到字典中时,我们的词汇表类的实现已经为我们完成了这项工作。
最后,我们将为标签创建一个映射函数。
labels2idx = {label: idx for idx, label in enumerate(labels)}
如果您想知道为什么我们同时使用字符词汇表和单词词汇表,那是因为字符嵌入对于跨上下文的概括非常有用。这有助于我们的模型预测一个词的标签,当这个词不在我们的词汇表中时,就像获得<unk>令牌的词的情况一样。这是因为该单词的所有字符都应该出现在字符词汇表中。
现在我们的数据准备工作已经完成,我们可以开始制作模型了。
模型
我们将用来实现 NER 的模型被称为带有字符嵌入的双向 LSTM-CRF 模型。我们将要使用的模块可以在这里找到。在模型中,我们将使用七种不同类型的层。
嵌入层是由整数 id 表示的文本数据(单词/字符/句子)被转换成密集的固定大小向量的层。然后可以训练这一层,使向量代表单词背后的意思,意思是具有相似意思的单词将得到相似的向量。
LSTM 层是递归层,将序列作为输入,可以返回序列(return_sequences=True)或展平输出。
双向层是将两个方向相反的隐藏层连接到同一输出的包装层。当需要输入的上下文时,例如标记单词序列时,它们很有用。本质上,它们允许序列中的一个位置拥有序列中在它之前和之后的所有信息。
时间分布层是包装层,允许我们将一个层应用到输入的每个时间片。Jason Brownlee 在他关于时间分布层的文章中比我更好地解释了这个概念。
丢弃层是一种正则化技术,包括在训练期间的每次更新时将一部分权重设置为 0,以防止过度拟合。该分数由图层使用的超参数决定。
密集层或全连接层是全连接神经网络层,其中每个输入节点连接到每个输出节点。它们对输入进行简单的线性变换。
条件随机场(CRF)层学习哪个标签序列最有可能。例如,它可以了解到在序列中 O 标签不应该直接出现在 I-Song 标签之前,并且 I-Song 只能出现在 B-Song 或 I-Song 之前。
# Word Embeddings
word_in = **Input**(shape=(None,))
word_emb = **Embedding**(input_dim=self.n_words+1, output_dim=100)(word_in)# Character Embeddings
char_in = **Input**(shape=(None, None,))
char_emb = **TimeDistributed**(**Embedding**(input_dim=self.n_chars + 2,
output_dim=10, mask_zero=True))(char_in)
char_enc = **TimeDistributed**(**LSTM**(units=20, return_sequences=False,
recurrent_dropout=0.5))(char_emb)concat = **concatenate**([word_emb, char_enc])
concat = **SpatialDropout1D**(0.3)(concat)
bi_lstm = **Bidirectional**(**LSTM**(units=256, return_sequences=True,
recurrent_dropout=0.3))(concat)
bi_lstm = **Bidirectional**(**LSTM**(units=256, return_sequences=True,
recurrent_dropout=0.3))(bi_lstm)fully_conn = **Dense**(self.n_labels, activation="relu")(bi_lstm)crf = **CRF**(self.n_labels, sparse_target=False)
pred = crf(fully_conn)self.model = Model(inputs=[word_in, char_in], outputs=pred)
self.loss = crf.loss_function
self.accuracy = crf.accuracy
在我们的模型中,我们有两个输入:
- 单词 id 的数组。
- 一个字符 id 矩阵,其中每一行映射到我们的单词序列中的一个单词。
我们要做的第一件事是将两个输入输入到一个嵌入层,该层将每个数组中的 id 转换成密集的固定大小的向量。这个过程的一个例子可以在图 3 中看到。

图 3:嵌入层将整数 id 数组转换为固定大小向量数组的示例。
您可能会注意到, LSTM 层将字符嵌入向量作为输入,它被一个时间分布式包装器所包装。这使得 LSTM 层被应用于输入的时间切片,而不是整个输入张量。图 4 直观地解释了包装器是如何工作的。

图 4: a)显示了如果一个常规的 LSTM 层被应用到我们的字符嵌入层的输出会发生什么。b)显示当我们用时间分布来包装层时,LSTM 层被应用于秩 3 张量[word,timestep,char]而不是秩 4 张量[batch,word,timestep,char]。
因为我们有了return_sequences=False我们的时间分布 LSTM 层减少了平坦化它的输出,所以输出张量的秩从 4 到 3。现在我们可以把它和单词 embeddings 连接起来。
char_enc = **TimeDistributed**(**LSTM**(units=20, return_sequences=False,
recurrent_dropout=0.5))(char_emb)
接下来,我们将级联的输入馈送到一个双向 LSTM 层。该层输出输入句子中每个单词的上下文嵌入。这将捕获单词在句子中的位置信息。
其次,我们将上下文嵌入提供给一个完全连接的层,该层将每个上下文单词嵌入映射到输出标签上的分布。
最后,我们将密集层的结果反馈给 CRF 层。该层从从密集层获得的张量中选择最可能的输出标签序列。
图 5 显示了模型的图表以及输入和输出维度。

图 5:bil STM-CRF 模型的图表。特别注意字符嵌入的输入和输出是如何变化的(左侧)。此外,如果一个尺寸的大小是 None ,那么这意味着模型不关心该尺寸的大小,只要它在每批中是一致的。
关于 Keras 中双向的实现,需要注意的一点是,组合正向传递和反向传递的默认配置是将它们连接在一起。这意味着我们为 LSTM 层选择的输出尺寸加倍了。但也有其他选项,例如让图层将结果相加或返回平均值,从而保持输出大小不变,而不是翻倍。
培养
既然我们已经介绍了如何准备我们需要的所有数据和模型的结构,现在是开始培训的时候了。
首先,我们将创建一个序列 对象来为模型准备迷你批处理。通过使用序列对象,我们可以在将每批数据发送到网络之前对其进行预处理。这简化了我们的代码,因为它允许我们一次只准备一批,而不是担心整个数据集。我们的 Sequence 对象相对简单,它与 Keras 文档给出的例子基本相同。
preprocessor = [Preprocessor](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/preprocessing.py)(word_vocab, labels2idx, char_vocab)
接下来,我们将创建一个预处理器来处理批处理的预处理。它将我们的映射函数作为参数,以便它们可以用来将我们的单词、字符和标签标记转换成整数 ID 标记。
model = [BiLSTMCRF](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/model.py#L11)(labels, len(word_vocab), len(char_vocab))
trainer = [Trainer](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/trainer.py#L7)(model, X, y, [0.75, 0.95])batch_size = 64
trainer.train(batch_size, preprocessor)
现在让我们初始化模型,并创建一个 Trainer 对象来负责训练和评估模型。训练集和验证集将在训练过程中使用,以提高我们的 NER 模型的质量,测试集将在最后使用,以查看模型在以前没有见过的数据上的表现。训练集将包含 75%的数据,验证集将包含 20%,而我们的测试集将包含 5%。这些比率一点也不神圣,所以你可以随意使用不同的比率,看看什么最适合你。
train_seq = [DataSequence](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/datautils.py#L83)(self.x_train, self.y_train, batch_size, preprocessor)
val_seq = [DataSequence](https://github.com/Skuldur/virtual-assistant-tutorial/blob/master/datautils.py#L83)(self.x_val, self.y_val, batch_size, preprocessor)self.model.train(train_seq, val_seq)
一旦我们分割了数据并创建了训练者对象,我们就可以训练模型了。我们的 DataSequence 对象接受一个输入、一个输出、每个批处理的大小和一个预处理函数作为参数。
现在我们可以开始训练模型了!
self.model.compile(
loss=self.loss,
optimizer='adam',
metrics=[self.accuracy]
)self.model.fit_generator(
generator=train_seq,
epochs=10,
verbose=1,
shuffle=True,
validation_data=test_seq,
)
为了计算模型的损失,我们将使用 CRF 损失函数。我们将使用具有默认设置的 Adam 优化器,我们要跟踪的指标是模型的准确性。为了训练模型,我们将使用 Keras 中的[fit_generator()](https://keras.io/models/sequential/#fit_generator)方法。这个方法允许我们使用由序列对象逐批生成的数据来训练模型。从而让我们对训练过程有更多的控制。
图 6 显示了四个时期的训练示例。正如你所看到的,我们的模型在维基数据集的第二个时期达到了 100%的准确率。这意味着我们的模型能够从每个给定的命令中提取正确的信息。

图 6:关于 Wiki 数据集的四个时期的训练会议
在我们自己的虚拟助手中,使用的方法与本文中展示的方法相同,我们对任何单一意图的最低准确率约为 99.5%。其余的有大约 100%的准确性。因此,我们可以看到,这个模型在从文本命令中检索实体方面非常有效。
结论
祝贺您完成了本系列的信息提取部分。读完这篇文章后,你应该明白 Alexa 和其他虚拟助手和聊天机器人是如何从你的请求中提取信息的,以及你如何创建模型来做同样的事情。如有任何问题,欢迎联系我或留言。
在下一部分中,我们将研究我们的助手如何选择哪个 NER 模型来处理传入的命令。
给读者的建议
- 尝试用 FastText 和 SentencePiece 替换自定义词汇表,看看是否有什么改进。它可能有助于更复杂的意图。
- 尝试使用变压器(BERT)代替双向 LSTM 网络。请注意网络质量和模型大小之间的权衡。模型对 Lambdas 或你的树莓派来说变得太大了吗?
- 在我们的模型以目前的规模开始挣扎之前,一个意图可以有多少不同的命令?
- 在 Pytorch 中实现模型。
让你的 Ubuntu 深度学习做好准备
在 Ubuntu 中安装 Nvidia 驱动程序、Cuda、cuDNN、TensorFlow、Keras & PyTorch

照片由 freestocks 在 Unsplash 拍摄
偶然发现很多安装深度学习库的指南,Cuda,cuDNN & nvidia-driver。但是我从来没有在只跟随一个向导的情况下一次成功。所以,我决定写这篇文章。首先,本指南是安装有 GPU 支持的深度学习库(TensorFlow,Keras,PyTorch)。CPU 支持非常简单,所以我不会谈论它。
你需要一个
具有 CUDA 计算能力 3.5 或更高的 NVIDIA GPU 卡。
你可以通过访问这个链接来检查你的 GPU 是否兼容。
安装 Nvidia 驱动程序
运行以下命令。它添加了下载 Nvidia 驱动程序所需的存储库。会的
sudo add-apt-repository ppa:graphic-drivers/ppasudo apt updateubuntu-drivers devices | grep nvidia
它会显示与您的 GPU 卡兼容的驱动程序版本。我有一张 RTX 2060 超级 GPU 卡。它显示
driver : nvidia-430 — third-party free recommended
根据您使用的 GPU 卡,它可能还会显示多个条目。例子
driver : nvidia-340 — distro non-free
driver : nvidia-304 — distro non-free
driver : nvidia-384 — distro non-free recommended
安装合适的版本。你的驱动将决定你将要安装的 CUDA 的最低版本。你可以在这里找到表格。
sudo apt install nvidia-xxx
用你想要的版本替换xxx。重新启动并检查安装
sudo reboot
lsmod|grep nvidia
nvidia-smi
安装 CUDA 和 cuDNN
从这里下载 CUDA 安装程序。我更喜欢从运行文件安装。安装并添加PATH和LD_LIBRARY_PATH变量中的路径。用您的路径替换 Cuda 的路径(在我的例子中是/usr/local/cuda-10.1/)。
./cuda_10.1.105_418.39_linux.runecho “export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64:$LD_LIBRARY_PATH”>> ~/.bashrcecho “export PATH=/usr/local/cuda-10.1/bin:$PATH”>> ~/.bashrc
访问此表获取经过测试的构建版本。检查您需要安装的 cuDNN 版本。从这里下载 cuDNN。我更喜欢压缩版本。

下载后解压并复制文件到 CUDA 目录。
tar -xzvf cudnn-x.x-linux-x64-v8.x.x.x.tgz
sudo cp cuda/include/cudnn*.h /usr/local/cuda/include
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*
安装 Tensorflow、Keras、Pytorch
使用安装 TensorFlow 和 Keras
pip install tensorflow-gpu==2.2.0 keras
要安装支持 GPU 的 PyTorch,请访问此链接。选择版本、操作系统、语言、软件包安装程序、CUDA 版本,然后按照下图中突出显示的部分进行安装。

这就是了。现在使用这些 python 脚本来验证您的安装。
张量流代码
from tensorflow.python.client import device_lib
def get_available_gpus():
local_device_protos = device_lib.list_local_devices()
return [x.physical_device_desc for x in local_device_protos if x.device_type == 'GPU'] get_available_gpus()
Pytorch 代码
import torchdef get_available_gpus():
return [ torch.cuda.get_device_properties(i) for i in range(torch.cuda.device_count())] get_available_gpus()
这就是了。
所有库都已安装。现在打开你的创意模式。
参考
[## cuDNN 安装指南::NVIDIA 深度学习 SDK 文档
本 cuDNN 8.0.0 预览版安装指南提供了如何安装和检查的分步说明…
docs.nvidia.com](https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html)
【https://stackoverflow.com/a/38580201
具有视觉模式识别的恶意软件分析
快速逆向工程二进制文件的秘密

以 Hiew 文本模式显示的 32 位 PE 文件
第 1 部分:简介和基本模式
我最初写这篇文章是为了让恶意软件分析人员受益,当时我在赛门铁克的安全响应团队工作,每天分析和分类 20 多个文件。“扩展 ASCII 分析”是一种通过模式识别快速获得对文件的高级理解的技术。这种技术对于不能在每个文件上花很多时间的分析师来说是非常有益的。对于许多类型的恶意软件,它可以在几秒钟内准确分类。这项技术包括训练你的视觉系统来识别原始二进制文件特有的模式。本文旨在作为介绍和参考,但可能需要检查数百或数千个文件才能熟悉这项技术。它还旨在为在恶意软件分类中使用卷积神经网络提供直观的理由,卷积神经网络通常在与人类视觉系统相同的任务中表现良好。我认为这种类型的领域知识对于构建对输入分布的变化具有鲁棒性的模型是必不可少的(更多信息请参见https://towardsdatascience . com/co variate-shift-in-malware-classification-77a 523 DBD 701)。我在 2014 年写了这篇文章的原始版本,所以一些特定的恶意软件截图可能已经过时了,但基本概念仍然适用。
有些文章假设读者熟悉 windows 二进制逆向工程,特别是熟悉可移植可执行文件(PE):windows 的文件格式。exe 和。dll 文件。该技术也可以提供对其他文件格式的洞察,但是考虑到 windows 可执行恶意软件(和良性文件)的数量,它们是一个很好的起点。然而,即使你不熟悉逆向工程,我希望这篇文章能够展示在其他类型的原始数据上训练/应用你的视觉系统的价值。原始数据之所以难以解释,可能只是因为你没有对其进行足够的观察,以找出模式:一旦你开始认识到模式,你可能会注意到一些被更多处理过的可视化所遗漏的东西。
问题是
有许多二进制分析工具可以显示文件各部分的具体信息。例如, Resource Hacker 显示 PE 文件中的资源,string dumpers 显示字符串, PEID 显示 PE/packer 信息等。运行大量工具并组合它们的输出以形成结论可能需要相当多的时间。因为这些工具中的大部分都提供了一个经过处理的表示,集中在二进制文件的特定方面,所以有些字节可能会被完全忽略。大多数工具也依赖于文件类型,因此依赖它们意味着分析不熟悉的格式很有挑战性。

不同的工具为一个文件提供了不同的视图,但通常不会提供一个既全面又能快速消化的概述
虽然IDA——业内最流行的交互式反汇编器/反编译器——允许对大多数可执行文件进行相当完整的分析,但识别文件的加密/压缩区域需要时间。因为 IDA 侧重于分析代码,所以识别加密数据通常涉及识别解密代码。同样,这可能非常耗时,并且识别加密数据对于恶意文件来说是至关重要的。大多数常见的恶意软件都是使用低熵定制打包程序打包的,旨在避开防病毒软件。像 PEID 这样的识别打包的可执行文件的工具不能始终如一地工作,因为许多打包程序检查是基于已知的打包程序或文件熵。PEID 也不能将一个特定的打包程序与一个特定的威胁联系起来:如果可以的话,那么它本身就可以成为一个伟大的反病毒引擎。获取文件中所有字节信息的更快方法对于形成第一印象是理想的。
解决办法
滚动浏览 Hiew 的文本视图(或在十六进制编辑器中打开文件,甚至是 notepad.exe ),显示二进制文件中的所有数据,每个字节由一个扩展的 ASCII 符号表示。不同的数据模式导致不同的符号模式。因为人类的大脑非常善于识别视觉模式,它可以非常快速地对数据进行分类。常见的数据类型包括:
- 原生代码(x86、x64、ARM 等。)
- 微软中间语言(MSIL)
- 加密很差的数据
- 高熵数据(压缩/加密良好/随机数据)
- 形象
- 搬迁科
- 字符串(包括非罗马字母)。
识别加密较差的数据可能非常有帮助,因为这通常表明是用于避免抗病毒的自定义打包程序,而不是可能用于压缩和保护的商业打包程序。
例如,许多木马。Asprox.B 样本(见下图)以一种非常一致的字节模式加密。这意味着有可能在不到一秒钟的时间内识别它们。

特洛伊木马的加密部分。Asprox.B:即使数据被加密,许多重复的模式也是可见的(表明加密是脆弱的)
虽然这在技术上给出了文件中(几乎)每个字节的信息,但它并不适合所有类型的分析。
限制
这种方法侧重于广泛的理解而不是深刻的理解:
- 它可以用来识别代码,但是理解代码仍然需要一个反汇编器/反编译器
- 它可以用来识别嵌入在 PE 文件中的图像,但是查看实际的图像仍然需要图像查看程序
- 它可用于识别加密/压缩的数据,但您必须先解密/解压缩数据,然后才能对其进行进一步分析
将数据视为符号而非十六进制数字,可以使人类模式识别更快、更容易。
ASCII 背景
这种方法的关键是将文件中的每个字节映射到 256 种不同符号中的一种,然后使用大脑的模式识别能力来解释结果。正式 ASCII 仅使用 7 位:0x00 至 0x7F。这仅包括所有可能符号的一半,其中大部分是“可打印”符号,如字母数字字符。为了使用这种技术,我们需要一种方法来为每个字节打印一个符号,然而不同的计算机系统对第 8 位的处理是不同的。Windows 将不同的字符映射称为“代码页”,两种常见的代码页是 ANSI 和 OEM。
ANSI 是指 Windows 代码页;默认名为“Windows-1252”。这个代码页没有映射每个字节:0x81,0x8c,0x8f,0x90,0x9D 没有映射到任何符号,通常显示为“.”或者呢?。因此,它们是不可能区分的,这就隐藏了信息。
OEM 指的是控制台/DOS 应用程序。来自 IBM PC 的代码页被称为代码页 437。它将所有字节映射到符号;但是,它将 0x00、0xFF 和 0x20 映射到同一个符号,即一个空格。这在实践中很少引起问题。

每个字节到一个符号的映射
您可以在标准文本编辑器(如记事本)中使用这种技术。但是,这造成了一些控制字符的问题,并且缺少功能。我个人用的是十六进制编辑器“Hiew”。
模式和高熵数据背景
如前所述,快速识别模式是这种技术的主要目的。识别良性模式以关注潜在恶意模式的能力对于恶意软件分析至关重要。更定量地考虑模式的一种简化方法是计算某些字符和字符序列在一个数据块中出现的频率。通常,一些字符/序列是普遍存在的,而另一些字符/序列是罕见的。例外是高熵数据,其中大多数字符出现的次数大致相等。请注意,在安全行业中,“熵”通常计算为分类分布的熵,其中每个字节都是其自己的类别,一个字节的概率由它在我们考虑的数据块中的频率给出。由于这是一个单变量分布,它没有捕获与字节的相对位置相关的结构。然而,在这里我将使用术语“高熵”来指看起来均匀随机的数据,即使是字节序列。下图是高熵数据的一个例子

高熵数据
高熵数据通常表示以下四种情况之一:
- 压缩数据
- 加密良好的数据
- 随机数据
- 加密计算中使用的常数。
在一个完美的高熵文件中,每个字节平均每 256 个字节出现一次,或者大约 0.39%的时间。下图显示了高熵文件(在本例中是一个. zip 文件的块)中最常见的字符和两个字符的序列的出现频率。虽然前 20 个最频繁出现的字符中没有一个出现的概率是 0.39%,但它们都相当接近。这种差异可以用抽样误差来解释。

高熵数据样本中最常见的一元和二元模型出现的频率
在这一节中,我将讨论如何识别标准编译代码产生的模式。这显然是可执行文件中的常见模式。
x86 (32 位)代码

x86 代码的示例
我从大约 7kb 的 x86 代码中生成了下面的图像。它显示了代码中一些最常见的字符/序列,以及(非常)粗略地显示了它们对应的操作码。这个例子并不代表所有可能的 x86 代码,因为不同的编译器/源代码会生成不同外观的编译代码。例如,一些编译器/编译器选项在 16 字节边界上对齐函数,一些在 4 字节边界上对齐,一些不对齐。有些编译器用 nop 填充,有些用 int3。显然不同的源文件会产生不同的编译文件。然而,在训练你的视觉系统之后,通常很容易识别所有类型的 x86 代码。

x86 代码中最常见的序列如何映射到操作
有几点需要注意:0x00 和 0xFF 是最常见的,通常以偏移量的形式出现(例如,jmp 指令中使用的偏移量)。这些字节映射到空格,并在 x86 代码中产生可见的间隙。在这段代码中,编译器使用 int3 (CC)指令作为函数之间的填充。函数开始/结束所涉及的序列是普遍的(padding,push ebp,mov ebp esp 用于开始,ret,padding 用于结束)。在对这样的序列进行一些定位练习后,立即识别 x86 数据变得容易多了。
结论
不幸的是,要熟悉这种技术可能需要检查成百上千个恶意和良性样本。如果您经常对文件进行逆向工程,我强烈建议您尝试一下,即使最初需要一段时间来获得有用的信息。长期以来,使用弱加密的恶意打包程序一直是恶意软件作者用来隐藏其攻击的主要工具之一,但仿真等现代技术可以通过拆开有效负载(比打包的文件更容易识别)来帮助发现这些攻击。了解文件结构还可以帮助启发和指导恶意软件检测模型,如用于恶意软件检测的神经网络https://medium . com/ai-ml-at-Symantec/deep-learning-for-malware-classification-dc9d 7712528 f。
第 2 部分:模式图谱
在这一部分,我回顾了我经常遇到的大量模式。如果你想学习这项技术,这可以作为一个参考。
x64 代码

x64 代码示例
64 位代码与 32 位代码有许多相似之处:偏移量和填充仍然存在,并且许多操作映射到相同的字节。最明显的区别因素是“H”字符在 64 位代码中出现的频率。

x64 代码示例中最常见的 1–4 个程序

x86 和 x64 代码的直接对比。注意,在这种情况下,x64 代码在函数之间没有填充,而 x86 代码有,但情况并非总是如此。如果你数一下每一部分中 H 字符的数量,很明显底部更多
MSIL 电码
MSIL 字节码与 x86 非常不同。几乎 25%的字节是 0x00,因此会有许多明显的间隙。

MSIL 电码的样本

MSIL 电码中最常见的 1–4g 内存
可移植可执行(PE)文件
在 windows 中,前面讨论的代码几乎总是出现在 PE 文件的上下文中(通常被视为带有。exe 和。dll 扩展),它有几种可识别的模式

PE 文件的各个部分
因为 PE 文件不仅仅包含代码,所以熟悉不同部分中出现的模式是有好处的。普通文件可能包含:
- . text 部分中的代码
- . rdata 节中的导入/导出/字符串
- . data 节中的字符串
- . rsrc 部分中的图像/版本信息
- . reloc 节中的重定位数据
- 附在末尾的签名
能够区分常见的良性数据(如重新定位数据)和潜在的恶意数据(加密不良、未知等)以快速分析文件非常重要。
以下是大量位置调整数据的示例

重新定位数据。在反汇编视图中,Hiew 突出显示了当文件加载到内存中时需要修改的全局地址对应的字节
下面是一个图标文件的例子,通常在资源部分找到并显示在资源管理器中

。ico 文件

可能出现在 PE 文件中的图标。显然,带有 PDF 图标的 PE 文件非常可疑,因为它会欺骗用户,使其认为这是一个文档而不是可执行文件
以下是附加到文件末尾的签名示例

PE 文件数字签名
可以在资源管理器中查看和验证这些类型的签名:

浏览器中的签名详细信息
当检查干净的或恶意的 PE 文件时,遇到高熵数据区域是正常的。下一节将讨论一些快速了解这些数据用途的方法,这些数据通常是出于合理的原因出现的。
高熵数据
由于压缩,许多图像格式包含高熵数据:
巴布亚新几内亚:

png 文件:大多数扩展名为. PNG 图像看起来像这样
GIF 格式

GIF 格式
联合图像专家组

联合图象专家组
压缩存档使用压缩(很明显),下面是一个. zip 文件的例子:

压缩文件
在信息论中,熵可以用来衡量随机性。除了简单地识别,人类从高熵数据中提取信息是不切实际的,因为它看起来是均匀随机的(没有重复序列之类的模式,所有字节出现的次数都相似)。然而,有时有更简单的方法来了解它。大多数高熵数据是压缩的,并且在顶部带有指示其用途的头字节。以下是一些使用压缩数据的标准格式
形象
- 联合图象专家组
- 可交换的图像格式
- png(使用 zlib)
档案
- 活力
- rar
- . tar.gz
安装人员
- Nullsoft
- Inno
- 自解压档案
自动编辑脚本
zlib 库
下图显示了附加到 PE 文件末尾的压缩数据。在每种情况下,都有一个标题,表明数据的用途(安装包、autoit 脚本)

Nullsoft 安装程序(从 NullsoftInst 开始)

Inno 安装程序(从 zlb 开始)

Autoit 脚本(有 AU3!)
以下是一个压缩闪存文件(CWS)的示例。它使用 zlib,几乎总是以 0x78 ('x ')开头。

使用 zlib 的 CWS 文件
png 和 pdf 也可能使用 zlib。
高熵数据也可以是加密/压缩常数。PEID 的“Krypto Analyzer”(KANAL)插件可以定位常见加密常量的偏移量/虚拟地址,然后可以使用 IDA 进行进一步的研究。一旦将数据识别为加密常数,就知道了它的用途,不需要进一步研究。
下面是一些单独加密的字符串,它们看起来熵值很高(加上字符串之间的间隙),因为数据不多。您可能会注意到底部有一个以“或 0”开头的块

后跟 CRC 常量的加密字符串
PEID 的 KANAL 扩展可用于研究该数据块,结果在 CRC 计算中使用了该数据块(使用原始偏移量而不是虚拟地址进行图像交叉引用)。通过实践,KANAL 不再需要寻找像 CRC 常量或 Rijndael S-box 这样的加密常量

KANAL 显示 CRC 常数的偏移
同时,IDA 可以用来研究字符串以找到解密函数

IDA 可用于查找引用加密字符串的代码(sub_1400EF84)
PE 文件中数据的位置可以提供额外的提示。如果在参考资料部分,我总是检查 PNG 文件头,因为文件有时会将它们的高分辨率图标存储为 PNG。如果附加到 PE 映像,文件可能是安装程序、autoit 脚本或签名文件(签名中有可识别的字符串)。PE 文件之外没有明显标题的高熵数据可能是某种自定义格式。有时在开头有一个长度指示器或神奇的数字,这可能会给出一些关于布局的提示。
有时,恶意软件将恶意数据隐藏在具有标准报头的高熵数据中。下面是一个例子,一个 PNG 文件有一个加密的 MZ 文件,这是显而易见的解压缩后的 PNG 的数据。查看文件中的 png 以确保它们不包含恶意数据通常是一个好主意(根据我的经验,这种情况很少见)。

包含恶意数据的 PNG 文件

UPX 收拾好文件。PE 头后面跟着高熵数据,后面跟着 x86 解密存根。
安全加密是高熵的,与随机/压缩数据无法区分。然而,恶意文件使用的大部分加密是脆弱的,并且包含容易识别的模式。下一节讨论弱加密中出现的数据模式。
弱加密
弱加密是任何容易被现代密码分析破解的加密,在实践中,它可以转化为几乎任何不为人所知且未经测试的加密方案。在复杂的攻击中,密钥可能存储在远程服务器上,或者以特定于机器的方式动态生成,除此之外,解密打包程序有效负载的加密密钥必须是二进制的,因此安全加密提供的防止密码分析的保护没有帮助。因此,大多数恶意软件打包程序的目标不是安全加密,甚至不是防止分析,而是躲避反病毒软件。因此,加密较差的数据表明该数据可能被用于恶意目的。弱加密方案的一个例子是短的 xor 密钥,在这种情况下,有时可以通过简单地查看加密数据来识别算法和密钥。请注意,使用加密来保护文件不被分析是有正当理由的:例如,知识产权保护。然而,确实有任何合法的理由来躲避反病毒产品(只要这些产品恰当地反映了用户的兴趣)。
下面是一个 PE 文件开头的 1 字节 xor 加密的例子。因为 0x00 与任何字节异或都是同一个字节,而且我们知道 PE 报头在报头和代码之间有 0x00 填充,所以很清楚密钥是什么:0xFE(方框符号)。

PE 文件的 1 字节异或加密
在这个 PE 文件被加密之后,任何可以用来检测原始 PE 文件的字节序列将不再工作。现代反病毒功能,如模拟器和动态分析,是为了防止这种类型的逃避而发明的。1 字节的 xor 密钥在实践中很少见,因为打包程序每次打包新的可执行文件时都会更改加密密钥,以避免被检测到加密数据。1 字节的 xor 密钥只允许 255 种变化(与 0 字节的 xor 不加密)。
这是同一个文件,用一个 4 字节的 xor 密钥进行 xor 运算,仍然很容易识别这个密钥

PE 文件的 4 字节异或加密。红色方框中的钥匙
下面是用 16 字节 xor 密钥进行 xor 的同一个文件

PE 文件的 16 字节异或加密
最后,这是用 64 字节 xor 密钥进行 xor 运算的同一个文件。虽然仍然有可能通过一些努力看到模式,但是看到密钥不再是微不足道的了(尽管使用标准的密码分析可能仍然很容易)。如果文件是用一个等于其长度的随机 xor 密钥加密的,那么它将是完美加密的,并且具有完美的高熵(这种“完美”类型的加密被称为一次一密)

PE 文件的 64 字节异或加密

一些重复序列在 64 字节版本中仍然可见
这里有一个使用 1 字节 xor 密钥的实际例子。下图显示了一个. jar 文件中使用的字符串集合,该集合已经过模糊处理。看到 xor 密钥并不容易,但是简单的密码分析就能轻易破解(想想字符串中出现最多的字符)。

用 JShrink 混淆
这是未加密的版本

未加密的 JShrink 数据
下一节将展示一些初看起来像弱加密的数据示例,但这是一种不同类型的数据。在实践这种技术时,在 IDA 中查找代码如何使用您不认识的数据是很有用的。
不是弱加密
区分可疑数据和良性数据需要一些实践,例如。非罗马字母语言的 ico 文件、重定位数据和字符串(如简体中文字符的 GB 2312 字符集)。
这是一个图标。即使采用弱加密,加密数据的熵也很少低于未加密数据。因此,我不会觉得这些数据太可疑,因为大多数潜在的恶意数据(代码、字符串)的熵都比这高。换句话说,存在如此多可预测的重复这一事实意味着,这部分数据可能无法在相同数量的字节中编码与普通 x86 代码一样多的信息。取决于加密算法有多疯狂,也有例外。

。ico 文件
这里有一些中国琴弦。乍一看,它们可能是加密不良的 ASCII 字符串。

从 Hiew 和 IDA 看中国弦乐
以下是各种语言/编码的字符串。有些比其他的更容易区分。

编码不同语言的各种方法
熟悉什么是加密不良的数据和什么不是加密不良的数据的最好方法是查看许多干净的和恶意的文件的例子,并检查看起来可疑的数据是如何在代码中使用的。下一节展示了使用弱加密来躲避防病毒软件的实际恶意软件的例子。
恶意软件示例
常见的 x86 恶意软件往往具有与一个或多个打包层相结合的解密代码存根。熟悉 x86 模式意味着识别代码存根通常很简单,有时甚至可以区分不同的加密层。如果 PE 文件中有很大区域的数据看起来很奇怪,那么检查内存转储中已知的恶意字符串通常是个好主意。这个过程可以让您快速确定文件的威胁,甚至不需要打开 IDA(有时比 IDA 加载文件的时间还要短)。在下面所有的例子中,如果你用同一个打包器打包任何一个文件,它看起来都差不多,尽管具体的字节会有所不同。
下面是木马的图片。它包括顶部的解包存根和底部的打包数据

Trojan.Asprox.B. x86 解包存根,后跟加密不良的数据
下面是 Trojan.Tracur 的图像,可以看到三个不同的部分:红色轮廓是 x86 解包代码,绿色轮廓是第一层,橙色轮廓是最后一层的顶部(这是一个加密的 MZ 文件)。

Trojan.Tracur. x86 解包存根,后跟加密不良的数据,再后跟不同类型的加密不良的数据
以下是特洛伊木马中的一些加密部分。Zbot 样本:

木马。Zbot 加密很差的数据

木马。带有 PE 头的 Zbot 数据加密不佳

木马。带有 PE 头的 Zbot 数据加密不佳

木马。Zbot 加密很差的数据
弱加密可以产生大量的模式,所以需要大量的练习才能一般地识别它。下一节有一些使用这种技术的技巧。
附加注释
- 对代码的熟悉使查找外壳代码变得更容易,参见下面的韩文文字处理程序利用(在开始时很容易看到“push ebp mov ebp,esp”的字节)

韩文文字处理器漏洞。一个绿框包含对应于函数开始的字节,另一个包含用于加载/引用 kernel32.dll 的数据。这些在文档文件的上下文中是非常可疑的。
- 这种技术可以应用于任何二进制文件,对于转储尤其有用
- 当使用完整的 ASCII 视图时,它还可以用于在类似于 ollydbg 的调试器中浏览内存。不幸的是,许多调试器会将正常 ASCII 范围以上的字符映射到“.”
- 有时不同的 IDEs 编译器会创建不同的文件结构,这种技术可以帮助识别/分析这些文件。下面的例子是 Delphi。在 Delphi 文件中快速获得大量信息的一个快捷方法是进入入口点(非文本模式下的 f8 f5),然后向上滚动查看自定义字符串。在 Delphi 中,字符串与代码混合在一起,库字符串更靠近顶部。

Delphi 文件
Hiew 背景
Hiew 是一个全功能的十六进制编辑器,设计时考虑了 PE 分析,非常适合这种技术。它有三种视图模式:文本、十六进制和反汇编。这种技术主要使用文本视图。虽然熟悉 Hiew 的所有功能/热键是件好事,但这里最重要的是“Enter”切换视图,“Pageup/Pagedown”滚动,F2 切换环绕/展开(确保“展开”显示在左下方“2”旁边)。文本模式下的 F8 可用于字符编码之间的切换;如果设置正确,该表应该保持“原样”(如果您看到许多“?”可能意味着它是以 Unicode 模式打开的)。
感谢 Mircea Ciubotariu 向我介绍了这种分析文件的方法,并创建了本文中使用的字体。感谢 Geoffrey So 和 Andrew Gardner 为本文提供建议和反馈。
使用卷积神经网络的恶意软件分类—分步指南
数据科学项目
关于恶意软件分类的有趣方法的快速简单的教程。

马库斯·斯皮斯克在 Unsplash 上的照片
一个恶意软件是一个通用术语,描述任何对系统有害的恶意代码或程序。
如今,有无数类型的恶意软件试图破坏公司的信息系统。因此,检测和预防是避免任何风险的关键。恶意软件分类是一个广泛使用的任务,正如你可能知道的,可以通过机器学习模型非常有效地完成。
在本文中,我决定将重点放在一个有趣的基于卷积神经网络的恶意软件分类方法上。这个想法直接来自 L. Nataraj、S. Karthikeyan、G. Jacob 和 B. S. Manjunath 的论文恶意软件图像:可视化和自动分类。
我的目标是给你一个快速简单的教程,教你如何实现他们的解决方案,从恶意软件的预处理到推理部分。希望您能够理解主要概念,并使用本文来构建自己的项目!
这个项目可以在我的 Github 上找到。
资料组
首先我们来介绍一下数据集!我们将主要使用来自前述论文的 恶意数据集 。
恶意软件数据集包含 9339 恶意软件图像,属于 25 家族/类。因此,我们的目标是对恶意软件进行多类分类。
以下是关于数据集的信息:

我们的模型将试图预测每个恶意软件属于哪个家族。类型栏仅提供信息。
预处理
从二进制到图像
由于恶意数据集已经包含了恶意图像,我将使用另一个数据集首先向您展示如何将恶意图像转换为图像。我从这个数据集中选取了示例文件。
对于每个文件,原始数据包含文件二进制内容的十六进制表示。目标是将这些文件转换成 PNG 图像,并将它们用作我们 CNN 的输入。
我们可以使用以下函数转换每个恶意软件:
下面是将0 acdb r5 m3 zhbjajygtuf . bytes二进制文件转换成 PNG 后的结果图。

0ACDbR5M3ZhBJajygTuf.bytes 至 PNG
由于这种方法,我们可以创建自己的 PNG 恶意软件数据集。然而,我不会处理整个数据集,现在将重点关注恶意数据集,其中恶意软件已经转换为图像。
而且,每个恶意软件镜像都需要放入与其类对应的子文件夹中。因此,在创建您自己的图像数据集时,不要忘记在执行下一步之前按家族将恶意软件收集到子文件夹中。
生成数据集
以下是我们的恶意软件类别/家族,作为包含png的子文件夹:

作为子文件夹的类别
ImageDataGenerator.flow_from_directory()从各自的数据目录(在我们的例子中是系列)生成批量归一化张量图像数据。多亏了这个功能,我们可以将我们的图像用于训练和测试。
- target_size :将所有图像调整到指定尺寸。我选择了(64*64)的图片。
- batch_size :是我们将要使用的批次的大小。在我们的例子中,我们只有 9339 个图像,因此设置大于这个值的批量大小不会改变任何事情。
一旦生成了我们的批次,我们可以使用train_test_split()功能在序列和测试之间分割数据,遵循(70–30)的比例。
下面是相应的代码:
ImageDataGenerator().flow_from_directory()的输出:

如您所见,由于子文件夹的名称,该函数很好地识别了 25 类。
这是我们数据集的一个示例:

样品
我们已经可以看到文件之间的一些差异。然而,对我们来说,要准确地将恶意软件划分到不同的家庭中去太难了。
快速分析
根据下图,我们的数据集是相当不平衡的:超过 30%的图像属于第二类:all ple。一个和 17%的三级:全部。L !我们将需要稍后处理这个问题。

不平衡数据集
让我们现在建立我们的 CNN 模型
CNN 模型
体系结构
现在我们的数据集已经准备好了,我们可以使用 Keras 构建我们的模型。将使用以下结构:
- 卷积层 : 30 个滤波器,(3 * 3)内核大小
- 最大池层 : (2 * 2)池大小
- 卷积层 : 15 个滤波器,(3 * 3)内核大小
- 最大池层数 : (2 * 2)池大小
- 脱落层:脱落 25%的神经元。
- 展平图层
- 密集/全连接层 : 128 个神经元,Relu 激活功能
- 脱落层:脱落 50%的神经元。
- 密集/全连接层 : 50 个神经元,Softmax 激活功能
- 密集/全连接层 : num_class 神经元,Softmax 激活函数
输入的形状为【64 * 64 * 3】:【宽高深】。在我们的例子中,每个恶意软件都是一个 RGB 图像。
下面是相应的代码:
不平衡数据
有几种方法可以处理不平衡数据。我选择给少数阶级较高的权重,给多数阶级较低的权重。
sk learn . utilis . class _ weights函数使用 y 的值自动调整输入数据中与类别频率成反比的权重。要使用这种方法, y_train 不能被一键编码。
结果
在对我们的模型进行训练和测试之后,我们最终达到了 95%的准确率,这还不错!

绘制混淆矩阵可以给我们一些提示,告诉我们在分类过程中哪里出错了。

混淆矩阵
我们可以观察到,虽然大部分恶意软件被很好的分类,自动运行。K 总是被误认为允儿。答。这大概是因为我们的 Autorun 的样本非常少。K 在我们的数据集中,并且两者都是 close Worm 类型的一部分。
而且, Swizzor.gen!E 就是经常被误认为 Swizzor.gen!l ,这可以用这样一个事实来解释,他们来自非常相近的家族和类型,因此他们的代码可能有相似之处。
最后,我相信,由于本文中提到的预处理步骤,我们可以通过创建更大的数据集来大大提高模型的性能。现在就看你的了!
结论
就是这样!由于这篇文章,你现在能够建立你的恶意软件图像数据集,并使用它来执行多类分类,由于卷积神经网络。
我希望这篇教程能以任何方式帮助你构建你的项目!现在,下一步可能是理解如何部署它😉
再说一次,我的目标只是给出一个关于其他人的伟大作品的简单教程,所以为他们欢呼吧!🍺
当然,我的 Github 上什么都有。
祝您愉快!
参考
以下是我找到灵感的地方:
我们提出了一种简单而有效的方法,使用图像处理技术对恶意软件进行可视化和分类…
dl.acm.org](https://dl.acm.org/doi/10.1145/2016904.2016908) [## 基于多家族恶意软件数据集的 k-fold 交叉验证监督分类
随着恶意软件及其家族数量的不断增加,将恶意软件分类到特定的家族非常具有挑战性…
sarvamblog.blogspot.com](https://sarvamblog.blogspot.com/2014/08/supervised-classification-with-k-fold.html) [## Python - DZone AI 中基于卷积神经网络的恶意软件检测
在本帖中,我们将学习人工网络架构以及如何使用其中一种(卷积神经…
dzone.com](https://dzone.com/articles/malware-detection-with-convolutional-neural-networ) [## 基于 Keras 的 CNN 图像分类器图像预处理
在这一集里,我们将演示如何使用 Keras 设置训练一个卷积神经网络(CNN)。我们的…
deeplizard.com](https://deeplizard.com/learn/video/LhEMXbjGV_4)
使用 Conda 创建可再现的数据科学和机器学习环境
使用 Conda、JupyterLab 和 Git 开发包含环境管理的工作流指南

介绍
数据科学和机器学习项目有依赖关系,我们依赖这些依赖关系来运行我们的代码,就像 pandas 或 numpy。这些依赖关系会随着时间的推移而更新,并且有不同的版本,如果使用了错误的版本,可能会导致代码中断。如果您与其他团队成员一起工作,您还需要在不同的计算机上维护相同的本地开发环境,以便代码能够成功运行。要为项目创建可复制的环境,使用环境管理器是一个很好的实践,它可以跟踪所有的依赖项——比如 Conda。
康达是什么?
Conda 是一个开源的包管理系统和环境管理系统,运行在 Windows、macOS 和 Linux 上。Conda 快速安装、运行和更新软件包及其依赖项。Conda 可以在本地计算机上轻松创建、保存、加载和切换环境。它是为 Python 程序创建的,但是它可以为任何语言打包和分发软件。
-蟒蛇文件
这篇文章将帮助您开发一个更好的工作流程来使用 Conda 管理您的环境。请随意跳过任何部分,直接跳到您需要的代码!
概述
- 安装 Anaconda
- 创建和激活 Conda 环境
- 安装和卸载依赖项
- 导出 Conda 环境
- 使用 Conda 和 JupyterLab
- 停用或删除 Conda 环境
- 命令摘要
- 可再生环境的工作流程示例
安装 Anaconda
如果您还没有安装 Anaconda,请按照这里的说明为您的操作系统安装它。安装之后,您应该会在应用程序中看到 Anaconda-Navigator。

创建和激活 Conda 环境
当您开始一个新项目时,您可以创建一个全新的 Conda 环境,或者从一个yaml文件重新创建一个现有的环境。
创建新的 Conda 环境
要创建新的 Conda 环境,请打开您的终端并键入以下命令:
conda create -n datasci-env
您将看到以下提示,询问您是否继续。键入y继续创建环境。

从 environment.yml 文件创建环境
如果您有一个包含项目依赖项的现有文件,您可以通过运行以下命令来重新创建环境:
conda env create -f environment.yaml
在这种情况下,yaml文件的第一行将设置环境的名称。用下面的yaml文件创建的环境名将被称为datasci-env。

使活动
创建环境后,您可以使用以下方式激活它:
conda activate datasci-env
您可以通过查看终端的左侧来区分环境是否已激活。您应该会看到它从base变为datasci-env,如下所示:

确认 Python 版本
我们可以使用以下命令在我们新创建的 Conda 环境中检查 python 的版本:
python --versionOR python3 --version
注意: 默认情况下,macOS Catalina 将 python 作为 Python 2,因此为了在 Python 3 中运行任何东西,您必须使用 *python3*
在您的终端中运行这些命令时,您将看到以下内容:

这意味着我们刚刚创建的 conda 环境正在运行版本Python 3.7.3。如果这是您想要的 python 版本,您可以跳过下一节,继续安装依赖项。
使用不同版本 Python 的 Conda 环境(可选)
如果您的环境需要不同版本的 python,您需要在安装时指定版本。首先,让我们停用刚刚创建的环境:
conda deactivate
例如,如果我们想要创建一个 Python 3.5 环境,我们可以运行以下命令:
conda create -n datasci-env-py35 python=3.5
下面我确认 conda 通过激活环境和运行python3 --version安装了正确版本的 python。

您可以使用以下命令列出所有可用的环境:
conda env list
安装和卸载依赖关系
首先,确保激活了正确的环境(它应该出现在终端左侧的括号中)。如果您正在处理多个项目,在错误的位置安装依赖项会导致问题,因此确保您在正确的环境中是很重要的。
安装
现在,您应该能够使用conda install安装您的依赖项了。让我们用一些流行的数据科学库来尝试一下:
conda install pandas matplotlib numpy scikit-learn
您将收到另一个提示,要求您继续,在键入y之后,您应该会看到所有的包都成功安装了。

如果您需要安装软件包的特定版本,您可以在安装时命名该版本:
conda install pandas=0.25.1
上面的这个命令也可以在你安装了库和包之后降级它们。
从计算机上卸载
如果要卸载软件包,可以使用以下方法:
conda uninstall PACKAGE_NAME
您可以使用conda list检查当前环境中的所有包和版本,它将显示以下内容:

注意: ——如果 *conda install* 命令对你要安装的库不起作用,你可以试着谷歌一下如何安装那个特定的库。
-安装依赖项时,请小心升级您的 python 版本。上面可以看到安装把我的 python 版本升级到了 3.8.2。
导出 Conda 环境
现在我们已经有了一个安装了一些依赖项的环境,我们可以为了版本控制和可再现性而导出它们。理想情况下,您会将这些文件导出到您的项目目录中,并将它们推送到 github,以获得版本历史的正确记录。您可以根据需要导出一个txt或yaml文件。
首先确保您激活了 conda 环境,并且您位于终端中正确的项目目录中。要将依赖项导出到一个txt文件,请运行以下命令:
**# with conda**
conda list --export > requirements.txt**# with pip**
pip freeze > requirements.txt
要将依赖项导出到一个yaml文件,请运行以下命令:
conda env export > environment.yaml**# OR if you run into issues, try --no-builds** conda env export --no-builds > environment.yaml
运行这些命令之后,您应该会看到一个新文件出现在您的项目目录中,其中包含所有的依赖项。您应该将该文件推送到 github,以便您的团队成员或您自己以后可以访问并重新创建准确的项目环境。
如果您正在与一个团队一起工作,如果其他人通过安装新的依赖项进行了更改,您可能希望在某个时候更新您这一端的环境。您可以使用以下命令从yaml文件更新现有的 conda 环境:
conda env update --file environment.yaml
使用 Conda 和 JupyterLab
如果您想在 JupyterLab 中使用 conda 环境,您需要为该环境创建一个特定的内核。
首先在您的环境中安装jupyterlab和ipykernel,然后创建一个新的内核:
conda install -c conda-forge jupyterlab ipykernelipython kernel install --user --name=datasci-env
现在,您应该能够使用以下命令从终端启动 JupyterLab 了:
jupyter lab
一旦 JupyterLab 启动,你可以打开一个新的或现有的笔记本,点击右上角的内核,并从下拉列表中选择你的新内核。如果看不到内核,尝试重启 Jupyter。

如果您想要列出“终端”中可用的内核:
jupyter kernelspec list
停用环境
当您使用完 conda 环境后,您可以在终端中使用以下命令停用它:
conda deactivate
您的终端现在应该将(base)显示为左侧的环境:

删除环境
如果您完成了一个项目,不再需要一个环境,您可以使用以下命令删除它:
conda env remove -n datasci-env
命令摘要
**# create new environment**
conda create -n ENV_NAME**# create new environment with different version of python**
conda create -n ENV_NAME python=VERSION**# create environment from existing environment.yaml** conda env create -f environment.yaml**# update existing environment from environment.yaml** conda env update --file environment.yaml**# activate environment** conda activate ENV_NAME**# deactivate environment** conda deactivate**# delete/remove environment** conda env remove -n ENV_NAME**# list all environments** conda env list**# export requirements.txt with conda**
conda list --export > requirements.txt**# export requirements.txt with pip**
pip freeze > requirements.txt**# export environment.yaml** conda env export > environment.yaml**# export environment.yaml with no builds** conda env export --no-builds > environment.yaml**# install dependencies**
conda install PACKAGE_NAME
OR
conda install -c conda-forge PACKAGE_NAME**# install dependencies with a specific version** conda install PACKAGE_NAME=VERSION**# uninstall dependencies** conda uninstall PACKAGE_NAME**# list all dependencies** conda list**# create ipython kernel (for jupyter and jupyterlab)** conda install -c conda-forge jupyterlab ipykernel
ipython kernel install --user --name=KERNEL_NAME**# list all ipython kernels**
jupyter kernelspec list**# uninstall/remove existing ipython kernel**
jupyter kernelspec uninstall KERNEL_NAME
可再生环境的工作流程示例
- 为项目创建新的 Github repo
- 使用
git clone在本地克隆回购 cd进入项目目录- 创建新的 Conda 环境
- 激活环境
- 安装依赖项
- 在 Jupyter 或其他 IDE 中处理项目
- (可选)如果在 Jupyter 中工作,从 env 创建内核
- 将 conda env 导出到
yaml或txt文件 - 保存代码
- 创建
.gitignore来避免不想添加到 git 的文件 - 使用
git add .将文件添加到 git - 将环境文件和代码推送到 Github
要再现环境:
- 在不同的计算机上克隆 repo
- 从
yaml或txt文件创建环境(不必使用 Conda) - 运行代码
注意: 如果您计划部署您的项目,您可能想要维护一个单独的部署环境,该环境只包含已部署方面所需的依赖项。
现在,您应该能够在 conda 环境中创建、激活和安装依赖项,以创建可再现的数据科学和机器学习环境。
请随时在 twitter @elizabethets 或 LinkedIn 上与我联系!
来源
** [## conda-conda 4 . 8 . 3 . post 51+2 CD D7 ab 0 文档入门
这个 20 分钟的 conda 入门指南让你尝试 conda 的主要功能。你应该明白…
docs.conda.io](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html#managing-python) [## 安装- Anaconda 文档
在安装 Anaconda 个人版之前,请阅读下面列出的系统要求。如果你不想要…
docs.anaconda.com](https://docs.anaconda.com/anaconda/install/)**
像专家一样管理 Python 中的文件和数据库连接
如何使用自定义上下文管理器管理 Python 中的外部资源

在数据工程和数据科学中,我们经常需要从数据库或平面文件中检索数据。但是,使用来自外部资源的数据而不关闭与底层数据库或文件的连接可能会导致不必要的后果。在本文中,我们将讨论如何构建定制的上下文管理器,帮助我们以安全有效的方式使用这些资源。
上下文管理器
多亏了上下文管理器,我们可以从外部资源读取数据,并确保与底层数据库或文件的连接已关闭,即使我们在代码中遇到一些未处理的异常。
上下文管理器的典型用途包括保存和恢复各种全局状态、锁定和解锁资源、关闭打开的文件等[1]
关闭资源至关重要,因为同时打开的文件或数据库连接的数量是有限制的。可以同时打开的文件数量取决于相应操作系统允许的文件描述符数量。在 Linux 和 macOS 上,我们可以通过使用ulimit -n [2]来检查这个数字:
➜ ~ ulimit -n
256
同样,并发数据库连接的数量也有限制。例如,默认情况下,开放 PostgreSQL 连接的最大数量限制为 100 [3]。
上下文管理器的典型用法
下面的代码显示了上下文管理器的典型用法:
-
将数据写入文件
-
从同一文件中读取数据:
上下文管理器背后的原因
您可能会问:为什么不直接向文件写入和读取数据,而不添加这个with?我们可以编写如下相同的代码:
但是想象一下,如果我们在写入这个文件时遇到错误,会发生什么?连接永远不会关闭。我们可以通过将代码包含在try-finally块中来改进这一点,如下所示:
但是这可能写起来很乏味,我们的代码变得冗长。因此,上下文管理器是很棒的——我们可以在仅仅两行代码中完成更多的工作,并且我们的代码变得更具可读性。
总结起来,上下文管理器的理由是:
- 确保资源被释放,即使我们遇到一些未处理的异常
- 可读性
- 便利——我们让自己变得更容易,因为我们不再忘记关闭与外部资源的连接。
自定义上下文管理器
有两种定义上下文管理器的方法:使用定制类,或者使用生成器[4]。让我们看看生成器选项,创建一个上下文管理器,让我们管理一个 MySQL 数据库连接。
用上下文管理器处理 MySQL 数据库连接
该逻辑与使用try-finally块的逻辑相似,除了我们产生连接对象,而不是返回它——这是由于生成器在需要时会延迟返回对象的性质(即,当我们迭代它们时)。在我们的例子中,上下文管理器将产生一个值——连接对象。
注意,我们所要做的就是添加一个装饰器@contextlib.contextmanager,并在try块中使用yield。
要使用这个上下文管理器将 MySQL 中的数据检索到 pandas 数据框中,我们只需通过上下文管理器导入并应用这个函数:
注意我们的 bus_logic.py 脚本变得多么简单!
try块可以包含任何定制的设置代码,比如从 secrets manager、环境变量或配置文件中检索配置细节和凭证。同样,在finally-块中,您可以定义任何拆卸逻辑,比如删除临时文件、关闭连接或改回工作目录。这是我们接下来要做的。
使用上下文管理器临时更改工作目录
假设您在src目录中,但是当您从 S3 下载文件时,您想将它们存储在data目录中。在这种情况下,我们可能希望暂时将工作目录更改为data文件夹,并在功能完成后将其更改回之前的目录。以下上下文管理器可以实现这一点:
通过使用上面的上下文管理器,我们可以确保我们在下载文件时位于正确的目录( data )。然后,一旦下载完成,我们就变回原来的工作目录。
结论
在本文中,我们研究了 Python 中的上下文管理器,它让我们能够以更优雅的方式处理外部资源。当未处理的异常导致我们的脚本在拆卸代码有机会执行之前结束时,它们还可以防止可能发生的错误。这样,上下文管理器可以防止离开锁定的资源、打开的文件或数据库连接。最后,通过抽象出安装和拆卸代码,它们使我们的代码更具可读性。
感谢您的阅读!如果这篇文章有帮助,请随时关注我的下一篇文章。
资源:
[1]https://docs . python . org/3/reference/data model . html # context-managers
[2]https://stack overflow . com/questions/2425084/我能一次打开多少个文件
[3]https://www . PostgreSQL . org/docs/current/runtime-config-connection . html
https://book.pythontips.com/en/latest/context_managers.html
使用 Apache Airflow 管理高含量筛选 CellProfiler 管道

如果你正在运行一个高内容筛选管道,你可能有很多移动的部分。作为一个非详尽的列表,您需要:
- 触发 CellProfiler 分析,要么来自 LIMS 系统,通过观察文件系统,要么来自其他进程。
- 跟踪 CellProfiler 分析的相关性-首先运行光照校正,然后进行分析。
- 如果您有一个大型数据集,并且希望在本世纪的某个时候对其进行分析,您需要拆分分析、运行,然后收集结果。
- 一旦你有了结果,你需要决定一个组织方法。你需要把你的数据放入数据库,并建立深度分析管道。
当您拥有一个为科学工作流而构建的系统或框架时,这些任务会更容易完成。
如果你更喜欢看,我有一个视频,我通过这个教程中的所有步骤。
进入阿帕奇气流
阿帕奇气流是:
Airflow 是一个由社区创建的平台,用于以编程方式创作、安排和监控工作流。
关于 Apache Airflow 有很多很好的介绍资源,但是我在这里将非常简要地介绍一下。
Apache Airflow 为您提供了一个框架,将您的分析组织到 Dag 或有向无环图中。如果你不熟悉这个术语,它实际上只是一种说法,第三步依赖于第二步,第二步依赖于第一步,或Step1 -> Step2 -> Step3。
Apache Airflow 使用Dag,这些 Dag 是你用来进行分析的桶。您的 DAG 由操作员和传感器组成。操作符是对你正在完成的任务的一种抽象。这些通常是 Bash、Python、SSH,但也可以是更酷的东西,如 Docker、Kubernetes、AWS Batch、AWS ECS、数据库操作、文件推送器等等。还有传感器,它们是等待各种操作的漂亮而闪亮的方式,无论是等待文件出现、数据库中的记录出现,还是等待另一个任务完成。
开箱即用,您可以获得许多好处,包括一个漂亮的 web 界面,带有任务的可视化浏览器、调度器、可配置的并行性、日志记录、观察器和任意数量的执行器。因为所有的配置都是用代码编写的,所以非常灵活。它可以与现有系统集成,也可以独立运行。
有许多科学的工作流管理器,在我完成这篇文章的时候,将会有更多的出现。阿帕奇气流是我最喜欢的,但你应该货比三家,看看你点击什么!
计算后端
我之前简单地提到了这一点,但是最初吸引我到 Apache Airflow 的好处之一是它对您的计算环境是完全不可知的。您可以拥有一台笔记本电脑、一台服务器、一个 HPC 集群,或者在 AWS 或 GCP 上执行。气流本身并不在意。您需要做的就是规划出您的逻辑,确保数据可用,并使用任何合适的操作符。
CellProfiler 分析工作流程示例
在这篇文章中,我将讨论 BBBC021 数据集以及我将如何组织和批处理分析。
我决定进行一个简单的设置,即将 Apache Airflow 与 docker-compose 结合使用,并使用 docker 操作符来执行 CellProfiler 分析。规划好逻辑和工作流后,您可以针对任何计算基础架构使用任何操作员,无论是 AWS ECS 还是 HPC。我最近最喜欢的是 Kubernetes,因为它不依赖于任何平台,可以在 AWS、GCP 或室内使用。您可以使用 Kubernetes 部署您的数据可视化应用程序,如 RShiny 、 Dash 或 Redash ,如果您使用网络存储或 S3,您的所有应用程序都可以访问相同的数据!
项目设置
让我们设置我们的项目目录结构!
mkdir CellProfiler-Apache-Airflow
cd CellProfiler-Apache-Airflow
mkdir -p data/dags
mkdir -p data/BBBC021/Week1
cd data/BBBC021/Week1
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22123.zip
find $(pwd) -name "*zip" | xargs -I {} unzip {}
# Clean up the zips, we don't need them anymore
find $(pwd) -name "*zip" | xargs -I {} rm -rf {}
cd ../
# Run $(pwd) to check where you are. You should be in /project/BBBC021
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_image.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_compound.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_moa.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/analysis.cppipe
wget https://data.broadinstitute.org/bbbc/BBBC021/illum.cppipe
# Let's create a data file ONLY for the week1 images, the first dataset
head -n 1 BBBC021_v1_image.csv > images_week1.csv
cat BBBC021_v1_image.csv | grep Week1_22123 >> images_week1.csv
这主要是来自 Bitnami 的阿帕奇气流配置。Bitnami 很棒,我一直在用他们的配置和图片。我对此做了一些修改,以绑定我们的分析 Dag,还做了一个快速更改,以便我们可以使用 docker 操作符。
Dockerfile 文件
We're going to use a custom Cellprofiler image to run our pipelines. Create a Dockerfile有了这个:
FROM cellprofiler/cellprofiler:3.1.9
RUN apt-get update -y; apt-get install -y unzip imagemagick
ENV TINI_VERSION v0.16.1
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini
RUN chmod +x /usr/bin/tini
ENTRYPOINT [ "/usr/bin/tini", "--" ]
CMD [ "/bin/bash" ]
现在我们将构建新的 CellProfiler 图像!
docker build -t cellprofiler .
获取 Docker 撰写配置
抓取这个文件并以docker-compose.yml的名称保存在您的项目根目录中。
version: '2'
services:
postgresql:
image: 'bitnami/postgresql:10'
- 'postgresql_data:/bitnami/postgresql'
environment:
- POSTGRESQL_DATABASE=bitnami_airflow
- POSTGRESQL_USERNAME=bn_airflow
- POSTGRESQL_PASSWORD=bitnami1
- ALLOW_EMPTY_PASSWORD=yes
redis:
image: bitnami/redis:5.0
volumes:
- 'redis_data:/bitnami'
environment:
- ALLOW_EMPTY_PASSWORD=yes
airflow-scheduler:
image: bitnami/airflow-scheduler:1
environment:
- AIRFLOW_LOAD_EXAMPLES=no
- AIRFLOW_DATABASE_NAME=bitnami_airflow
- AIRFLOW_DATABASE_USERNAME=bn_airflow
- AIRFLOW_DATABASE_PASSWORD=bitnami1
- AIRFLOW_EXECUTOR=CeleryExecutor
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
- ./dags:/opt/bitnami/airflow/dags
- airflow_scheduler_data:/bitnami
airflow-worker:
image: bitnami/airflow-worker:1
environment:
- AIRFLOW_LOAD_EXAMPLES=no
- AIRFLOW_DATABASE_NAME=bitnami_airflow
- AIRFLOW_DATABASE_USERNAME=bn_airflow
- AIRFLOW_DATABASE_PASSWORD=bitnami1
- AIRFLOW_EXECUTOR=CeleryExecutor
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
- ./dags:/opt/bitnami/airflow/dags
- airflow_worker_data:/bitnami
airflow:
image: bitnami/airflow:1
environment:
- AIRFLOW_LOAD_EXAMPLES=no
- AIRFLOW_DATABASE_NAME=bitnami_airflow
- AIRFLOW_DATABASE_USERNAME=bn_airflow
- AIRFLOW_DATABASE_PASSWORD=bitnami1
- AIRFLOW_EXECUTOR=CeleryExecutor
ports:
- '8080:8080'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
- ./dags:/opt/bitnami/airflow/dags
- airflow_data:/bitnami
volumes:
airflow_scheduler_data:
driver: local
airflow_worker_data:
driver: local
airflow_data:
driver: local
postgresql_data:
driver: local
redis_data:
driver: local
如果您不习惯容器,这可能会有点棘手,但有一点要注意,主机上的路径不一定与 docker 容器中的路径相同,例如,我们的数据目录可能在主机系统上的任何地方,但在我们的容器上被绑定为/data。
把docker-compose.yml文件放到你的项目目录中,用docker-compose up调出。初始化可能需要一些时间。这是我去泡茶的时候。;-)
一旦启动,您将能够使用默认配置在localhost:8080访问您的 Airflow 实例。
AIRFLOW_USERNAME: Airflow application username. Default: user AIRFLOW_PASSWORD: Airflow application password. Default: bitnami
这里还不会有什么有趣的东西,因为我们还没有分析到位。
抓住细胞分析仪的分析工具
首先拿起照明匕首。将它放在您的dags文件夹中。它可以被命名为任何东西,气流引用的是dag_id,但我会引用它为cellprofiler-illum-dag.py。
# dags/cellprofiler-illum-dag.py
from airflow import DAG
from datetime import datetime, timedelta
import string
import random
from airflow.utils import timezone
from airflow.operators.dagrun_operator import TriggerDagRunOperator
from airflow.operators.bash_operator import BashOperator
from airflow.operators.python_operator import PythonOperator
# Depending on which version of airflow you are on you will use either operators.docker_operator or providers.docker
from airflow.operators.docker_operator import DockerOperator
# from airflow.providers.docker.operators.docker import DockerOperator
from airflow.api.common.experimental.trigger_dag import trigger_dag
from airflow.sensors.external_task_sensor import ExternalTaskSensor
from airflow.api.common.experimental import check_and_get_dag, check_and_get_dagrun
import time
import os
from pprint import pprint
from airflow.utils.state import State
this_env = os.environ.copy()
this_dir = os.path.dirname(os.path.realpath(__file__))
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': datetime(2019, 1, 1),
'email': ['airflow@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
}
dag = DAG('cellprofiler_illumination', default_args=default_args, schedule_interval=None)
EXAMPLE_TRIGGER = """
{
"illum_pipeline" : "/data/BBBC021/illum.cppipe",
"analysis_pipeline" : "/data/BBBC021/analysis.cppipe",
"pipeline" : "/data/BBBC021/illum.cppipe",
"output": "/data/BBBC021/Week1/Week1_22123",
"input": "/data/BBBC021/Week1/Week1_22123",
"data_file": "/data/BBBC021/images_week1.csv"
}
"""
# Volumes are from the HOST MACHINE
illum = DockerOperator(
dag=dag,
task_id='illum',
retries=1,
volumes=[
# UPDATE THIS to your path!
'/path-to-project-on-HOST/data:/data'
],
working_dir='/data/BBBC021',
tty=True,
image='cellprofiler',
command=[
"bash", "-c",
"""cellprofiler --run --run-headless \
-p {{ dag_run.conf['illum_pipeline'] }} \
-o {{ dag_run.conf['output'] }} \
-i {{ dag_run.conf['input'] }} \
-data-file {{ dag_run.conf['data_file'] }} \
-c -r"""
]
)
def get_number_of_tasks(data_file):
"""
Parse the file to get the number of lines
The number of lines, minus 1 for the header
is the number of groups
:param data_file:
:return:
"""
file = open(data_file, "r")
number_of_lines = 0
for line in file:
number_of_lines += 1
file.close()
return number_of_lines - 1
def watch_task(triggers):
"""
This is only here for demonstration purposes
to show how you could dynamically watch the cellprofiler analysis DAG
:param triggers:
:return:
"""
print('-------------------------------------------')
print('Checking up on our dag...')
check_dag = check_and_get_dag(dag_id='cellprofiler_analysis')
dag_run = check_and_get_dagrun(check_dag, triggers[0].execution_date)
state = dag_run.get_state()
finished = State.finished()
unfinished = State.unfinished()
while state in unfinished:
time.sleep(10)
state = dag_run.get_state()
print('-------------------------------------------')
print('Dag run finished or dead')
pprint(dag_run.get_state())
def trigger_analysis(ds, **kwargs):
"""
Trigger the cellprofiler analysis DAG
We want one DAG run per row in the datafile, or -f / -l combo
:param ds:
:param kwargs:
:return:
"""
print('-------------------------------------------')
print("Here's the conf!")
pprint(kwargs['dag_run'].conf)
output = kwargs['dag_run'].conf['output']
data_file = kwargs['dag_run'].conf['data_file']
no_tasks = get_number_of_tasks(str(data_file))
triggers = []
print('-------------------------------------------')
print('Triggering our dag...')
for index, value in enumerate(range(1, no_tasks + 1)):
trigger = trigger_dag(
dag_id="cellprofiler_analysis",
replace_microseconds=False,
run_id="trig__{}__f_{}__l_{}".format(
timezone.utcnow().isoformat(),
value,
value
),
conf={
"pipeline": kwargs['dag_run'].conf['analysis_pipeline'],
"output": "{}/f-{}__l-{}".format(output, value, value),
"input": kwargs['dag_run'].conf['input'],
"data_file": data_file,
"first": value,
"last": value,
}
)
triggers.append(trigger)
trigger_analysis_task = PythonOperator(
dag=dag,
task_id='trigger_analysis',
provide_context=True,
python_callable=trigger_analysis
)
trigger_analysis_task.set_upstream(illum)
而现在我们的cellprofiler-analysis-dag.py。
# dags/cellprofiler-analysis-dag.py
from airflow import DAG
from datetime import datetime, timedelta
from airflow.operators.python_operator import PythonOperator
from airflow.operators.docker_operator import DockerOperator
import os
from pprint import pprint
this_env = os.environ.copy()
this_dir = os.path.dirname(os.path.realpath(__file__))
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': datetime(2019, 1, 1),
'email': ['airflow@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
}
dag = DAG('cellprofiler_analysis', default_args=default_args, schedule_interval=None)
analysis = DockerOperator(
dag=dag,
task_id='analysis',
retries=1,
volumes=[
# Volumes are from the HOST MACHINE
# UPDATE THIS to your path!
'/path-on-HOST/data:/data'
],
tty=True,
image='cellprofiler',
command=[
"bash", "-c",
"""cellprofiler --run --run-headless \
-p {{ dag_run.conf['pipeline'] }} \
-o {{ dag_run.conf['output'] }} \
-i {{ dag_run.conf['input'] }} \
--data-file {{ dag_run.conf['data_file'] }} \
-c -r -f {{ dag_run.conf['first'] }} -l {{ dag_run.conf['last'] }}"""
]
)
def gather_results(ds, **kwargs):
"""
Once we have the Cellprofiler results let's do something with them!
:param ds:
:param kwargs:
:return:
"""
pass
gather_results_task = PythonOperator(
dag=dag,
task_id='gather_results_task',
provide_context=True,
python_callable=gather_results
)
gather_results_task.set_upstream(analysis)
确保您更新了DockerOperator volumes以匹配您的本地文件系统!否则你的分析是行不通的!
分析组织概述
我们这里有 2 个独立的 Dag,每个 CellProfiler 分析一个。
这些步骤是:
- 所有图像的过程照明管道
- 获取数据文件,看看我们有多少图像
- 为每个图像动态生成一个 CellProfiler 提交。
- (Placeholder)对我们的结果做点什么吧!
您会注意到,我们正在动态拆分 CellProfiler 分析。这将使我们的分析更快完成,当你购买产生大量数据的花哨的机器人显微镜时,这变得越来越重要。Airflow 负责处理引擎下的任务队列,所以我们需要做的就是找出我们如何分割分析的逻辑。如果你想知道更多关于并行性在气流中是如何处理的,这是一篇很棒的文章。
好的,最后一个只是一个占位符。我可以想象,一旦你有了结果,你会想对它们做些什么,比如把它们放入数据库,根据某些标准进行一个或多个分析,或者做一些后处理,但现在这是空白的,所以你可以想知道可能性。
将参数传递给我们的分析
当我开始使用气流时,这一点对我来说并不明显,现在你可以听到关于它的一切了!;-)
您可以使用 conf 对象或参数向气流传递参数。根据运算符类型的不同,这可能会略有不同。如果你使用的是 Python 操作符,你可以把它作为一个字典kwargs['dag_run'].conf来访问,如果你使用的是Bash,或者在这个例子中是Docker,你可以把它作为一个模板变量 {{ dag_run.conf['variable'] }}来访问。
我将带您了解如何使用 Airflow web 界面来触发 DAG 并传入变量,但是您也可以使用 REST API、通过 Airflow CLI 或使用 Python 代码以编程方式来触发 DAG。无论如何触发 DAG,都要将配置变量作为 JSON 字符串传入。
关于 Docker 卷的一个注记
这有点奇怪,因为我们使用 docker-compose 来运行 Airflow,然后使用 docker 操作符。请记住,当您使用 Docker 操作符时,您使用主机上的路径来映射卷,而不是在 docker-compose 容器中。你的主机就是你运行docker-compose up的机器。
例如:
analysis = DockerOperator(
...
volumes=[
# Volumes are from the HOST MACHINE
'/path-on-HOST/data:/data'
# NOT
# '/data:/data'
# Even though in our docker-compose instance the volume is bound as /data
],
...
)
分析一下!
我们准备好了!现在您已经有了 Dag(您需要有 Dag)所有设置,我们可以开始分析数据了!
使用用户user和密码bitnami在localhost:8080登录。您应该会看到如下所示的屏幕:

默认情况下,您的 dags 将关闭。确保在进行下一步之前打开它们!
触发你的分析
前往你在localhost:8080的主页并触发cellprofiler-illum DAG。

系统会提示您添加一些 JSON 配置变量。
{ "illum_pipeline" : "/data/BBBC021/illum.cppipe", "analysis_pipeline" : "/data/BBBC021/analysis.cppipe", "pipeline" : "/data/BBBC021/illum.cppipe", "output": "/data/BBBC021/Week1/Week1_22123", "input": "/data/BBBC021/Week1/Week1_22123", "data_file": "/data/BBBC021/images_week1.csv" }

您将返回到主页面,并且应该看到您的 CellProfiler 光照分析正在运行!

这里有一个简短的(~1 分钟)视频,展示了如何浏览气流界面来研究您的分析。
包裹
就是这样!让气流运行,你将有你的照明和分析管道运行,所有分裂很好,你不是保姆跟踪作业队列,日志,和成功/失败率。您还可以使用 REST API、CLI 或代码将 Airflow 与任何其他系统集成,例如 LIMS、报告数据库或辅助分析工作流。
如果你想了解更多,请查看我的网站,或者直接联系 jillian@dabbleofdevops.com。
感谢
特别感谢 Broad BioImage Repository 提供的数据集,以及 Anne Carpenter 博士、Beth Cimini 和 Becki Ledford 提供的极有价值的反馈和编辑!
引文
https://data.broadinstitute.org/bbbc/BBBC021/
“我们使用图像集 bbbc 021v 1[蔡锷等人,分子癌症治疗学,2010],可从广泛的生物图像基准收集[Ljosa 等人,自然方法,2012]。”
最初发表于【https://www.dabbleofdevops.com】。
用 TODOr 管理你的整个 R 代码库
永远不要忘记修理你的FIXME或再次做你的TODO!

TODOr 是一个非常有用的 R 包,RStudio 插件使得管理你所有的开发者评论变得非常容易。

照片由 TODOr 的开发者张秀坤·克尔泽米斯基拍摄
托多能为你做什么?
这种情况在您身上发生的频率有多高:
“我需要记得修复这个 bug…”
mean[1] # FIXME: This doesn't work#> Error in mean[1] : object of type 'closure' is not subsettable
然后你继续前进,继续你的工作,打算以后再回到这个问题上来。代码库可能充斥着这种类型的注释。R 包开发人员创建的这些提醒,每一个修正的意图,在庞大的代码库中经常会被遗忘或放错地方。
TODOr 减轻了技术债务的负担,解决了所有这些提醒你代码库健康的问题。
TODOr 将在整个文件、项目或包中找到所有这些提醒。甚至多种类型的文件都被支持,你会得到一个详细的提醒列表,包括什么类型的提醒,提醒的细节,文件所在的位置,文件所在的行,点击列表中的一项,你就可以找到你需要修复的代码行!
你需要做些什么来见证这种力量?只是这个:
todor::todor()
有哪些默认?
默认情况下,TODOr 将返回所有带有正确标记的注释(例如“TODO”、“FIXME”等)。)在整个 R 项目中(当你有一个 .Rproj 文件在目录中)而不仅仅是当前文件。
“所有的评论?但我不在乎所有的评论,只在乎我该做的事……”
返回的并不是每个评论,TODOr 寻找以标记词开始的评论。默认值为:

作者图片
- 固定时间
- 待办事宜
- 改变了
- 想法
- 黑掉
- 注
- 回顾
- BUG
- 问题
- COMBAK
- 温度
超出默认范围
搜索范围
TODOr 不仅可以查看一个项目,还可以让它搜索单个文件:
todor::todor_file("my_file.Rmd")
或者甚至整个 R 包:
todor::todor_package()
标记
默认情况下,TODOr 会寻找所有前面提到的注释标记。您将得到一个返回给您的所有代码的列表,但是如果您有一个非常大的代码库呢?喜欢ggplot2大?
你可能只想查看一些特定类型的注释,我们可以通过向函数传递一个向量来做到这一点:
todor::todor(c("TODO", "FIXME"))
这将只显示为 TODO 和 FIXME 的注释。
这样,我们可以过滤我们的搜索,从特定的文件中筛选出我们想要返回的评论类型。
如果你不喜欢默认标记怎么办?
如果您希望您的团队拥有这一功能,但又希望用团队成员的名字来标记评论,该怎么办?
我们实际上可以定义一个自定义的 TODOr 搜索模式列表,这样我们就可以为函数定义新的关键字,以便在整个代码库中查找。为此,我们需要使用options函数:
options(todor_patterns = c("FIXME", "TODO", "BRYAN"))
现在,每当我把我的名字放在一个评论旁边时,它就会被 TODOr 作为一个有效的标记评论返回*。
*请务必注意,这些搜索模式区分大小写:
# BRYAN please fix this bug <---- would be picked up
# bryan please fix this bug <---- This would be ignored

作者图片
托多尔能看到的不仅仅是.R的文件
在 TODOr 中,我们可以控制多种选项
还有其他几种文件类型,TODOr 可以在其中找到标记并以列表格式返回。为了搜索其他文件类型,我们可以用options()功能配置这些选项。

Rmarkdown 评论-作者图片
todor_rmd —当设置为真时,它也搜索 Rmd( Rmarkdown )文件(默认为真)。
返回的 Rmarkdown 标记注释将是使用 HTML 语法的代码块和 markdown 空格注释:

sweave 文档—按作者分类的图像
todor_rnw —设置为 TRUE 时,它还会搜索 Rnw( Sweave )文件(默认为 FALSE )。

Sweave 评论—作者图片
Sweave 是 LaTeX 与可执行 R 代码块的组合,返回的注释是代码块和 LaTeX 注释:

RHTML 文件—作者图片
todor_rhtml —当设置为真时,它也搜索 RHTML 文件(默认为假)。

就像 RMarkdown 文档一样,只要使用了正确的标记,HTML 样式和 R 样式的注释都会被选中。

Packrat 选项设置为 FALSE 按作者分类的图像

无尽的开发者评论——作者图片
todor_exlude_packrat—设置为 FALSE 时,“packrat”目录下的所有文件都被 排除 ( 默认为 TRUE )。
如果您曾经使用 packrat 来获取您的包或项目依赖关系的快照,那么您可能不希望为所有那些依赖包获取所有开发人员的注释。
我运行过一次,你肯定想把它改成FALSE,因为默认是TRUE,你可能会得到这样一个列表。
如果你真的想忽略 R 文件呢?该选项仅忽略 R 脚本文件,不忽略 RMarkdown。
todor_exclude_r —为真时,忽略 R 文件(默认为假)
总体而言,您可以将以下选项()用于 TODOr:
TODOr options() —按作者编码
概括起来
我希望这篇文章对你有所帮助,并决定在你的工作流程中使用 TODOr。我在公共部门政府的工作中使用了这个软件包,发现它对我自己的评论非常有帮助,以后可以很容易地跟进。
如果你更喜欢这个包评论的视频格式,并想获得我在 R 包评论中使用的所有文件,你可以在这里得到它们:
TODOr R 软件包评论—作者视频
对于我所有的 R 包评审,如果您需要我在评审中使用的任何代码/文档,我还将所有代码和样本文档保存在一个 repo 中:
[## tallguyjenks/RPackageReviews
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/tallguyjenks/RPackageReviews/tree/master/examples/todor)
如果你喜欢 R 包评论,你可以看看我以前对拼凑包的评论:
Patchwork 是 R 编程语言的一个包,它通过一个简单的…
medium.com](https://medium.com/analytics-vidhya/the-patchwork-package-in-r-9468e4a7cd29)
来源
[1] D. Krzemiński, TODOr — RStudio 插件,用于查找 TODO、FIXME、CHANGED 等。代码中的注释。 (2017),GitHub.com
使用 Python 管理您的资金
一步一步引导你控制自己的财务

来自 Pexels 的 Karolina Grabowska 摄影
曾经有一段时间,我们习惯于在笔记本、电子表格或应用程序上写下我们所做的所有交易,以了解我们如何花钱。嗯,这种方法可能相当耗时,需要努力,而且需要一致性。
这篇文章旨在为你提供一个巩固的理财习惯,有效地控制你的支出。如果你是一个初学 Python 的程序员,我希望这篇文章也能启发你一个实际的用例,你可以根据自己的需要进行个性化。
如果你喜欢视频格式,一定要在我的 YouTube 频道上查看这篇文章的内容
问题陈述
我们中的一些人使用移动应用程序来检查我们如何花钱。就我个人而言,为了跟踪我的支出,我使用 Yolt T7,这是一个应用程序,由于开放银行,它允许你把你所有的银行账户放在一个地方。
你可能已经意识到的是,Yolt 和数字银行的应用程序,如 Revolut 或 Monzo 在如何定制你的财务报告方面仍然有局限性。例如,Yolt 目前不允许你编辑你的支出类别,所以你不能将午餐、外出就餐和外卖归入一个单独的食物类别。此外,该应用程序可能会将你的健身房会员信息放在食品杂货下,或将你的机票购买信息放在个人护理下。这肯定不会帮助你跟上你的支出。
那么,如何才能让我们的资金管理更上一层楼呢?
解决办法
解决这个问题的一个方法是使用 Python 来处理我们的交易数据,并创建个性化的财务月报,以最能引起你共鸣的方式对费用进行分类。我们需要做的是收集每月的数据,并选择我们的费用类别(仅在第一次运行代码时)。
你可以在这个链接找到整个脚本。您可以访问它,以便更好地跟进或根据需要编辑代码。
在开始之前,重要的是要注意预算的好处不在于创建整洁的图表或仪表盘。这些方法可以让你发现你最糟糕的消费领域,并帮助你更好地控制它们。 真实值不在图表中。真正的价值在于图表如何改变你的行为。
让我们通过以下 5 个步骤来看看如何更好地管理我们的钱。
步骤 1:导入 Python 库
首先,我们需要导入将要使用的 Python 库。库是允许您执行不同操作的函数和方法的集合。
第二步:获取数据
然后我们需要得到所有的交易数据。这可以通过将您的交易数据从您的网上银行下载到一个 csv 文件中来完成(大多数银行允许您从他们的应用程序中完成这一操作)。
如果你有多个银行账户,或者你无法从网上银行下载交易数据,我建议你使用 Yolt 。使用此应用程序,您可以在一个地方获得您的所有帐户,并轻松下载包含您所有交易的 csv 文件(在应用程序中,只需进入更多选项卡,隐私设置,然后点击下载您的信息)。
因为我想让你们所有人都可以访问这篇文章,不管你有什么银行账户和应用程序,我们要使用的 csv 文件只有 6 列(id、日期、金额、描述、商家和类别),看起来像下面的截图。在本练习中,我只使用了两个不同的银行账户,但是您可以根据需要添加任意数量的账户。让我们将交易数据转换成熊猫数据框架。

本练习中使用的数据帧的子集
在数据框架的这个子集中,我们已经可以看到有交易被错误地分类(例如,来自朋友的付款被标记为收入……)。我们将在接下来的步骤中解决这个问题。
步骤 3:操作数据并定制您的事务类别
按照此步骤,您可以编辑您的数据并个性化您想要的交易管理方式。
步骤 3.1:删除包含特定字符串的行
使用这一简单的行,您可以删除某一列中包含特定字符串的所有行(然后您可以重复该命令任意次来删除其他行)。在下面的例子中,我删除了将钱从一个银行账户转移到另一个银行账户的所有交易,我的应用程序将其标记为 Internal 。
步骤 3.2:定义所有交易的类别
现在是时候定义所有事务应该归入的类别了。在我的案例中,我选择使用 14 个类别:
- 收入
- 娱乐
- 食物
- 租金和账单
- 旅行
- 运输
- 运动
- 转移
- 物欲
- 现金提取
- 礼物
- 食品
- 个人护理
- 其他的
步骤 3.3:将交易分配到正确的类别
在您定义了您想要用来管理您的资金的所有交易类别后,我们可以开始识别在数据框架中被错误标记的交易,并将它们分配到正确的类别。这是以最符合你需求的方式形成你的最终报告的关键。
一种方法是再次定位包含特定字符串的行,并将它们分配到某个类别(例如,包含优步、 Zipcar 或 Bird 的所有行都应该归入 Transport category )。
此外,使用下面的命令,您还可以将从开始的事务从一个特定的字符串重新分配到一个特定的类别。例如,我将把描述以“到“开头的所有交易移动到转移类别。
步骤 3.4:更改类别的名称
要用我们在上一步中定义的类别来改变现有的类别,我们可以使用下面的代码行。如上所述,一个例子是将所有与吃/喝相关的交易分配到一个食品类别。
第四步:设计你的月度报告
完成第 3 步后,我们现在应该有一个清晰的数据框架,其中包含按对我们更有意义的类别聚合的事务。我们现在准备设计我们的月度报告,它将由三张不同的图表组成。
步骤 4.1:一段时间内的净收入图表
我们要制作的第一张图表将显示我们的净收入(收入减去支出)如何随时间变化。
让我们添加一个列来获取交易的年份和月份(因为我们想要创建一个月报表)。然后,为了创建第一个图表,我们只需要按照我们刚刚创建的 year_month 列对数据帧进行分组,并添加一个包含金额累计总和的列。
通过使用 Plotly Go 库,我们可以创建一个线形图,Y 轴表示净收入,X 轴表示日期。

步骤 4.2:每月总费用图表
在第二个图表中,我们想要显示我们所有费用的总和每月是如何变化的。这将有助于我们了解每月支出是否超出预算,并与前几个月进行比较。
同样,我们将按照 year_month 列对数据框架进行分组,只是在删除了所有标记为 Income 的交易之后。
然后,通过使用 Plotly Express 库,我们可以创建一个条形图,Y 轴表示费用,X 轴表示日期。

第 4.3 步:费用分解图
我们要创建的最后一个图表将让我们清楚地了解我们是如何花钱的,按照我们在步骤 3.2 中定义的类别划分我们的支出。
为了做到这一点,我们将只旋转数据框架,以获得特定月份和类别的费用总和。
根据结果,我们将再次创建一个简单的折线图,Y 轴表示费用,X 轴表示日期,如下所示。

负支出与退款有关
步骤 5:构建最终的仪表板
现在,我们已经创建了 3 个不同的图表,显示我们的净收入、每月支出及其明细,我们只需要将它们合并到一个 Dash 应用程序中,该应用程序将在您的本地笔记本电脑上运行。
在 Dash 应用程序中,您可以通过悬停鼠标来查看每个数据点的详细信息,并过滤掉您想要在图表中显示的类别。
就这样,您现在拥有了您的最终仪表板!!

结论
我希望这篇文章能像帮助我一样帮助你,既能让你控制自己的钱,又能揭露你一些最糟糕的消费习惯。
在你积累了一些条目后,开始观察这些模式,看看它们告诉了你什么,你可以对你的支出做出明智的改变。希望这将向你展示 综合理财习惯如何对你的金钱使用产生巨大影响 。
这篇文章可以作为一个起点,让您向自己的报告中添加更多图表,并使仪表板更具交互性。例如,一个显示每一类详细信息的图表可以让你更加注意你的开销。改进代码的另一个想法是自动收集交易信息,这可以通过使用网络抓取直接从您的在线银行页面获取数据来实现。
请务必联系我,告诉我你所有的建议和意见。
感谢阅读!
如果你喜欢这个内容,一定要看看我的 YouTube 频道下面的了解更多!
再见👋我是 Lore,是一名住在伦敦的意大利人,是一名数据分析师@FAANG。我从人们那里获得了巨大的价值…
www.youtube.com](https://www.youtube.com/@loresowhat)
使用 Conda 管理您的 Python 虚拟环境
轻松在 Python 2 和 Python 3 环境之间切换

丹尼斯·帕夫洛维奇在 Unsplash 的照片
虽然 Python 2 正式弃用(Python 3,你的时代就是现在!),我相信在将这些项目完全移植到 Python 3 之前,我们中的一些人仍然必须维护现有的 Python 2 项目。
在本文中,我将向您展示如何使用 Conda 来管理您的 Python 虚拟环境。Conda 是一个包和环境管理系统,它允许我们在本地机器上轻松地创建和切换环境。
使用 Conda 环境
我将使用 macOS 中的 iTerm 终端。如果您从未将 Conda 环境路径添加到您的 Windows 环境变量中,windows 用户将不得不使用Anaconda Prompt。
1。显示康达环境信息
% conda info
显示当前 Conda 安装的信息。

macOS 上的 iTerm 终端显示 conda 信息

窗口上显示 conda 信息的 Anaconda 提示符
2.列出所有现有环境
(base) username % conda env list# conda environments:
#
base * /Users/username/opt/anaconda3
py2 /Users/username/opt/anaconda3/envs/py2
我们可以使用conda env list列出所有现有的 Python 环境。*将指向当前的活动环境。base始终是您打开终端时的默认活动环境。py2是我的 Python 2 项目的另一个虚拟环境。
3.创造新环境
(base) username % conda create --name project-env python=3.7
假设您想要为您的新项目创建一个虚拟环境,我们可以使用conda create来创建一个名为project-env的新环境。我们还可以在创建环境时指定 Python 版本。
创建新环境后,您可以运行conda env list来检查您的新环境。
(base) username % conda env list# conda environments:
#
base * /Users/username/opt/anaconda3
project-env /Users/username/opt/anaconda3/envs/project-env
py2 /Users/username/opt/anaconda3/envs/py2
康达创造的环境总是位于/Users/.../anaconda3/envs/。您可以使用以下命令更改默认位置,但不鼓励这样做。Conda 不能再通过你的环境名找到你的环境,你必须指定环境的完整路径才能每次激活它。
(base) username % conda create --prefix /path/project-env
4.激活你的新环境
如您所见,您已经成功地创建了新 Python 环境。现在我们必须激活并使用它。
(base) username % conda activate project-env(project-env) username %
(project-env)表示当前的活动环境。
您可以使用conda list来显示这个环境中的所有包。
(project-env) username ~ % conda list# packages in environment at /Users/username/opt/anaconda3/envs/project-env:
#
# Name Version Build Channel
ca-certificates 2020.1.1 0
pip 20.0.2 py37_1
python 3.7.6 h359304d_2
readline 7.0 h1de35cc_5
setuptools 45.1.0 py37_0
...
...
conda list还支持修订历史。在环境中管理您的包是一个非常有用的特性。
(project-env) username ~ % conda list --revision2020-02-03 00:01:32 (rev 0) # new environment
+ca-certificates-2020.1.1
+pip-20.0.2
+python-3.7.6
+readline-7.0
+setuptools-45.1.0
...2020-02-03 00:24:55 (rev 1) # installed numpy
+blas-1.0
+intel-openmp-2019.4
+libgfortran-3.0.1
+mkl-2019.4
+mkl-service-2.3.0
+mkl_fft-1.0.15
+mkl_random-1.1.0
+numpy-1.18.1
+numpy-base-1.18.1
+six-1.14.02020-02-03 22:14:24 (rev 2) # installed configparser
+configparser-3.5.0
想象一下,仅仅因为你更新/安装了一个新的包,你就不小心搞砸了你的依赖关系。修订历史允许您将环境回滚到以前的版本。
(project-env) username ~ % conda install --revision 1## Package Plan ##environment location: /Users/username/opt/anaconda3/envs/project-envadded / updated specs:
- configparser
- numpy
- python=3.7The following packages will be REMOVED:configparser-3.5.0-py37_0
configparser已被成功移除。可以用conda list — revision再检查一遍。
(project-env) username ~ % conda list --revision2020-02-03 00:01:32 (rev 0) # new environment
+ca-certificates-2020.1.1
+pip-20.0.2
+python-3.7.6
+readline-7.0
+setuptools-45.1.0
...2020-02-03 00:24:55 (rev 1) # installed numpy
+blas-1.0
+intel-openmp-2019.4
+libgfortran-3.0.1
+mkl-2019.4
+mkl-service-2.3.0
+mkl_fft-1.0.15
+mkl_random-1.1.0
+numpy-1.18.1
+numpy-base-1.18.1
+six-1.14.02020-02-03 22:14:24 (rev 2) # installed configparser
+configparser-3.5.02020-02-03 22:17:02 (rev 3) # reverted to rev 1
-configparser-3.5.0
4.停用/更改您的活动环境
您可以随时使用conda activate或conda deactivate在您的环境之间切换。您可以使用conda activate直接激活您想要使用的环境。
(project-env) username ~ % conda activate base
(base) username ~ %
conda deactivate将停用您当前的活动环境,并更改为默认环境,即base环境。
(project-env) username ~ % conda deactivate
(base) username ~ %
5.移除您的环境
当您使用完该环境并希望删除它时。可以使用conda env remove移除环境。
(base) username ~ % conda env list# conda environments:
#
base * /Users/username/opt/anaconda3
project-env /Users/username/opt/anaconda3/envs/project-env
py2 /Users/username/opt/anaconda3/envs/py2
与 create 一样,您必须使用--name指定您希望删除的环境的名称。
(base) username ~ % conda env remove --name project-envRemove all packages in environment /Users/junetao/opt/anaconda3/envs/project-env:
project-env已从您的环境中成功删除。
(base) username ~ % conda env list
# conda environments:
#
base * /Users/junetao/opt/anaconda3
py2 /Users/junetao/opt/anaconda3/envs/py2
6.奖金!在 VS 代码中改变你的环境。
如果你和我一样是 Visual Studio 代码爱好者,你可以在没有任何命令行的情况下更改你创建的 Python 环境。
- 点击 VS 代码左下角的
Python 3.7.4。 - 选择首选环境。
- 搞定了。

在 VS 代码中更改 Python 环境
现在你已经学会了如何用 Conda 管理你的 Python 环境。如果我犯了任何错误或打字错误,请给我留言。干杯!
如果你喜欢读这篇文章,你可能也会喜欢这些:
作为一名数据分析师,我经常会收到这样的请求:“你能每周给我发一份报告吗?”或者…
towardsdatascience.com](/how-to-send-email-with-attachments-by-using-python-41a9d1a3860b) [## 最佳 Spyder 替代方案— VS 代码
如果你是 Spyder 或 R Studio 的粉丝,你一定会喜欢 Visual Studio 代码。
towardsdatascience.com](/best-spyder-alternative-vs-code-de0d9a01c8b5)
你可以在 Medium 上找到我其他作品的链接,关注我 这里 。感谢阅读!
用 Conda 管理 CUDA 依赖性
在下一个数据科学项目中管理 CUDA 依赖性的“最佳实践”

Conda 大大简化了启动新的 GPU 加速数据科学项目。来源:作者
将数据科学项目从 CPU 转移到 GPU 似乎是一项艰巨的任务。特别是有相当多不熟悉的附加软件,比如英伟达 CUDA Toolkit 、英伟达集体通信库(NCCL) 、英伟达深度神经网络库(cuDNN )下载安装。
如果你去 NVIDIA 开发者网站,你会找到大量关于如何在系统范围内安装这些库的文档和说明。但是,如果您需要这些新库的不同版本用于不同的项目,您该怎么办呢?你可以在系统范围内安装一堆不同版本的 NVIDIA CUDA Toolkit、NCCL 和 cuDNN,然后使用环境变量来控制每个项目的“活动”版本,但这很麻烦且容易出错。幸运的是有更好的方法!
在这篇文章中,我将向你展示如何使用 Conda 管理 NVIDIA CUDA Toolkit、NCCL 和 cuDNN 的项目特定版本。我假设您对 Conda 有基本的了解,所以如果您还没有听说过 Conda 或者刚刚入门,我鼓励您阅读我的其他文章Conda 入门 和 使用 Conda 管理您的数据科学项目。
NVIDIA 库可以通过 Conda 获得吗?
没错。您可以使用conda search命令查看默认渠道中有哪些版本的 NVIDIA CUDA Toolkit 可用。
$ conda search cudatoolkitLoading channels: done# Name Version Build Channel
cudatoolkit 9.0 h13b8566_0 pkgs/main
cudatoolkit 9.2 0 pkgs/main
cudatoolkit 10.0.130 0 pkgs/main
cudatoolkit 10.1.168 0 pkgs/main
cudatoolkit 10.1.243 h6bb024c_0 pkgs/main
cudatoolkit 10.2.89 hfd86e86_0 pkgs/main
cudatoolkit 10.2.89 hfd86e86_1 pkgs/main
NVIDIA 实际上维护着自己的 Conda 通道,默认通道中可用的 CUDA Toolkit 版本与 NVIDIA 通道中的版本相同。如果您有兴趣确认这一点,您可以运行命令conda search --channel nvidia cudatoolkit,然后将构建号与上面列出的默认通道中的构建号进行比较。
默认或 NVIDIA Conda 渠道提供的 NVIDIA CUDA 工具包版本的一个重要限制是它们不包括 NVIDIA CUDA 编译器(NVCC) 。
cuDNN 呢?
您还可以从默认渠道找到各种版本的 cuDNN。
$ conda search cudnnLoading channels: done# Name Version Build Channel
cudnn 7.0.5 cuda8.0_0 pkgs/main
cudnn 7.1.2 cuda9.0_0 pkgs/main
cudnn 7.1.3 cuda8.0_0 pkgs/main
cudnn 7.2.1 cuda9.2_0 pkgs/main
cudnn 7.3.1 cuda10.0_0 pkgs/main
cudnn 7.3.1 cuda9.0_0 pkgs/main
cudnn 7.3.1 cuda9.2_0 pkgs/main
cudnn 7.6.0 cuda10.0_0 pkgs/main
cudnn 7.6.0 cuda10.1_0 pkgs/main
cudnn 7.6.0 cuda9.0_0 pkgs/main
cudnn 7.6.0 cuda9.2_0 pkgs/main
cudnn 7.6.4 cuda10.0_0 pkgs/main
cudnn 7.6.4 cuda10.1_0 pkgs/main
cudnn 7.6.4 cuda9.0_0 pkgs/main
cudnn 7.6.4 cuda9.2_0 pkgs/main
cudnn 7.6.5 cuda10.0_0 pkgs/main
cudnn 7.6.5 cuda10.1_0 pkgs/main
cudnn 7.6.5 cuda10.2_0 pkgs/main
cudnn 7.6.5 cuda9.0_0 pkgs/main
cudnn 7.6.5 cuda9.2_0 pkgs/main
NCCL 怎么样?
默认频道有一些旧版本的 NCCL,但这些版本不会有用(除非你被迫使用非常旧版本的 TensorFlow 或类似软件)。
$ conda search ncclLoading channels: done# Name Version Build Channel
nccl 1.3.5 cuda10.0_0 pkgs/main
nccl 1.3.5 cuda9.0_0 pkgs/main
nccl 1.3.5 cuda9.2_0 pkgs/main
不要担心!康达锻造来救援。Conda Forge 是一个由社区主导的食谱、构建基础设施和 Conda 包管理器发行版的集合。当我在默认频道上找不到我需要的节目时,我总是会检查频道。
$ conda search -c conda-forge ncclLoading channels: done# Name Version Build Channel
nccl 1.3.5 cuda10.0_0 pkgs/main
nccl 1.3.5 cuda9.0_0 pkgs/main
nccl 1.3.5 cuda9.2_0 pkgs/main
nccl 2.4.6.1 h51cf6c1_0 conda-forge
nccl 2.4.6.1 h7cc98d6_0 conda-forge
nccl 2.4.6.1 hc6a2c23_0 conda-forge
nccl 2.4.6.1 hd6f8bf8_0 conda-forge
nccl 2.4.7.1 h51cf6c1_0 conda-forge
nccl 2.4.7.1 h7cc98d6_0 conda-forge
nccl 2.4.7.1 hd6f8bf8_0 conda-forge
nccl 2.4.8.1 h51cf6c1_0 conda-forge
nccl 2.4.8.1 h51cf6c1_1 conda-forge
nccl 2.4.8.1 h7cc98d6_0 conda-forge
nccl 2.4.8.1 h7cc98d6_1 conda-forge
nccl 2.4.8.1 hd6f8bf8_0 conda-forge
nccl 2.4.8.1 hd6f8bf8_1 conda-forge
nccl 2.5.6.1 h51cf6c1_0 conda-forge
nccl 2.5.6.1 h7cc98d6_0 conda-forge
nccl 2.5.6.1 hc6a2c23_0 conda-forge
nccl 2.5.6.1 hd6f8bf8_0 conda-forge
nccl 2.5.7.1 h51cf6c1_0 conda-forge
nccl 2.5.7.1 h7cc98d6_0 conda-forge
nccl 2.5.7.1 hc6a2c23_0 conda-forge
nccl 2.5.7.1 hd6f8bf8_0 conda-forge
nccl 2.6.4.1 h51cf6c1_0 conda-forge
nccl 2.6.4.1 h7cc98d6_0 conda-forge
nccl 2.6.4.1 hc6a2c23_0 conda-forge
nccl 2.6.4.1 hd6f8bf8_0 conda-forge
一些示例 Conda 环境文件
现在你已经知道如何找出各种 NVIDIA CUDA 库的哪些版本在哪些频道上可用,你已经准备好编写你的environment.yml文件了。在本节中,我将提供 PyTorch、TensorFlow 和 NVIDIA RAPIDS 的一些示例 Conda 环境文件,以帮助您开始下一个 GPU 数据科学项目。
PyTorch
PyTorch 是基于 Torch 库的开源机器学习库,用于计算机视觉、自然语言处理等应用。它主要由脸书人工智能研究实验室开发。Conda 其实就是推荐的安装 PyTorch 的方式。
name: nullchannels:
- pytorch
- conda-forge
- defaultsdependencies:
- cudatoolkit=10.1
- mpi4py=3.0 # installs cuda-aware openmpi
- pip=20.0
- python=3.7
- pytorch=1.5
- torchvision=0.6
官方的 PyTorch 二进制文件附带了 NCCL 和 cuDNN,所以没有必要在你的environment.yml文件中包含这些库(除非其他一些包也需要这些库!).还要注意频道优先级:官方pytorch频道必须优先于conda-forge频道,以确保官方 PyTorch 二进制文件(包括 NCCL 和 cuDNN)将被安装(否则你将在conda-forge获得一些非官方版本的 PyTorch)。
张量流示例
TensorFlow 是一个免费的开源软件库,用于数据流和跨一系列任务的差异化编程。它是一个符号数学库,也用于机器学习应用,如神经网络。
通过 Conda 可以获得 TensorFlow 的很多版本和构建(conda search tensorflow的输出太长,无法在此分享!).如何决定哪个版本是“正确的”版本?如何确保你得到一个包含 GPU 支持的构建?
使用tensorflow-gpu元包为您的操作系统选择合适的 TensorFlow 版本和版本。
name: null
channels:
- conda-forge
- defaults
dependencies:
- cudatoolkit=10.1
- cudnn=7.6
- cupti=10.1
- mpi4py=3.0 # installs cuda-aware openmpi
- nccl=2.4
- pip=20.0
- python=3.7
- tensorflow-gpu=2.1 # installs tensorflow=2.1=gpu_py37h7a4bb67_0
BlazingSQL + NVIDIA RAPIDS 示例
作为最后一个例子,我想告诉你如何开始与英伟达急流(和朋友!).
NVIDIA RAPIDS 是一套开源软件库和 API,让您能够完全在 GPU 上执行端到端的数据科学和分析管道(想想熊猫 + Scikit-learn ,但针对的是 GPU 而不是 CPU)。
我还在这个示例环境文件中包含了 BlazingSQL 。BlazingSQL 是一个开源的 SQL 接口,可以使用 NVIDIA RAPIDS 将海量数据集直接提取-转换-加载(ETL)到 GPU 内存中进行分析。安装 BlazingSQL 以便它能与 NVIDIA RAPIDS 一起正常工作比大多数 Conda 软件包安装要稍微复杂一些,所以我决定在这里包含一个工作示例。
最后,上面的环境还包括 Datashader ,这是一个图形管道系统,用于快速灵活地创建大型数据集的有意义的表示,可以通过 GPU 加速。如果你打算在 GPU 上进行所有的数据分析,你也可以在 GPU 上进行数据可视化。
name: null channels:
- blazingsql
- rapidsai
- nvidia
- conda-forge
- defaultsdependencies:
- blazingsql=0.13
- cudatoolkit=10.1
- datashader=0.10
- pip=20.0
- python=3.7
- rapids=0.13
但是如果我需要 NVIDIA CUDA 编译器呢?
在本文的开头,我提到了默认渠道提供的 NVIDIA CUDA Toolkit 版本不包括 NVIDIA CUDA 编译器(NVCC)。然而,如果您的数据科学项目有需要编译自定义 CUDA 扩展的依赖项,那么您几乎肯定会需要 NVIDIA CUDA 编译器(NVCC)。
您如何知道您的项目依赖项需要 NVCC?很有可能你会尝试上面的标准方法,而 Conda 将无法成功地创建环境,并可能抛出一堆编译器错误。一旦你知道你需要 NVCC,有几种方法可以安装 NVCC 编译器。
试试 cudatoolkit-dev 包
从conda-forge渠道获得的cudatoolkit-dev包包括 GPU 加速库、调试和优化工具、C/C++编译器和运行时库。这个包包含一个安装后脚本,用于下载和安装完整的 CUDA 工具包(NVCC 编译器和库,但不包括 CUDA 驱动程序)。
虽然conda-forge提供的cudatoolkit-dev包确实包括 NVCC,但我很难让这些包持续正确地安装。
- 一些可用的构建需要手动干预来接受许可协议,这使得这些构建不适合安装在远程系统上(这是关键的功能)。
- 其他一些版本似乎可以在 Ubuntu 上运行,但不能在其他版本的 Linux 上运行,比如 CentOS。
- 其他依赖 CUDA 的 Conda 包通常会安装
cudatoolkit包,即使这个包中包含的所有东西都已经通过cudatoolkit-dev安装了。
也就是说,首先尝试cudatoolkit-dev方法总是值得的。也许对你的用例有用。
下面是一个使用通过cudatoolkit-dev包安装的 NVCC 来编译来自 PyTorch 集群的定制扩展的例子,PyTorch 集群是一个高度优化的图形集群算法的小型扩展库,用于与 PyTorch 一起使用。
name: null
channels:
- pytorch
- conda-forge
- defaults
dependencies:
- cudatoolkit-dev=10.1
- cxx-compiler=1.0
- matplotlib=3.2
- networkx=2.4
- numba=0.48
- pandas=1.0
- pip=20.0
- pip:
- -r file:requirements.txt
- python=3.7
- pytorch=1.4
- scikit-image=0.16
- scikit-learn=0.22
- tensorboard=2.1
- torchvision=0.5
上面引用的requirements.txt文件包含 PyTorch 集群和相关包,如 PyTorch Geometric 。这是该文件的样子。
torch-scatter==2.0.*
torch-sparse==0.6.*
torch-spline-conv==1.2.*
torch-cluster==1.5.*
torch-geometric==1.4.*# make sure the following are re-compiled if environment is re-built
--no-binary=torch-scatter
--no-binary=torch-sparse
--no-binary=torch-spline-conv
--no-binary=torch-cluster
--no-binary=torch-geometric
这里使用的--no-binary选项确保了无论何时重建环境,都将重建带有自定义扩展的包,这有助于在从工作站移植到可能具有不同操作系统的远程集群时,提高环境构建过程的可重复性。
一般来说,使用 nvcc_linux-64 元包
获得 NVCC 并仍然使用 Conda 管理所有其他依赖项的最可靠方法是在您的系统上安装 NVIDIA CUDA Toolkit,然后安装来自conda-forge的元包[nvcc_linux-64](https://anaconda.org/nvidia/nvcc_linux-64),该元包配置您的 Conda 环境,以使用安装在您系统上的 NVCC 以及安装在 Conda 环境中的其他 CUDA Toolkit 组件。虽然我发现这种方法比依靠cudatoolkit-dev更健壮,但这种方法更复杂,因为它需要首先在您的系统上安装特定版本的 NVIDIA CUDA Toolkit。
要查看这种方法的完整示例,请看我最近的文章 为 Horovod 构建 Conda 环境。
摘要
我在这篇文章中涉及了很多内容。我向您展示了如何使用conda search来查看哪些版本的 NVIDIA CUDA Toolkit 和相关库(如 NCCL 和 cuDNN)可通过 Conda 获得。然后,我向您介绍了几个可以使用 GPU 的流行数据科学框架的示例 Conda 环境文件。希望这些想法能帮助你在下一个数据科学项目中从 CPU 跳到 GPU!
作为数据工程师管理数据—第 1 部分:了解用户
了解用户如何看待数据以及他们在使用数据时的痛点
作为一名数据工程师,我的工作围绕着管理数据资产,包括 ETL 脚本、数据库、数据仓库、数据访问控制、查询、仪表板和数据对象。随着数据越来越多,数据变得越来越大,管理数据变得相当困难。在这篇文章中,我想分享一些我在一家金融科技公司管理万亿字节数据时学到的东西。
这是一篇由三部分组成的系列文章。第 1 部分侧重于理解数据用户。第 2 部分分享了更多关于理解数据变更的内容。
用户如何查看数据?
在我们开始管理数据之前,让我们先试着了解我们的用户。在一家金融科技公司,我们的大多数用户都是内部用户,他们的角色各不相同,从产品经理、软件工程师、数据科学家、分析师、高管到客户支持团队。这些用户每天都以各种方式与数据进行交互。
一方面,业务/运营用户以报告仪表板和图表的形式使用数据。这是他们了解最新业务指标以做出日常业务决策的方式。
另一方面,数据分析师/数据科学家更具技术性。他们使用 SQL 查询、Jupyter 笔记本和 Python 库处理数据。有时,他们也是其他用户使用的下游数据资产的创建者。
软件工程师是产品的建造者。应用程序生成的数据存储在数据库中,也供其他用户或其他服务使用。这些数据通常用作分析和其他下游数据的原始数据。
最后但同样重要的是,产品经理还通过电子邮件/ slack 通知和警报来消耗数据,通知他们产品的最新状态。
数据用户面临哪些挑战?
对用户来说,理解数据通常很有挑战性。尤其对于一个新用户来说,数据本身乍一看似乎没有什么意义。数据通常以图表、列/字段和值的形式呈现。没有上下文,数据代表什么,数据是如何生成、更新和随时间变化的,往往并不明显。为了理解一段数据,用户通常需要花一些时间调查和熟悉数据。
当用户最终理解数据时,获得的知识通常是包含的,而知识转移往往是耗时且困难的。
此外,产品变更几乎总是会导致数据变更。数据用户还必须跟上产品的变化,以正确理解数据。这导致了产品和分析之间的巨大差距。
导航数据对数据用户来说也是一个巨大的挑战。由于用户通常只熟悉他或她密切使用的数据,因此通常很难浏览用户领域知识之外的数据。在数百个模式和数千个数据对象中,搜索数据就像大海捞针。通常,当创建数据的源或查询逻辑丢失时,数据也就失去了意义。因此,用户经常不得不重新构建查询或从头开始重新设计表,做了双重工作,同时还创建了重复的管道。这也可能导致不一致的数据推导和试图回答同一问题的重复图表。
数据用户对数据的信任度通常很低。由于信息经常缺失或不完整,您如何知道数据对象正按预期使用呢?因此,在使用数据时,这增加了错误报告、误解和混乱的发生。
数据工程师如何看待数据?
数据工程师也每天处理数据。但是,我们对数据的看法有点不同。
我们数据工程师从 10000 英尺的高度查看数据,在这里我们将数据作为一个整体系统来监管。通常,我们以数据仓库的健康指标的形式来查看数据,例如数量或运行与排队查询、表锁、内存使用和集群存储使用。我们维护并关注数据仓库的健康,以确保它能够支持我们的用户工作负载。
作为数据管道的构建者,我们也将数据视为数据源、数据目的地、数据类型和数据结构。我们将数据视为依赖关系,例如数据的上游和下游。我们确保产品中的变更被正确地传播到数据仓库中,以供我们的数据用户使用。
在我们管理数百条安排了 Airflow 和 spark 集群的数据管道时,我们还围绕它们构建了各种监控基础设施,以确保它们按预期工作。这有助于在出现任何破裂或错误的管道时提醒我们,并为我们提供系统关键健康指标的报告。
数据工程师的挑战是什么?
作为数据的守门人,我们数据工程师在管理数据时也面临着各种挑战。首先,数据太多了。尽管我们是数据管道的建设者和维护者,但我们通常不是数据的创造者,也不是数据的最终用户。因此,我们经常缺少关于数据含义或如何使用数据的上下文。软件工程师是数据源方面的专家,因为他们通常是数据的创建者,而数据科学家是使用数据的专家,因为他们知道如何用数据回答重要的业务问题。数据工程师同时管理数百条数据管道,我们几乎不可避免地会丢失对数据每日变化的跟踪。
数据在不断增长,越来越大,越来越多。这给数据工程师带来了一个挑战,他们需要构建更具可扩展性和健壮性的管道来支持不断增长的数据。适用于小数据的脚本不一定适用于大数据。我们曾经用 python 脚本来凑合。但是随着数据变得越来越大,我们还必须使用更具可扩展性的解决方案,如 Spark 和 Airflow Celery Workers 来处理更大的数据工作负载。
由于产品团队和数据工程团队通常独立工作,数据的变化有时不会传达给下游的数据用户。产品中的数据变化或错误数据可能会破坏下游的数据管道。数据工程师的大部分工作是修复和调试损坏或泄漏的管道。维护和修复损坏的管道,以及回填数据以便对数据进行校正,有时是乏味且耗时的。
我们还面临着管理数据资源的挑战,因为数据工作负载是动态的,用户行为是不可预测的。资源分配和流量管理可能会很棘手,因为我们不想供应太多或太少。供应过多会造成资源浪费并产生额外成本,而供应过少会导致系统过载。有时,当数据工作负载过高时,为了防止流量堵塞或避免系统崩溃,可能需要人工干预来释放资源。一些系统在提供资源方面不太灵活,我们经常需要做出艰难的权衡,以确保数据管道和数据仓库在各种工作负载下都能顺利运行。
结论
在本文中,我们探讨了不同类型的用户如何看待数据以及他们面临的挑战,通常围绕理解数据、信任数据和跟上数据变化方面的困难。数据工程师从更高的层面查看数据,以确保整体系统健康,并管理产品和分析团队之间的数据管道。由于数据量巨大,而且还在不断增长和变化,管理数据工作负载也极具挑战性。现在我们已经了解了数据用户和数据工程师的观点以及他们面临的挑战,接下来让我们看看数据是如何变化的,以及如何在第 2 部分和第 3 部分中管理它们。敬请期待!
作为数据工程师管理数据—第 2 部分:了解数据变更
了解在快速发展的公司中,数据的变化如何使数据处理变得富有挑战性
在上一篇文章中,我们讨论了用户如何看待数据以及他们在使用数据时面临的挑战。如果你错过了,你可以在第一部分找到它。
作为数据工程师,我们处理各种数据资产,从数据存储系统、数据管道到数据查询。如果数据是静态的,理解和管理数据就容易了。我们会想出一个解决方案,这个方案会永远有效。但事实往往并非如此。处理数据具有挑战性,因为数据总是在变化和增长。因此,我们理解和管理数据的解决方案和方式也需要改变。今天,我们来看看在一个成长中的公司,数据是如何变化的。
公司增长
公司增长是数据变化的直接原因之一。当公司很小的时候,公司可能只有几个产品。每个产品都会生成一些用户应用程序数据,这些数据存储在生产数据库中。出于分析目的,这些数据通过管道传输到数据仓库。因为数据的用例很小,数据仓库中的数据可能会被分组到更一般的组中,比如general_analytics。这个数据模型会工作一段时间,因为它服务于公司产品和用户的目的。

随着公司的发展,可能会增加新产品和新功能,这也会导致生产数据库中产生新的数据集。这些数据也将通过管道传输到数据仓库。但是很快,我们发现太多的数据被归到了general_analytics下,这使得理解和搜索数据变得更加困难。因此,我们开始将数据分成更多特定于产品的组。

随着公司的进一步发展,数据也变得更加多样化。一些产品变得越来越大,导致存储的数据集越来越大。随着分析团队的成长,他们还会发现更多的数据用例,有时还会通过组合原始数据集来衍生新的数据集。这些数据洞察进一步推动了公司内部的产品增长,改进了产品,也允许更多的跨产品协同作用。

这种循环继续下去,并进一步增加数据。随着公司的发展,产品的数量也在增长,开发产品的团队也在增长,这继续创造了更加丰富和多样化的数据集。
用户增长
另一个直接影响数据增长的原因是用户群的增长。随着产品用户群的增长,生成的数据量也在增长。这是有意义的,因为应用程序上的每个用户活动都会生成一些数据反馈给产品后端系统。随着越来越多的用户使用该产品,将会产生更多的应用程序数据并反馈给系统。因此,用户群的增长几乎与产品生成的数据量的增长率成线性关系。
数据增长
即使用户群和产品保持不变,数据本身也会随着时间的推移而增长。这是因为我们保留了应用程序生成的数据,即使是在一段时间之后。历史数据通常用于分析,以了解一段时间内的趋势和用户行为。此外,为了跟踪和审计的目的,通常有必要在应用程序中保留用户过去活动的跟踪记录。很少每天清除数据或“刷新”数据库。因此,随着公司的发展,数据量会随着时间的推移而增长。
产品变化
当产品中引入变更时,有时也会导致存储的数据发生变化。有时,它是添加的一个附加字段,就像检查用户是否活跃的标志。有时,它是一个被引入的新状态,比如除了先前的SUCCESS和FAILURE状态之外的一个PENDING状态。有时这些变化更加内在,比如贷款利息的计算方式。比如使用一个新的公式,或者在不同的条件下计算数字。这种变化很难跟踪,并且必须在团队之间进行沟通,以便用户理解和正确使用。
有时意外的产品变化会破坏下游的数据应用程序。不一致的数据类型(例如,从字符串类型更改为整数)或不同的时间戳格式是一些常见的数据错误。这种类型的数据更改可能会在应用程序中引入错误。数据类型的变化最好在团队间进行讨论和标准化,以便数据在应用程序间顺畅流动。
团队成长
随着数据的增长,数据工程团队及其职能也随之增长。当公司的数据集很小时,通常只需要一两个数据工程师。这些数据工程师的工作主要围绕构建 ETL 脚本和管理数据仓库。

小型数据工程团队的角色
随着数据变得越来越大,数据基础设施也在增长,数据工程师开始扮演不同的角色来满足数据用户的需求。例如,我们承担了数据保管人和分析工程师的角色,以更有效地支持数据用户。我们引入了工程实践,如 git 和将查询存储为代码,以支持版本控制。我们还帮助建立数据文档,以帮助用户轻松地找到和理解数据。由于我们使用许多数据存储系统,我们还担任不同团队的数据顾问,以帮助优化查询和高数据工作负载。
我们过去只使用一台服务器运行 ETL 脚本,一台服务器用于调度。现在,随着我们维护数百条数据管道并管理数万亿字节的数据,我们也转向了更具可扩展性的数据系统。我们的一套数据基础设施现在由诸如 Airflow with Celery Worker cluster、Spark cluster、一个更大的红移数据仓库以及各种类型的数据工具和存储系统(如 S3、dbt 等)组成。

现代数据工程团队的角色
由于我们现在有了一套更多样化的数据工具,我们每个人都开始专业化,以便更有效地工作。一些数据工程师专注于为分析用户提供转换后的数据,一些人管理数据基础设施和数据管道,而其他人则研究更好、更有效的数据工具。我们不再构建单一的端到端数据管道,而是改变了我们的工作方式,并创建了可重复使用的模块,可以帮助更好地构建数据管道的每个部分。
结论
在本文中,我们研究了导致数据变化的一些因素,如公司增长、用户群增长、数据增长和产品变化。随着数据的增长,数据工程团队也在不断发展,以满足不断变化的数据需求。现在我们已经了解了数据是如何变化的,接下来让我们看看如何在第 3 部分中管理数据。敬请期待!
将数据科学作为产品进行管理
数据科学团队如何应用产品管理实践来解决他们最大的挑战
根据沃顿商学院发表的一篇文章,数据科学工作的数量在过去几年经历了“巨大的增长——15 倍,20 倍”。然而,这并不意味着数据科学家轻松。随着麻省理工学院斯隆管理学院和波士顿咨询集团【2019 年 10 月的报告引用“到目前为止,十分之七的公司报告人工智能的影响很小或没有影响”,数据科学团队面临着克服这些障碍和展示影响的巨大压力。
在 2017 年 Kaggle 数据科学和机器学习状况调查中,16,000 名受访者指出了数据科学家在工作中的 7 个最大障碍:
- 脏数据(49.4%)
- 组织中缺乏数据科学人才(41.6%)
- 公司政治/缺乏对数据科学团队的管理/财务支持(37.2%)
- 缺乏需要回答的明确问题或可用数据的明确方向(30.4%)
- 数据不可用/难以获取(30.2%)
- 业务决策者不使用数据科学结果(24.3%)
- 向他人解释数据科学(22.0%)
除了脏数据,数据科学团队面临的所有障碍都与组织和利益相关者管理问题有关。
再多的 Python 或 R 代码也无法解决这样的挑战。相反,数据科学团队需要立即采用产品管理实践来有效地吸引利益相关者,并向组织展示他们的价值。以下是数据科学团队可以付诸实践的一些简单步骤
理解“要做的工作”

作者图片
数据科学或软件开发的每一个过程或方法都需要对涉众需求的理解。随着当今业务领域日新月异的变化,数据科学团队必须超越需求,成为业务的思想伙伴。
通过聘请哈佛商学院教授 Clayton Christensen 的“要做的工作”框架,数据科学团队可以更好地了解整个业务应用。这首先要从利益相关者那里了解他们的情况,是什么激发了他们的需求,最终,他们想要完成什么,以及他们想要的(和可测量的)结果是什么。这种理解可以通过发现对话和潜在的利用其他用户研究方法来实现。
例如,B2B 销售或营销团队可能会要求数据科学团队创建一个线索评分模型,以根据公司捕获的公司地理、人口统计和行为数据来确定主要线索。对于许多数据科学团队来说,这将是一个理想的请求,因为有一个清晰的业务用例,并且这是一个可以执行的项目,具有可衡量的结果(线索数量、线索转化、提升等)。)但是,在对利益相关方进行访谈后,数据科学团队可能会了解到该企业今年确实希望扩大利润。
虽然销售线索评分模型可以通过更好的渠道转换获得更高的利润,但公司可能还可以利用其他策略,如优化定价。通过确认业务目标,数据科学团队可以成为真正的合作伙伴,为他们的组织提供有价值的见解,并建议更高价值的替代解决方案,同时要求更低的成本,并实现预期目标。
通过让产品经理从战略角度了解客户挑战,数据科学团队可以更有效地应对 Kaggle 调查受访者强调的组织参与挑战,例如克服缺乏组织支持、采纳和理解的问题。
敏捷数据产品开发

照片由邦内瓦尔·塞巴斯蒂安 | Unsplash 拍摄
一旦数据科学团队更好地理解了他们的利益相关者的需求,他们就可以开始应用敏捷方法来管理作为数据产品的数据科学。定义数据产品与其说是关于构建最佳机器学习模型,不如说是关于定义模型将如何被使用。通过利用“要做的工作”框架并成为业务的思想伙伴,数据科学团队可以开始为需要构建的数据产品制定强有力的愿景。
数据产品可以具体化为网站的算法特性、交互式仪表板或其他分析驱动的解决方案。例如,电子商务网站上的数据产品可以包括产品详情页面上的产品推荐轮播、结账页面上的促销横幅、个性化报价推荐等。每个数据产品的背后都可能是模型或分析的不同迭代,数据科学团队将随着时间的推移不断改进这些模型或分析。
一旦建立了需要构建什么的愿景,下一个问题是如何保持与业务或产品团队的接触,并确保在进入开发时不断展示价值?这就是敏捷开发的关键所在。
敏捷开发关注迭代开发,适应变化的需求和解决方案,并遵循敏捷宣言的原则。关于敏捷方法有大量的可用资源,本文不会涉及。然而,当它应用于数据产品时,数据科学团队必须重视以下 4 个关键因素才能保持敏捷:
1.过程和工具之上的个人和交互
当涉及到数据科学时,《敏捷宣言》的许多价值观都非常适用。业务、数据科学、技术等之间的互动和交流。作为个体最终比任何标准化的工具或过程更重要。通过理解业务涉众的“要做的工作”,并成为其他内部团队的深思熟虑的合作伙伴,对成功开发数据产品极其重要。
除了业务利益相关方之外,数据科学家还必须与数据工程师、产品经理、开发人员、MLOps 和其他利益相关方接触和交流,以与他们的同行建立关系,并了解实现他们的目标需要什么。通过在整个组织中发展关系,数据科学家将对运营和部署他们的模型所需的所有任务有更全面的了解。
2.穷尽模型开发的模型迭代
一旦数据科学家理解了需求,他们的任务通常是开发尽可能好的模型。对于用于预测的传统机器学习模型,这通常意味着设计一套广泛而多样的模型特征,收集、清理和聚合数据,然后训练和验证模型,以期获得高度预测的模型。
然而,这个过程是非常耗时的,有时业务涉众直到几个月后才看到模型性能的任何结果。在模型需要由技术团队实时部署的情况下,实时计算这些特性的成本可能会非常高。
相反,数据科学团队可以采用迭代设计方法。实际上,这意味着首先与业务和技术团队合作,决定要利用的模型特性的子集。特别是在没有开发模型的情况下,发布一个最小可行的数据产品比试图提高 R 几个点更重要。
当没有足够的数据来正确训练模型时,可以应用这种迭代思想。不要因为缺乏数据而受阻。相反,用可用的数据做一个简单的分析,并开始用这些见解影响利益相关者的想法。之后,更容易在此基础上进行构建,并传达有时机器学习模型需要更多数据才能真正实现其价值。
3.利益相关方在数据所有权方面的合作
正如本文第一部分所强调的,数据科学团队的最大障碍可以在很大程度上通过更好的利益相关者协作来克服。如前所述,解决方案包括:
- 作为企业的思想伙伴,
- 与业务和技术合作伙伴共同设计模型,以及
- 发布并使用最小可行的数据产品,以便整个跨职能团队可以开始从使用度量和用户反馈中学习
数据科学团队必须帮助克服的另一个挑战是数据所有权何时成为办公室政治。有时,不同的团队会将他们控制“他们的数据”的能力视为他们的力量来源。不幸的是,当多个业务、数据科学、分析和技术团队共享这种类型的心态时,会导致数据囤积。这造成了数据孤岛,并限制了数据科学团队开发优秀模型的能力。最终结果是数据科学或人工智能项目没有创造任何价值。克服这种情况的唯一方法是确保所有的利益相关者从第一天起就保持一致并进行合作,并且高级发起人共同支持正在开发的数据产品的成功。
能够跨越通道并协调利益相关者的需求有时也意味着,当利益相关者可能缺乏某些技能时,数据科学家需要进入角色。有时,这意味着对业务利益相关者进行数据科学基础培训,创建可视化来展示来自模型的洞察力,构建其他工程团队可以使用的预测模型端点的原型,等等。
总之,协作意味着打破障碍,做任何必要的事情来解除项目障碍,同情并与所有利益相关者合作来交付成功的产品。
4.响应变化而不是遵循计划
商业和竞争环境的变化速度越来越快。如果你的公司在利用数据和机器学习作为竞争手段方面已经落后,那么数据科学团队能够应对变化而不是遵循计划就更加重要了。
让我们回到之前的例子,数据科学团队建议实施定价优化算法来帮助企业实现更高的利润。
假设数据科学团队完成了一个模型的开发,他们离与工程团队一起部署它还有两周时间。然而,根据最近的市场变化,高管团队将改变战略,进入一个更广阔的市场,以更低的价格提供更实惠的产品。
知道他们开发的模型会增加定价,这个数据科学团队应该继续发布吗?不要!不幸的是,一些公司可能会继续前进,因为在他们看来,“船已经启航了。”然而,真正成为业务合作伙伴的数据科学团队将会公开他们的发现,并且能够要求更多的时间来评估如何做出最佳响应。
如果通过早期的构思和咨询过程发现定价优化不再可行,数据科学团队应该已经有了可以部署的其他数据产品组合。通过遵循迭代设计和最小可行的数据产品发布思想,他们将会损失更少的时间,并且能够利用相同的过程来快速发布不同的数据产品。
今天开始应用产品管理实践的 3 种方法

照片由布拉登·科拉姆 | Unsplash 拍摄
改变过程和文化从来都不是简单或快速的。但是,数据科学团队可以立即采取三种产品管理实践:
- 捕捉用户故事 —产品经理经常以用户故事的形式捕捉产品需求,一般遵循“作为一个【用户】,我希望能够【做一些事情】,这样我才能【受益】”的格式这种形式相当符合“要做的工作”框架,该框架将客户的愿望描述为“当[情况/背景]我想要[激励],所以我可以[预期结果]。”无论数据科学团队采用何种格式或方法来捕捉利益相关者的需求,重要的是要非常明确地关注利益相关者可以获得的利益。
- 创建一个待办事项清单——不管你最终使用哪种敏捷方法,Scrum,Kanban 等等。您应该开始创建用户故事的积压。除了捕获笔记的实际性质,一个维护良好的 backlog 将开始浮现出利益相关者想要实现的重复出现的主题。一旦在要求的产品类型或期望的类似结果上出现某些模式,数据科学团队就可以开始开发考虑到多种用例的数据产品,以及首先解决大量或更高价值需求的优先路线图
- 迭代发布 —如前所述,数据科学家可能希望收集尽可能多的数据,设计最广泛、最具代表性的模型特征集,并开发具有最高预测能力的模型。然而,如果在开发模型的过程中业务发生了变化,这一切都是徒劳的。相反,与所有利益相关者合作,定义一个最小可行的数据产品,该产品将尽快上市,以便公司可以从实际使用指标和用户反馈中学习。在进行正式的客户发布之前,数据科学领导者应该为他们的团队提供机会,向业务和内部利益相关方展示模型或分析结果,以保持可见性并收集反馈。
Richard Sheng 是百威英博(Anheuser-Busch InBev)旗下 Z-Tech 的数据科学和分析全球总监,为全球小型企业带来数据驱动的技术解决方案。Richard 拥有 12 年以上为初创公司和财富 500 强公司开发数据产品的经验。
管理 Apache Airflow & Prefect 中数据管道之间的依赖关系
管理工作流之间依赖关系的简单方法

凯利·西克玛在 Unsplash 上的照片
如果你曾经为相互依赖的业务流程构建过数据管道,你可能会注意到,将公司的所有业务逻辑整合到一个单一的工作流程中并不能很好地工作,而且很快会变成一场维护的噩梦。许多工作流调度系统允许我们管理单个数据管道内的依赖关系,但它们不支持我们管理工作流之间的依赖关系。
解决这个问题的一个自然方法是将一个大管道分成许多小管道,并以某种父子关系协调它们之间的依赖关系。然而,有许多可能的方法来解决这个问题,我想分享一个对我很有效的简单方法。我希望它可以帮助您管理数据管道之间的依赖关系。
气流组织如何试图解决这个问题
在 GoDataDriven 的两位数据工程师编写的关于 Apache Airflow [1]的书中,有一章是关于管理依赖关系的。他们是这样总结这个问题的:
“Airflow 管理单个 DAG 内任务之间的依赖关系,但是它不提供 DAG 间依赖关系的机制。”
子标签
组织相互依赖的数据管道的一般问题是众所周知的,人们试图解决它的一种方法是使用子标记抽象。将工作流组织成子标签最初看起来是个好主意,但是很快导致了许多问题:
- 一个子 Dag 被解释为父数据管道中的图中的一个节点,即使该子 DAG 可能由许多任务组成
- 这意味着子 DAG 中的每个任务一次按顺序运行一个,这可能会导致调度过程中的死锁。
下面是另一个引用 [2]很好地总结了关于子标签有用性的讨论:
天文学家强烈建议远离子袋。
外部任务传感器
另一个想法是在父 DAG 中使用一个传感器,它定期探测子 DAG 的执行状态。这似乎是一个比子包更好的主意。然而,它只在父 DAG 和子 DAG 之间的时间表对齐的情况下才起作用,这是一个非常强的假设,在我的情况下几乎从未为真。想象一下,当您手动触发这个父 DAG 时会发生什么?它将永远运行,直到超时,因为子 DAG 不按相同的计划运行。
TriggerDagRunOperator
另一种方式是从父 DAG 触发子 DAG。我更喜欢这个想法,因为:
- 不存在产生死锁的风险
- 它还会在管道被意外触发时运行,例如。通过手动触发器。
不过,当我在 Airflow 中尝试时,我发现当前的TriggerDagRunOperator实现是以一种一劳永逸的方式工作的。这意味着父 DAG 不会等到触发的子 DAG 完成后才开始下一个任务!如果我们希望管理数据管道之间的依赖关系,这不是我们想要的。
为了说明这一点,让我们看看下面的管道:

作者图片
如果我们将TriggerDagRunOperator用于父 DAG 中的业务逻辑层,它将触发子 DAG 的 DagRun,但随后它将立即启动数据集市任务,然后等待子 DAG 中的所有bus_logic_ETL_x任务完成。
我用气流解决的方法
我的解决方案是:
- 在每个子 DAG 的末尾添加一个虚拟任务
finish - 实施
WaitForCompletion传感器,该传感器在气流元数据数据库中检查子 DAG 的最后 DagRun 的状态。我们将子 DAG 的最后一个 DagRun 标识如下:它必须以"trig__"开头,因为每个由外部 DAG 触发的 DagRun 都是这样命名的。然后,我们按照执行日期降序排列这些 DagRun,并使用LIMIT 1获得最后一个→这正是我们想要寻找的 Dag run。 - 在这个传感器中,我们探测这个 DagRun 中的
finish任务的状态。如果是success,则传感器完成任务,并可以继续执行父管道中的数据集市任务。但是只要不是成功 ,这就意味着要么任务仍在运行,要么它失败了。在这两种情况下,这意味着我们不能继续进行数据集市任务。
这是传感器的实现:
这是我在父 DAG 中使用该传感器的方式:
提督是如何处理这个问题的
Prefect 包括许多开箱即用的有用抽象。其中之一是FlowRunTask,它包含一个参数wait=True,该参数将与我的WaitForCompletion在气流中具有相同的效果,而无需我实现任何执行定期数据库查找的传感器。这将:
- 触发子流程
- 等待子流程完成,然后再继续下一个任务。
主流(即父流)
父流的整个实现就这么简单:

如果我们通过运行flow.visualize来可视化这个流,我们可以看到子流甚至以不同的方式被可视化,以便容易地区分普通任务和由FlowRunTask ( 或其他类型的任务(如 ex)触发的流。映射的任务)。
子流程
我还创建了一些非常基本的子流,这样我们就可以运行一个完整的示例,并在 UI 中看到输出。在下面的脚本中,您可以看到三个子流程,每个子流程有三个任务:
staging_area流量business_logic_layer流量data_mart流量
现在让我们通过注册父流(MasterFlow)和三个子流来运行完整的示例,并确认流之间的依赖关系如预期的那样工作。



完美的云用户界面:由父流(主流)按照我们指定的顺序触发的子流——图片由作者提供

完美云用户界面:父流(主流)按预期最后完成,因为它等待子流的完成—图片由作者提供
只有在暂存区和业务逻辑层流程都完成后,我们才能确认依赖关系得到了尊重,并且数据集市才开始运行。
如果出现故障,我们可以很容易地导航到相应的子流来检查日志:

Prefect Cloud UI:检查来自子流的日志——按作者排序的图片
如何调度相互依赖的数据管道?
为了正确地构建和调度这些父子依赖关系,我们可以使用“主”数据管道(也可以称之为“父数据管道”或“协调数据管道”),如上例所示,而只调度那些父管道。因为子流是直接从父流触发的,所以不需要对它们进行调度。
让我们用一个具体的例子来展示一下。让我们假设,目前,这些子流具有以下执行运行时:
- 暂存区 : 2.5 小时
- 业务逻辑 : 1.5 小时
- 数据集市 : 2 小时。
这意味着如果我们安排MasterFlow在晚上 2 点运行,它将在凌晨 2 点运行 staging_area 开始,然后 business_logic 将在凌晨 4:30 开始, data_mart 将在早上 6 点开始,整个 ETL 将在早上 8 点完成。
要实现这一点,我们只需在第 6 行和第 9 行向MasterFlow添加一个调度,如下所示:
注:此时间表适用于 UTC。要使用时区特定的计划,请使用:
这种主流方法的好处是什么?
假设您想要修改业务逻辑层并向其添加一个任务:通过使用这种方法,您可以在不影响临时区域和数据集市工作流的情况下进行修改。你不需要重新安排任何事情,你也不会陷入任何僵局。
从用户的角度来看,哪种实现更容易?
总的来说,我发现完美的实现更容易,因为我不必编写任何定制的传感器逻辑来正确反映数据管道之间的依赖关系,并且它开箱即用。在这些抽象的设计中,它显示了很多远见。
提督社区也在讨论 Github 第期【3】中的子流程——如果你有兴趣的话,请继续关注。
结论
在本文中,我们研究了如何管理数据管道之间的依赖性。我们展示了历史上气流是如何解决这个问题的。
然后,我提出了一个解决这个问题的简单方法,它基于一个原则:创建一个主数据管道来调度和触发子工作流,同时确保当被触发时,主数据管道等待直到子工作流完成,然后再触发下一个工作流。
“触发+等待”范式似乎比根据时间表调整相互依赖的管道更安全,并且让我们以简单的方式管理工作流之间的依赖关系。
感谢您的阅读!如果这篇文章有帮助,请随时关注我的下一篇文章。
参考文献:
[1]“带有阿帕奇气流的数据管道”——巴斯·p·哈伦斯拉克和朱利安·鲁特格尔·德·鲁特
[2]天文学家博客:https://www.astronomer.io/guides/subdags/
[3]关于子流的提督社区:https://github.com/PrefectHQ/prefect/issues/1745
管理信息流行病学——使用数据科学减缓错误信息的传播
社交媒体公司如何使用机器学习来打击假新闻

随着越来越多的人依赖社交媒体来了解时事,托管公司有道德责任来抵御虚假信息。虚假信息是一种旨在操纵和误导的错误信息,会造成动荡和恐慌。其他类型的错误信息,如谣言和恶作剧,如果不加制止,也有可能给粗心的读者带来精神和身体上的伤害。阻止错误信息传播的关键是对他们采取迅速的行动,因为他们有快速传播的趋势。事实上,研究表明谎言传播的速度比真相快得多(来源)。社交媒体公司已经制定了协议来限制不准确内容的传播,但这些协议只有在内容经过第三方事实核查合作伙伴审查后才能生效。因此,重点在于快速评估准确性。我们已经看到科技公司在这方面的非凡创造力。即使用机器学习算法来补充事实检查程序,以识别不准确的内容。然而,这还不是一个完整的解决方案。在本文中,我们将研究这一过程,并探索它可能如何演变。
如何识别错误信息

事实核查程序工作流程
评估内容准确性的过程始于对潜在错误的内部筛选。这涉及利用自动化和机器学习模型来拾取各种信号。如果内容被确定为潜在的错误信息,它将被发送给事实核查合作伙伴进行进一步审查。在手动研究和/或咨询主要来源后,分配内容评级。结果评级通知社交媒体公司是否需要采取行动。此外,评级还有助于训练机器学习模型,以便在未来更好地捕捉错误信息。以下是机器学习对这一过程的贡献:
- 预测模型大大减少了第三方事实核查合作伙伴需要执行的审查数量
- 发现重复或近似重复的内容,为事实核查合作伙伴腾出了审查新的错误信息实例的空间
这是一个相当稳健的过程,但并非没有挑战。这一过程面临的主要挑战如下:
- 活跃用户的庞大和不断增长的数量使该平台成为协调宣传攻击的目标,为事实核查计划带来紧迫性和繁重的工作量
- 用作预测分类模型训练的语料库的经过验证的欺骗性内容的缺乏是机器学习方法的一个障碍。由于需要不同的处理方法,从而稀释了可获得的数据,人们希望有更窄的“真实”类别,这进一步加剧了这种情况
- 在真实内容背后隐藏误导性内容的“坏演员”很难被发现。例如,迷因可以使用叠加在照片或视频上的文本来形成欺骗性的内容
- 讽刺可能会被人误解,对计算机来说更难

随着社交媒体成为人们获取新闻的主要媒体,月活跃用户持续增长
仔细看看筛选过程

自动化和机器学习寻找信号来筛选内容
发展中
科技公司正在努力改善这一过程,方法是大幅扩展他们的数据库,这将帮助他们建立人工智能,以打击“深度假货”和“武器化模因”等复杂的攻击。算法和模型的有效性在很大程度上取决于是否有多样化的数据集来进行训练。幸运的是,随着技术社区在数据共享方面的广泛合作,模型在理解内容方面变得越来越好。尽管如此,这项工作仍在进行中。
推荐
应该研究一些考虑因素,以便立即做出改进。我正在探索的一个建议是为第三方事实检查者对内容进行优先排序和专门化。我们可以执行 A/B 测试来比较周转率和总体病毒率,以衡量这些措施的影响。
- 在具有传播倾向的危险内容成为病毒之前,对其进行优先级排序
- 内容专业化将内容提交给专业领域内的第三方事实审查员,以减少审查所需的时间
摘要
在最近的健康危机之前,流行病是一种困扰我们很久的疾病。如果没有适当的管理,它会给我们的社会带来巨大的危害。谢天谢地,有技术工具可以帮助我们降低这些风险。我们回顾了事实检查的进展,特别是机器学习如何在这个用例中应用。
在 Python 中管理实例属性
在 Python 中创建托管属性

通常,在 python 类的实现中,如果我们能够轻松地添加额外的处理来获取和/或设置实例属性,将会非常有用。例如,在获取/设置实例属性的过程中,能够执行类型检查或其他形式的验证会很有用。在本帖中,我们将讨论如何在 python 中管理实例属性。
我们开始吧!
假设我们有一个名为“Cars”的类,其属性为“car_brand”:
class Car:
def __init__(self, car_brand):
self.car_brand = car_brand
让我们将汽车类实例初始化为“Tesla”:
car1 = Car('Tesla')
print("Car brand:", car1.car_brand)

虽然这样做很好,但是如果我们用一个错误的‘car _ brand’输入值初始化一个实例,就没有数据验证或类型检查。例如,如果我们用数字 500 的汽车品牌值初始化一个汽车实例:
car2 = Car(500)
print("Car brand:", car2.car_brand)

我们应该有一种方法来验证这个实例属性的类型。我们可以通过将“car_brand”属性定义为“property”来自定义对属性的访问:
class Car:
...
@property
def car_brand(self):
return self._car_brand
将' car_brand '定义为' property '允许我们将 setter 和 deleter 函数附加到' car_brand '属性。让我们向‘car _ brand’属性添加一个 setter 方法,如果用非字符串值初始化实例,该方法将引发一个错误:
class Car:
...
#setter function
[@car_brand](http://twitter.com/car_brand).setter
def car_brand(self, value):
if not isinstance(value, str):
raise TypeError('Expected a string')
self._car_brand = value
让我们再次定义我们的实例,用我们的整数输入 500:
car2 = Car(500)
print("Car brand:", car2.car_brand)

另一个要考虑的实例管理操作是删除实例属性。如果我们看看我们的初始实例:
car1 = Car('Tesla')
print("Car brand:", car1.car_brand)
我们可以很容易地删除属性值:
car1 = Car('Tesla')
print("Car brand:", car1.car_brand)
del car1.car_brand
print("Car brand:", car1.car_brand)

我们可以添加一个 deleter 函数,在尝试删除时引发错误:
class Car:
...
#deleter function
[@car_brand](http://twitter.com/car_brand).deleter
def car_brand(self):
raise AttributeError("Can't delete attribute")
让我们再次尝试设置和删除属性值:
car1 = Car('Tesla')
print("Car brand:", car1.car_brand)
del car1.car_brand

我就讲到这里,但是您可以自己随意摆弄代码。
结论
总之,在这篇文章中,我们讨论了如何在 python 类中管理实例属性。我们展示了通过将类属性定义为“属性”,我们可以附加 setter 和 deleter 函数来帮助我们管理属性的访问。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
使用 Conda (+pip)管理基于 JupyterLab 的数据科学项目
为眼光敏锐的数据科学家收集的“最佳实践”

使用 Conda (+pip)和一点 Bash,自动安装 JupyterLab 很容易。(图片:NASA/JPL/比约恩·杰森/塞恩·多兰/Flickr(CC BY-NC-ND 2.0))
本文讨论了使用 Conda (+pip)管理基于 JupyterLab 的数据科学项目的两种方法:一种是“全系统”方法,其中 Conda (+pip)用于管理所有项目共享的单个 JupyterLab 安装,另一种是“基于项目”方法,其中 Conda (+pip)用于管理每个项目的单独 JupyterLab 安装。在描述了这两种方法之后,我将浏览一些例子并讨论相关的权衡。
“系统级”JupyterLab 安装
Conda (+pip)采用“全系统”方法管理 JupyterLab,用于管理所有或您的数据科学项目共享的 JupyterLab 安装。“全系统”方法有几个好处。
- 一组通用的 JupyterLab 扩展简化了用户界面(UI)和用户体验(UX)。
- 允许更快地启动新项目,因为不需要安装(和构建!)JupyterLab 每一个项目。
- 通过用户主目录中的
~/.jupyter目录中的文件对 JupyterLab 进行简单的低级配置。
“系统范围”安装的典型 Conda environment.yml
下面是一个“系统级”JupyterLab 安装的存根environment.yml文件。
name: jupyterlab-base-envchannels:
— conda-forge
— defaults
dependencies:
— jupyterlab
— jupyterlab-git # provides git support
— nodejs # required for building (some) extensions
— pip
— pip:
— -r file:requirements.txt # extensions available via pip go here
— python
有几件事值得注意。首先,您应该将通过 Conda(通常来自[conda-forge](https://conda-forge.org/)频道)获得的任何 JupyterLab 扩展作为依赖项包含在这个文件中。通过 Pip 获得的 JupyterLab 扩展应该单独包含在一个requirements.txt文件中(下面讨论)。第二,我明确地将nodejs作为一个依赖项。 Node.js 是重新构建 JupyterLab 所必需的(这可能是必需的,取决于您的扩展集合)。最后,我安装 Pip 并使用pip来安装包含在一个单独的requirements.txt文件中的所有包和扩展。
“系统范围”安装的典型 pip 要求. txt
关于requirements.txt文件没有什么特别的。您只需列出您想通过pip安装的包和扩展。在这里,我包括了 Jupyter 语言服务器协议扩展,它带来了完整的 IDE 功能,比如代码导航、悬停建议、linters、自动完成和 JupyterLab 的重命名。
jupyter-lsp
python-language-server[all]
使用 Bash 脚本自动化jupyterlab-base-env构建
因为 Conda (+pip)环境的环境构建过程有点复杂(因为它涉及到通过 Conda 安装包,通过 pip 安装包,然后可能安装扩展并重新构建 JupyterLab 本身),所以使用 Bash 脚本自动构建环境是一个好主意。
#!/bin/bash --login
set -econda env create \
—-name jupyterlab-base-env \
—-file environment.yml \
—-force
conda activate jupyterlab-base-env
source postBuild # put jupyter labextension install commands here
注意--login标志的使用。这确保了脚本将在一个登录 shell 中运行,该 shell 将正确地获取必要的 Bash 概要文件,这些文件是conda activate命令按预期工作所必需的。还要注意对一个postBuild文件的引用。这是一个 Bash 脚本,包含启用这些扩展和重建 JupyterLab 所需的任何必要的jupyter labextension install命令。我已经在 GitHub 上包含了上面提到的所有配置文件的工作示例。
保持身体的倾斜
您的jupyterlab-base-env环境应该仅包含 JupyterLab 和任何必需的扩展(+依赖项)。不要将用于数据科学项目的包安装到您的jupyterlab-base-env中。相反,您应该为每个项目创建单独的 Conda (+pip)环境,然后为每个特定于项目的 Conda (+pip)环境创建定制的 Jupyter 内核。
为 Conda 环境创建 Jupyter 内核
为您项目的每个 Conda (+pip)环境创建一个定制的 Jupyter 内核,这将允许您在一个通用的 JupyterLab 安装中从这些环境启动 Jupyter 笔记本和 IPython 控制台。您甚至可以使用[jupyter-conda](https://github.com/fcollonval/jupyter_conda)扩展为您机器上的所有 Conda (+pip)环境自动化内核创建过程!
然而,与其为每个 Conda (+pip)环境创建定制内核,我更喜欢为我真正关心的特定 Conda (+pip)环境手动创建定制 Jupyter 内核。
如何手动创建自定义 Jupyter 内核
在为 Conda (+pip)环境创建定制内核之前,您需要确保在 Conda 环境中安装了[ipykernel](https://pypi.org/project/ipykernel/)包,因为您将需要使用该包来创建内核规范文件。
conda activate $PROJECT_DIR/env # don’t forget to activate!
python -m ipykernel install \ # requires ipykernel!
--user \
—-name name-for-internal-use-only \
—-display-name “Name you will see in the JupyerLab launcher”
基于项目的 JupyterLab 安装
通过“基于项目”的方法来管理 JupyterLab,Conda (+pip)用于管理每个项目的独立 JupyterLab 安装。“基于项目”的方法有几个优点。
- 更灵活的用户界面/UX,因为 JupyterLab 版本和扩展可以为每个项目定制。
- JupyterLab 前沿特性的更简单实验。
- 自动生成数据科学项目报告“活页夹就绪”。
“基于项目”安装的典型 Conda environment.yml
这个environment.yml文件的结构类似于“全系统”方法的结构。不同之处在于,使用“基于项目”的方法,您应该将您的项目所需的所有包和扩展通过 Conda 添加到这个文件中;皮普和requirements.txt文件也是如此。
name: nullchannels:
— conda-forge
— defaults
dependencies:
— jupyterlab
— jupyterlab-git # extensions available via conda go here
- nodejs
— pip
— pip:
— -r file:requirements.txt # packages available via pip go here
— python
使用 Bash 脚本自动构建项目环境
同样,您应该尽可能自动化 Conda (+pip)环境构建。这个脚本与“系统范围”方法中使用的脚本之间的唯一区别是,我将 Conda (+pip)环境安装在我的项目目录的一个名为env的子目录中。这是一个 Conda (+pip)“最佳实践”。
#!/bin/bash —-login
set -eexport ENV_PREFIX=$PROJECT_DIR/env
conda env create \
—-prefix $ENV_PREFIX
—-file environment.yml \
—-force
conda activate $ENV_PREFIX
source postBuild # put jupyter labextension install commands here
“基于项目”的 JupyterLab 安装示例
正如我所承诺的,这里有几个“基于项目”方法的例子,可以作为你下一个数据科学项目的灵感。
- JupyterLab+Scikit Learn+Dask:基于 CPU 的数据科学项目环境,将 JupyterLab 与 Scikit-learn 和 Dask (还有朋友!).包括一些常见的 JupyterLab 扩展。
- JupyterLab + PyTorch :使用 JupyterLab 和 PyTorch 进行 GPU 加速深度学习的标准环境。包括 GPU 和深度学习特定的 JupyterLab 扩展,如 jupyterlab-nvdashboard 和 jupyterlab-tensorboard 。
- JupyterLab+NVIDIA RAPIDS+BlazingSQL+Dask:更复杂的 GPU 加速机器学习环境有 JupyterLab、 NVIDIA RAPIDS 、 BlazingSQL 、 Dask (还有很多的朋友!).包括一些常见的 JupyterLab 扩展以及一些特定于 GPU 的扩展,如 jupyterlab-nvdashboard 。
%conda 和%pip 魔术命令
任何关于 JupyterLab、Conda 和 pip 的讨论,如果不提及内置的 IPython 魔术命令,将软件包通过 Conda ( [%conda](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-conda))或 Pip ( [%pip](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-pip))安装到活动环境/内核中,都是不完整的。
- 这两个命令都可以在 Jupyter 笔记本或 IPython 控制台中使用。
%conda和%pip对新项目的原型设计都非常有用。- 对于“生产”,更喜欢向
environment.yml或requirements.txt文件添加新的包(并重建环境)。
摘要
希望到此为止,您将理解用 Conda (+pip)管理 JupyterLab 安装的“系统范围”和“基于项目”方法之间的区别。您还看到了这两种方法的几个示例,包括一些可用于下一个数据科学项目的起始代码。
总的来说,我推荐“基于项目”的方法,因为它具有更大的灵活性和最小的额外开销。如果您只在部分项目中使用 GPU,那么您可能更喜欢“基于项目”的方法,因为有一些很好的用于 GPU 加速数据科学项目的 JupyterLab 扩展(您不想为纯 CPU 项目安装这些扩展)。然而,如果您的所有项目要么只有 CPU,要么几乎总是使用 GPU,并且总是使用一组通用的 JupyterLab 扩展,那么您可能更喜欢“系统范围”的方法。
用 Mlflow 管理机器学习开发周期
使用 mlflow 跟踪、比较、评估和服务您的机器学习模型。

管理机器学习开发生命周期是一项复杂的任务。可复制性是很难的,通常从开发最好的模型并将其转移到生产的过渡会变得混乱和延迟。
原因是每个新模型都需要修改生产代码,因为现在您的服务器需要指向新模型并快速迭代,同时还要维护审计跟踪,这是一项具有挑战性的任务。这就是 mlflow 的用武之地。从跟踪模型参数、度量和工件,到将您的代码作为项目在其他系统上运行,以及为模型服务,Mlflow 都做了。
注意:按照文档安装 mlflow
物流跟踪
让我们从跟踪模块开始,设置我们的跟踪服务器。要设置我们的跟踪服务器,我们首先需要创建一个数据库。只需打开 mysql 命令提示符并执行以下查询
-> CREATE DATABASE mlflow_tracking_database;
现在,您有了数据库来跟踪您的机器学习模型结果、参数和模型。数据库将存储度量、参数和其他元相关信息。对于运行期间产生的文件或工件,我们将使用基于文件的存储,并在下面的命令中指定路径,以便在跟踪服务器中找到这些运行。
mlflow server --backend-store-uri mysql+pymysql://root@localhost/mlflow_tracking_database --default-artifact-root file:/./mlruns -h 0.0.0.0 -p 5000
--backend-sotre-uri指定我们需要跟踪 mlflow 运行的数据库的 uri,而--default-artifact-root指定存储模型文件和其他工件的路径。

mlflow 跟踪服务器命令的屏幕截图
您的跟踪服务器现在应该已经启动并运行了。要验证其设置是否正确,只需进入http://localhost:8000,您将看到 mlflow 界面。
现在让我们训练几个模型,并使用我们刚刚创建的服务器记录它们。
密码
我们可以多次运行这个脚本,也可以运行另一个脚本,我们的所有运行都将被记录到我们刚刚设置的跟踪服务器中。在多次迭代和尝试不同的技术之后,我们可以比较我们在跟踪服务器上跟踪的运行。这个跟踪服务器的优点是,同一个网络中的多个团队可以以集中的方式跟踪他们的跑步,每个人都可以更有效和高效地协作。
ml 流程模型
在 mlflow UI 中比较运行后,我们需要做的就是识别最佳模型的运行 id,并使用 mlflow 模型功能提供它。这将建立一个 web 服务器,允许您发送 POST 请求以从您的模型中获得预测。
$ mlflow models serve -m file:/home/saad/downloads/<run-id>/XGB_Model
-m flag 指定了模型 uri。你也可以根据自己的需要传递其他的标志。例如--no-conda将允许你在相同的环境中运行你的模型,而不是创建一个新的。你可以在这里了解更多关于服务 mlflow 模型
注意:
mlflow models serve仅在 Linux 上可用,在 windows 上尚不支持。
现在,为了测试我们的 mlflow 模型服务器,我们需要做的就是发送一个 POST 请求。我将使用邮递员来做这件事。

正如所料,我从 mlflow 模型服务器得到了一个指定价格的响应。我希望这篇文章能让你快速了解 mlflow 以及如何在生产中使用它。
我个人认为 mlflow 使得机器学习模型的开发周期变得更加容易。它非常直观,而且有一个不断发展的社区在你遇到困难时帮助你。Mlflow 仍然有很多东西可以提供,我鼓励你进一步探索它。
参考资料:
[1]https://www.mlflow.org/docs/latest/tracking.html
https://www.mlflow.org/docs/latest/models.html
管理机器学习项目
工具决策之旅

由 Unsplash 上 Mukuko 工作室拍摄的照片
当我开始全职在 slashwhy (以前是 SALT AND PEPPER Software)做机器学习研究员时,我来自一个用 C#和 Python 开发 Unity 的背景。在几个月的过程中,我们的团队发展到总共 5 人,我们很快就不得不面对一些关于我们工作和组织自己的方式的非常重要的问题。作为一个快速的背景,我们几乎总是与来自工业领域的广泛不同客户合作深度学习项目,从大型机器数据到光学识别和质量保证。因此,我们的工作总是涉及到与客户的密切互动:理解数据、挑战以及应该通过使用机器学习实现的预期价值。
我们必须问自己的问题如下:
- 我们如何编写代码和构建项目?
- 我们如何管理我们的 ML 实验?
- 我们如何向客户传达我们的工作?
- 我们如何保证代码和结果的质量?
虽然这些问题中的一些乍一看似乎微不足道,但它们的答案并不直截了当。回到我们开始的时候,我们只有有限的计算资源和有限的预算——这种情况对于以前在小型年轻团队中工作过的人来说可能很熟悉。因此,在试图找到问题的答案时,我们试图避免昂贵的开箱即用的解决方案,而是专注于免费可用的开源解决方案。我们来依次看看前面提到的问题以及我们的解决方案和经验。
我们如何编写代码和构建项目?
去还是不去?
我们团队中五分之三的人有更传统的软件开发背景。因此,使用 git 作为版本控制,并为项目提供清晰的编码指南和风格指南,这也是我们希望应用到 ML 工作中的一个概念。
Gitlab 已经被我们公司的几乎所有人使用,所以版本控制不是问题。另一方面,代码和项目结构。
在讨论如何合理构建我们的工作流程时,很快就引出了 Jupyter 笔记本的问题——以及如何在日常工作中处理它们。看看笔记本电脑和谷歌协作变得多么受欢迎,现在你可能会问“我为什么不用 Jupyter 笔记本做任何事情呢?”。根据我们的经验,Jupyter 笔记本非常适合探索性工作,例如初始数据探索,甚至是模仿快速原型。它们易于使用,并能很好地跟踪你对数据做了什么。但是,一旦你的项目增长,Docker 部署、代码重用和测试等事情进入阶段,它们很快就会变得一团糟。它们也不能很好地进行版本控制,因为你的算法的逻辑与表示语法纠缠在一起——使得评论一片混乱(特别是如果有人在提交前忘记清除输出)。
因此,我们决定以模板的形式为所有即将到来的项目创建一个结构基础。在其第一个版本中,它基本上是一个 bash 脚本,创建了一个文件和文件夹结构,如下所示:
src/
├── train.py
├── inference.py
├── data_processing/
│ └── data_loader.py
├── utils/
│ └── ...
├── models/
│ └── model.py
└── visualization/
└── explore.ipynb.gitignore
README.md
requirements.txt
run.py
对我们来说,让不同的项目尽可能相似是很重要的。毕竟,我们做客户工作——新项目稳步发展,最初不清楚它们是否能通过概念验证阶段。我们希望能够查看我们的一个团队成员正在进行的项目,并立即了解正在发生的事情,而不必先通读他们的所有代码。此外,拥有结构清晰的项目使得与客户的沟通更加容易。
此外,我们决定使用一个名为 run.py 的脚本作为我们所有项目的中心接口:它必须在所有存储库中相同,并管理诸如 GPU 使用和对指定数据运行训练或模型推理之类的事情。
虽然我们决定不使用 Jupyter 笔记本作为我们的常规编码程序,但我们仍然保留了一个探索性的笔记本作为我们模板的一部分,用于最初的数据探索。
以这种方式设置我们的项目已经很有帮助了,但是仍然没有解决一些基本问题:
- 我们需要设法管理我们的训练
- 我们需要记录我们在一个项目中所做的事情——正确地!
- 我们调整超参数的方法在这一点上是相当直观的,并且不是非常结构化
- 我们无法以自动化的方式检查更复杂的数据操作
我们如何管理我们的 ML 实验?
在这一点上,我们在项目中有了一个清晰的代码结构,甚至有了一个风格指南,我们就使用什么样的编码指南达成了一致。我们仍然缺少的是有系统地组织我们实际核心工作的方法——ML 实验。
当时,我们依靠 Tensorboard 进行结果跟踪和可视化。这基本上没问题,但是没有中心位置来存储和比较我们的结果。此外,由于我们使用不同的机器来运行训练,这很快导致了一堆 Tensorboard 记录文件到处都是。简而言之,我们在寻找更好的解决方案。
对于我们和我们的大多数客户来说,数据安全和隐私是非常重要的话题。对于许多客户来说,将基于云的服务与他们的数据结合使用是绝对不可能的。通过物理硬盘发送数据并不罕见,因为人们往往非常小心,尤其是对于实际的客户数据。无论我们对此问题的解决方案是什么样的,它都必须是本地的,而不是第三方云服务。
幸运的是,大约在那个时候,一个新的开源项目诞生了,它将极大地改变我们的工作流程。Sacred 是一个致力于管理 ML 实验的框架,通过记录并保存到数据库中。

包罗万象。来源:github.com/vivekratnuel/omni board
我们很快决定尝试一下,将我们的一个 ML 工作站变成了一个 MongoDB 服务器。拥有一个包含许多不同脚本的分散的项目结构在这里被证明是一个好处,因为神圣很好地集成到这个结构中。在很短的时间内,我们在神圣的支持下开始了我们的第一个项目。现在我们有了一个带有非常结构化和有组织的跟踪系统的中央服务器——我们决定使用 Omniboard 作为数据库查看器。
当时唯一的问题是,神圣仍然缺少一些对我们来说很关键的功能:
超参数配置文件
当使用 sacred 时,通常有一个超参数字典作为主训练脚本的一部分,用于覆盖函数调用中的参数。虽然我们真的很喜欢这个想法,但它不太适合我们为代码的每个部分分别编写脚本的结构,所以我们在新的项目模板中添加了一个 config.py 脚本。这个配置脚本包含一个默认配置,可以通过函数调用来访问,还包含一个配置覆盖函数,可以从同一个超参数的多个值中创建一个置换配置列表。例如,如果想研究不同学习率值对训练性能的影响,只需在配置中输入多个不同值的列表,就可以创建并返回多个配置字典的列表,这些字典又可以用于网格训练。
实验队列和网格训练
当我们开始使用神圣的,它非常侧重于运行单一的实验。已经有可能仅仅将一次运行排队而不是立即开始,但是这意味着为每次这样的运行输入不同的配置。有了 config.py 脚本,我们就可以扩展 run.py 来使用不同配置的列表,并在数据库中自动创建一个队列。每次训练运行都有专用 GPU 访问的多线程训练循环使我们有可能创建一个大型网格训练,并让它自动运行,而不再需要任何人工监督。
最后但并非最不重要的是,我们决定编写一些自定义回调来扩展神圣的日志功能。此时,我们的项目结构看起来是这样的:
docker/
├── Dockerfile
├── .dockerignore
└── main.pysrc/
├── train.py
├── inference.py
├── config.py
├── data_processing/
│ └── data_loader.py
├── utils/
│ └── ...
├── models/
│ └── model.py
└── visualization/
└── explore.ipynb.gitignore
README.md
requirements.txt
run.py
正如您所看到的,docker 部署文件夹也潜入其中。将所有代码整齐地分离在单独的脚本中,可以很容易地将其重用到 Docker 部署等任务中——事实上,也可以重用到任何部署中。
我们如何保证代码和结果的质量?
有了神圣的地方,我们现在有了一个清晰的项目结构,代码风格指南,和一个实验管理系统。然而我们仍然缺少的是一些非常基本的东西——持续的测试。
每当我阅读关于 ML 的文章时,通常是由具有 Python 背景的人撰写的,我注意到尽管有大量关于数据处理或神经网络微调的信息,但代码质量很少成为问题。如果你在一个纯科学的环境中工作,并且大部分只是为你自己编码,这是没问题的。对我们来说,编写代码并希望通过手工测试得到最好的结果是远远不够的。
因此,我们向我们的新项目模板添加了另一个部分——测试。我们决定使用经典的 Python 包 unittest 来测试你的代码。然后,我们开始编写测试。
为了让我们的生活更容易,我们使用 GitLab 持续集成(CI) 在每次提交后自动运行我们的测试。
测试 ML 项目通常比其他类型的软件开发更复杂,但是它仍然有很大的帮助!我们发现在我们的项目管道中最重要的测试是数据加载和(预处理)部分。在这里,只需将少量数据添加到存储库中,就可以自动确保无论对数据管道做了什么更改,您的中间结果仍然保持所需的范围、形状和类型。

对清晰、优美的代码进行自动测试和林挺检查
然而,如果你着眼于一个模型的训练,连续测试就成了一个挑战。大多数情况下,这是一个非常耗时的过程,人们不希望每次提交都运行这个过程。在非常敏感的浮点机制中,这也是一个高度随机的过程,我们不得不编写许多浮点精度有误差的断言。最后,我们根据一个通用的计算机科学范例将我们的测试工作划分为集成测试和单元测试。我们运行更复杂和耗时的测试,只需要为合并请求构建复杂的模型,并运行更快的单元测试,在每次提交时检查我们的数据操作。
由于我们也需要一点计算能力,我们将 GitLab runner 从公司范围的管道中分离出来,让它在我们专用的机器学习服务器上运行。
我们如何向客户传达我们的工作?

为了与我们的客户分享中间结果,我们基本上有两个策略:1-快速建立一些解释我们当前状态的图像和幻灯片,或者 2-直接使用 Jupyter 笔记本。这并不是最佳的,因为我们希望将会议的焦点放在结果上,并有一种更灵活的方式与数据交互(而不是修改代码和重新运行单元格)。将工作算法从笔记本结构转移到构成我们剩余代码结构的纯 Python 脚本也相当麻烦。所以我们寻找不同的工具。
谢天谢地,我们找到了 Streamlit,并立即对它的功能深信不疑。Streamlit 允许用最少的额外代码生成一个小的 web 应用程序。这有利于我们,原因如下:
- 所有人需要做的就是编写纯 Python 文件→这巧妙地集成到我们的项目模板结构中
- 演示与代码分离,这样我们就可以在客户会议上专注于数据和图表
- 创建的 HTML 页面易于呈现,并允许像按钮、选择和过滤器这样的交互式元素,使我们能够超越静态的电源点
- 从开发的角度来看,它比笔记本更容易使用,并且可以更快地将代码转移到训练程序中

资料来源:ithub.com/streamlit/streamlit
在开发周期中,由于 Streamlit 管理热代码替换的方式,它可能会变得有点慢(基本上没有),但到目前为止,我们还没有找到更好的工具来处理我们项目的这一方面。
我们最终和当前的《不扩散条约》结构现在看起来是这样的:
docker/
├── Dockerfile
├── .dockerignore
└── main.pysrc/
├── train.py
├── inference.py
├── config.py
├── data_processing/
│ └── data_loader.py
├── utils/
│ └── ...
├── models/
│ └── model.py
└── visualization/
└── explore.pytests/
├── data/
│ └── [project relevant data goes here for testing]
├── unit/
│ └── test_data_loader.py
└── integration/
└── test_model.py.gitignore
gitlab-ci.yml
README.md
requirements.txt
run.py
这一切是如何组合在一起的?
我们工作的领域正以令人难以置信的速度发展。在一个常规的软件项目中,跟踪所有移动的部分已经够难的了,但是我们发现一个机器学习项目现在还没有标准化。我们处理 ML 项目的方法使我们处于两种流行方法之间:使用计算成本较低的算法验证第一次实验的更科学的数据方面,以及具有丰富的硬件和软件资源生态系统的完全支持云的数据管道。
我们接受的框架目前最适合我们的需求,尽管这在未来的几个月和几年中(很可能)会改变,但我们对目前的选择感到满意。它们使我们的工作保持独立,并允许对每个项目采取非常个性化的方法,同时还确保灵活的数据处理和易于重用成熟的算法和例程。我们从小事做起,但我们总是努力改进我们的日常工作,使其更有效率,并改善我们与客户的沟通。也许这篇文章帮助你回答了一些关于建立端到端机器学习项目的问题,我们希望这是对我们技术栈的一个有趣的见解。
管理机器学习项目——Allegro Trains vs GitHub
Allegro Trains 是一个项目管理中心,旨在与 ML 工作流无缝集成。

Allegro Trains,ML 项目管理的人工智能基础设施。
人工智能由于计算能力的急剧增长而复活,这使得它的忠实爱好者、不经意的观众和专家等可以用仅仅二十年前还是纯粹幻想的想法进行实验。计算能力和海量数据爆炸的最大受益者(谢谢你,互联网!)正是深度学习,机器学习(ML)的子领域,任务是提取下划线特征、模式和识别猫图像。严肃地说,这项技术引领的进步在新闻媒体的宠儿中无处不在,如特斯拉的自动驾驶仪、谷歌的 AlphaGo 和脑机接口技术。虽然它们值得每一点的宣传,但它隐藏了最终产品下难以置信的困难和复杂的任务。任何敢于尝试深度学习项目的人都知道这并不容易!它需要出色的项目管理技能,几个令人沮丧的深夜和工作部件的非线性装配。如果你最后没有白头发,你会被认为是幸运的。

当前 ML 工作流程问题……
如果你不是幸运的一员,你将不得不花大量的时间在泥里粘上你的意大利面条代码,把你不可靠的分支推到 GitHub ,乞求拉请求,并合并到你可怜的起源大师那里。这个工作流程似乎是业内最被接受的规范。然而,你对你到达目的地的步骤有很好的了解吗?比方说,你被要求展示你是如何得出你提出的辉煌结论的,拉出一个流程图或一个网页来简洁地展示你每天对未知的冒险不是很好吗?如果这看起来很吸引人,让我向您介绍一个专门为 ML 项目设计的自动化项目管理系统的优秀抽象。无论你运行的是 Linux、macOS 还是 Windows,在你的电脑上设置它几乎不费吹灰之力。这个产品背后的公司(快板 AI )叫它快板火车,欢迎入伙!进来的时候请在门口出示你的开源平台会员证。
正如我前面提到的,从大型数据集提取有意义的见解的能力是 ML 中的一项关键技能。随着这种必要性而来的是对大量有用的统计和绘图库、框架和算法的无数实验的需求。这个领域的广泛共识是利用一个版本控制管理系统,比如 GitHub,这样你的实验就能在失控之前被及时跟踪。然而,社区版 GitHub 有一些限制。其中一些是:
- 它并不跟踪你的实验的每一次迭代的资源分配。
- 无论是 Jupyter Notebook/Lab 还是 PyCharm,它都不会与您选择的 IDE 集成。
- 它限制了你的代码/图形在网络上显示的数量。
GitHub 基于博弈论的引擎非常有说服力,但对其不断增长的语法的询问使其成为堆栈溢出的宠儿。

两行代码跟踪你的 ML 项目。
培训现成的解决方案
另一方面,Trains 与您的 IDE 集成,只需在您的单元格顶部添加两行代码 (TLC),如上所示。再熟悉不过的 Python 内置函数 import 访问 trains 模块,可以从 pip 安装。Task类附带了许多有用的函数,例如 init 其中跟踪您的实验,在本例中为 ETL 。与 GitHub 类似,Trains 给了你灵魂所渴望的版本控制,但没有冲突、提交问题或搜索正确语法等令人担忧的方面。你可以想象,如果你用不同的名字开始一个新的笔记本,并在 TLC 中键入一个新的项目和任务,Trains 会自动单独跟踪这些项目。如果您决定中止您的一个任务,并在 2 小时后重新启动它(或者在我的情况下,8 天,标题如下),Trains 将分别保存这两个版本,给您一个版本控制系统的动态。让我告诉你我的意思。

第一次看到你宝贵的两行代码的成果。
正如您在上面的中所看到的,* MarchMadness 项目是在三个独立的笔记本实例中创建的,其中有 3 个实验或任务: 测试 、 ETL 和 数据探索 。你可能注意到了 测试 有两个版本。这些是你的分支,你只需点击一下,就可以并排比较,更好地了解你的进展(类似于 git diff )。Trains 实际上比 GitHub 走得更远,它跟踪任务的各个版本的处理负载分布,如 CPU/GPU 使用情况、网络和 I/O 速度(见下面的),因此您可以识别 ML 代码的瓶颈,并进行更快的迭代,而无需优化每一行代码。在迁移到 AWS 和 Azure 等云计算服务之前,您也可以将这些信息作为指南。如果你想为你的实验的每一次迭代留下一个消息(类似于 git commit),那么 Trains 也能帮你回到那里*。**

ML 项目的资源管理。
培训附加功能
你可能会想‘这里有什么问题?’我同意你对世界的愤世嫉俗的看法,但我还没说完。Trains 为 ML 从业者和开发者提供了更多的茶点,而 TLC 甚至不在社区版 GitHub 的范围之内。其中的一些例子包括:
- 保存您的 ML 模型的快照,这些快照可以在云存储系统上共享。
- 显示在您的实验中使用的 python 包及其特定版本的摘要,这可以在调试时节省您大量的时间。
- 通过 web 用户界面提供控制,远程停止或监控正在本地机器上运行的实验。
最后但同样重要的是,训练版本代码本身的转换。要编写脚本的 ipynb 文件。py 文件,这样它就可以跟踪代码的实际改进,而不是您正在执行的代码。当您进行远程协作或在不同的机器上协作时,这一点非常重要,这样您的代码就可以使用脚本文件以及代码中使用的包的正确版本(类似于需求文本)来重新生成。
摘要
相对于您已经习惯的正常 GitHub 工作流程,让您体验一下 Trains 在商店中为您提供的服务是一件愉快的事情。作为开放平台会员的一部分,对于 Trains 还有很多我没有在这里探索的,等待未来的探索和发现。我鼓励你继续合作,通过使用 Trains 自动化你的项目,把你的 ML 项目带到下一个层次。我还鼓励您与开发人员和数据专业人员分享您的进展。从我个人与团队的互动中,我知道 Allegro AI 非常感谢您的持续参与和富有洞察力的反馈和建议。我鼓励你在这个频道上打开问题,你一定会得到快速响应。至于我,我有数据科学项目要离线监控,我希望在我下一次乘坐火车时赶上你,火车将专注于机器学习和深度学习探索新冠肺炎患者的胸部 X 射线和 CT 图像。直到我们再次见面,一路顺风!
为人工智能和机器学习管理 Anaconda 中的多个环境
管理多个 Anaconda 环境

照片由 Soragrit Wangsa 在 Unsplash 上拍摄
当我们适当地组织它们时,事情看起来很好。在从事数据科学项目时,我们需要在从事不同项目时管理许多技术堆栈。Anaconda 为我们提供了这种功能。Anaconda 提出了 Jupyter 笔记本,我们通常更喜欢使用 Jupyter 笔记本来完成我们的数据科学任务。任务可以是训练模型、准备数据、特征工程、绘制图表、验证模型或测试我们训练的模型。当我们在不同的机器学习和深度学习模型上工作时,那么对于特定的模型,我们需要一套库来使用。如果我们将所有的库安装在一个环境中,我们可能会遇到很多问题。
这些问题是由于所使用的库的版本或任何其他兼容性问题造成的。最值得注意的是,当我们将模型迁移到不同的环境,比如云和不同的机器上时,就很难知道我们使用了什么库来完成我们的任务。这里需要创建一个不同的 Anaconda 环境。
当我们有一个不同的 Anaconda 环境时,正确地管理它们以便在类似的项目出现时加以利用是至关重要的。在本文中,我将介绍管理 Anaconda 环境的一些要点。在这里,我假设您的机器上安装了 Anaconda。
创建您的第一个 Anaconda 环境
安装 Anaconda 后,您可以在搜索窗口中找到 Anaconda 提示符。点击它,您将看到 Anaconda 提示符。

图片来自作者
在这里,我们将创建一个名为“Python-Keras”的新环境环境的名称应该基于您的项目,以便我们以后可以使用它。
conda create -n Python-keras python=3.6
运行该命令后,您将看到下面的屏幕,在这里开始创建环境。

图片来自作者
我们的环境被创建,但是它没有安装任何库。我们可以在激活环境后安装它们。我们将在本文后面讨论。
但是,有另一种方法可以让您在创建环境的同时安装库。为此,我们需要创建 YAML 文件,而 YAML 文件包含环境和所用库的名称。

图片来自作者
现在,我们可以使用下面的命令来创建使用 YAML 文件的环境。
conda env create -f python39.yml
在这里,将使用定义库创建一个环境。
激活您的环境
创建您的环境后,如果我们想将该环境用于 Jupyter 笔记本,我们需要激活它。使用下面的命令启动该环境。

图片来自作者
我们也可以在激活环境后安装其他库。我们可以使用 PIP 来安装,也可以使用“Conda”来安装库。

图片来自作者
共享您创建的环境
激活您的环境后,我们可以共享我们的环境,以便在不同的位置或机器上使用同一个项目。使用下面的命令生成 YAML 文件。然后我们可以和其他人分享 YAML 的档案。

图片来自作者
它将在相同的命令提示符位置生成一个 YAML 文件。在这种情况下,它将保存在“C:\Users\pranj”中。
获取环境列表
完成你的任务后,为了进行不同的项目,我们切换到不同的环境。首先,我们需要检查可用的环境。同样,使用下面的命令。

图片来自作者
我创造了许多环境;我们可以使用 activate 命令切换到不同的环境。

图片来自作者
删除您的环境
当你认为你不需要任何特定的环境时,我们可以将它们从硬盘中释放出来,而不是保留它们。为此,Anaconda 提供了一个命令。
conda remove --name Python-Keras --all
要运行上面的命令,您需要通过再次打开 Anaconda 提示符来退出激活的环境。

图片来自作者
结论
如果您在数据科学领域工作,我们已经完成了一些重要的基本步骤。训练和建立数据科学模型并不耗时,但如何恰当地管理项目非常重要。如果你弄糟了这些小点,你将删除一切,并通过安装 python 从头开始。因为如果模型中有一些问题,我们可以通过检查代码来修复它,但是如果错误在技术堆栈中,就变得更难修复了。
希望你喜欢这篇文章,会在其他地方看到你。在那之前,继续享受数据科学吧。
使用 Conda 管理您的数据科学项目环境
为眼光敏锐的数据科学家提供的一组最小的“最佳实践”。

有眼光的数据科学家的环境和包管理器。来源:https://docs.conda.io/en/latest/
Conda“最佳实践”
在这篇文章中,我详细介绍了使用 Conda 管理我在自己的数据科学工作中使用的特定于项目的环境的“最佳实践”的最小集合。本文假设您对 Conda 有基本的了解,并重点介绍了使用 Conda 管理数据科学项目环境的一小组“最佳实践”。如果你没听说过康达或者刚开始使用康达,那么我推荐你看一下 康达 入门。
TLDR;
下面是使用 Conda 管理特定项目软件堆栈的基本方法。
(base) $ mkdir project-dir
(base) $ cd project-dir
(base) $ nano environment.yml # create the environment file
(base) $ conda env create --prefix ./env --file environment.yml
(base) $ conda activate ./env # activate the environment
(/path/to/env) $ nano environment.yml # forgot to add some deps
(/path/to/env) $ conda env update --prefix ./env --file environment.yml --prune # update the environment
(/path/to/env) $ conda deactivate # done working on project (for now!)
新项目,新目录
每一个新项目(不管多小!)应该存在于自己的目录中。开始组织你的项目目录的一个好的参考是科学计算的足够好的实践。
mkdir project-dir
cd project-dir
新项目,新环境
现在您已经有了一个新的项目目录,您可以为您的项目创建一个新的环境了。我们将分两步进行。
- 创建一个描述软件依赖关系的环境文件(包括具体的版本号!)对于项目来说。
- 使用新创建的环境文件来构建软件环境。
这里是一个典型环境文件的示例,可用于运行使用 PyTorch 开发的深度学习模型的 GPU 加速、分布式训练。
name: nullchannels:
- pytorch
- conda-forge
- defaultsdependencies:
- cudatoolkit=10.1
- jupyterlab=1.2
- pip=20.0
- python=3.7
- pytorch=1.5
- tensorboard=2.1
- torchvision=0.6
- torchtext=0.6
一旦在项目目录中创建了一个environment.yml文件,就可以使用下面的命令在项目目录中创建一个名为env的子目录。
conda env create --prefix ./env --file environment.yml
激活环境
激活环境对于让环境中的软件工作良好(或者有时根本不工作)是必不可少的!).环境的激活做两件事。
- 为环境向
PATH添加条目。 - 运行环境可能包含的任何激活脚本。
第 2 步尤其重要,因为激活脚本是包如何设置它们运行所需的任意环境变量的。
conda activate ./env # activate the environment
(/path/to/env) $ # prompt indicates which environment is active!
更新环境
您不太可能提前知道哪些包(和版本号!)你将需要用于你的研究项目。例如,情况可能是…
- 您的一个核心依赖项刚刚发布了一个新版本(依赖项版本号更新)。
- 您需要一个用于数据分析的附加包(添加一个新的依赖项)。
- 您已经找到了一个更好的可视化包,不再需要旧的可视化包(添加新的依赖项并删除旧的依赖项)。
如果在您的研究项目过程中出现这些情况,您需要做的就是相应地更新您的environment.yml文件的内容,然后运行下面的命令。
conda env update --prefix ./env --file environment.yml --prune
或者,您可以使用以下命令从头开始简单地重建环境。
conda env create --prefix ./env --file environment.yml --force
除非从头开始构建环境需要大量的时间(这应该非常罕见!)当我添加(或删除)依赖项时,我几乎总是从头开始重建我的环境。
停用环境
当您完成项目时,最好停用当前环境。要停用当前激活的环境,使用如下的deactivate命令。
conda deactivate # done working on project (for now!)
(base) $ # now you are back to the base environment
有兴趣了解更多信息吗?
有关使用 Conda 为您的数据科学项目管理软件堆栈的更多详细信息,请查看我为Carpentries 孵化器撰写的Conda(数据)科学家简介培训材料。这些课程材料正在积极开发中,因此请随时提出问题或提交 PRs!
Conda 入门
只是最基本的。康达是什么?为什么要用康达?康达怎么安装?
康达是什么?
Conda 是一个运行在 Windows、Mac OS 和 Linux 上的开源包和环境管理系统。
- Conda 可以快速安装、运行和更新软件包和相关的依赖项。
- Conda 可以在您的本地计算机上创建、保存、加载和切换项目特定的软件环境。
- 虽然 Conda 是为 Python 程序创建的,但 Conda 可以为任何语言如 R、Ruby、Lua、Scala、Java、JavaScript、C、C++、FORTRAN 打包和分发软件。
康达作为一个软件包管理器帮助你找到并安装软件包。如果你需要一个需要不同版本 Python 的包,你不需要切换到不同的环境管理器,因为 Conda 也是一个环境管理器。只需几个命令,您就可以建立一个完全独立的环境来运行不同版本的 Python,同时在您的正常环境中继续运行您常用的 Python 版本。
康达 vs 迷你康达 vs 蟒蛇
用户经常混淆 Conda、 Miniconda 和 Anaconda 之间的区别。 Planemo 文档有一个极好的图表,很好地展示了 Conda 环境和包管理工具与 Miniconda 和 Anaconda Python 发行版之间的区别(注意,Anaconda Python 发行版现在有超过 150 个额外的包!).

资料来源:计划办公室文件
我建议安装 Miniconda,它结合了 conda 和 Python 3(以及少量核心系统包),而不是完整的 Anaconda 发行版。只安装 Miniconda 会鼓励你为每个项目创建单独的环境(并且只安装那些你实际需要的包!)这将增强您的研究和工作流程的可移植性和可重复性。
此外,如果你真的想要一个完整的 Anaconda 发行版的特定版本,你总是可以创建一个新的conda环境并使用下面的命令安装它
。
conda create --name anaconda-2020-02 anaconda=2020.02
为什么要用康达?
在众多不同的软件包和环境管理系统中,Conda 是少数几个明确针对数据科学家的系统之一。
- Conda 提供预构建的包或二进制文件(这通常避免了从源代码编译包的需要)。 TensorFlow 是数据科学家广泛使用的工具的一个例子,它很难安装源代码(特别是在 GPU 支持下),但可以使用 Conda 一步安装。
- Conda 是跨平台的,支持 Windows、MacOS、GNU/Linux,支持多种硬件平台,比如 x86 和 Power 8、9。在后续的博文中,我将展示如何让您的 Conda 环境在这些不同的平台上重现。
- 如果一个库或工具还没有使用
conda打包安装,Conda 允许在 Conda 环境中使用其他包管理工具(比如pip)。
使用 Conda,您可以快速安装常用的数据科学库和工具,如 R 、 NumPy 、 SciPy 、 Scikit-learn 、 Dask 、 TensorFlow 、 PyTorch 、 Fast.ai 、 NVIDIA RAPIDS ,以及更多使用优化的硬件专用库构建的库
如何安装 Miniconda?
从下载适用于您的操作系统的 64 位 Python 3 版本的【Miniconda 安装程序,并按照说明进行操作。我将在下面介绍在 Linux 系统上安装的步骤,因为在 Linux 系统上安装稍微复杂一些。
下载 Miniconda 的 64 位 Python 3 安装脚本。
wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
运行 Miniconda 安装脚本。
bash Miniconda3-latest-Linux-x86_64.sh
该脚本将显示几个提示,允许您定制 Miniconda 安装。我通常建议您接受默认设置。但是,当出现以下提示时…
Do you wish the installer to initialize Miniconda3
by running conda init?
…我建议您键入yes(而不是默认的no),以避免以后不得不为 Bash 手动初始化 Conda。如果你不小心接受了默认,不用担心。当脚本完成时,您只需要输入以下命令。
conda init bash
source ~/.bashrc
安装脚本完成后,您可以删除它。
rm Miniconda3-latest-Linux-x86_64.sh
为 Conda
初始化您的 shell 安装 Miniconda 后,接下来您需要将您的首选 shell 配置为“Conda 感知”。运行安装脚本时,可能会提示您为 shell 初始化 Conda。如果是这样,那么您可以安全地跳过这一步。
conda init bash
source ~/.bashrc
(base) $ # prompt indicates that the base environment is active!
更新 Conda
最好将 Conda 安装更新到最新的
版本。以下命令会将 Conda 更新到最新版本。
conda update --name base conda --yes
卸载 Miniconda
每当安装新软件时,了解如何卸载该软件总是一个好主意(以防你有第二个想法!).卸载 Miniconda 相当简单。
取消 shell 初始化,从~/.bashrc中删除 Conda 相关内容。
conda init --reverse bash
删除整个~/miniconda3目录。
rm -rf ~/miniconda3
删除整个~/.conda目录。
rm -rf ~/.conda
如果存在,删除 Conda 配置文件。
if [ -f ~/.condarc ] && rm ~/.condarc
接下来去哪里?
现在,您已经安装了 Conda 环境和包管理工具,可以开始学习使用 Conda 管理数据科学项目环境的“最佳实践”了。在我的下一篇文章中,我将介绍我认为可靠的、最小的“最佳实践”集,当您开始下一个数据科学项目时,您可以采用这些最佳实践来充分利用 Conda。
利用蒙特卡罗模拟管理项目不确定性

在 Unsplash 上由 Helloquence 拍摄的照片
几乎每个项目经理都经历过错过项目最后期限的情况。错过项目期限的一个常见原因是对成本或任务持续时间的估计。大多数经理认为估算(成本或任务持续时间)是确定性的,因此没有认识到估算是概率性的。他们使用单点估计,并有一个错误的概念,即未来可以准确预测。预测项目结果的更好方法是使用蒙特卡罗模拟来进行项目风险的定量分析。
蒙特卡洛模拟是什么?

蒙特卡洛模拟是约翰·冯·诺依曼和斯坦尼斯劳·乌拉姆为曼哈顿计划开发的一种数学技术。它以蒙特卡洛赌场命名,斯坦尼斯劳·乌兰的叔叔经常在那里赌博。
它告诉你两件事:
- 所有可能或将要发生的事件。
- 每种可能结果的概率。
举例说明其工作原理
如果我们想要找到得到 21 点的概率,我们可以简单地计算在这种情况下可能的手牌数量,然后除以牌的可能组合的总数来得到概率(如果你好奇的话,大约是 1/21)。但是现在想象一下,我们的样本空间很难计算,例如,我们的一副牌有数千张,而不是只有 52 张,或者更好的是,我们甚至不知道有多少张牌。还有一种方法可以求出这个概率。

我们可以玩一百个游戏,一边玩一边记录结果。我们可能得到 20 次、40 次甚至 50 次 21 点,并使用这些值中的任何一个来分配概率。这似乎是一个很糟糕的方法来评估我们在赌场的赔率,但希望,我们只是玩得开心。如果我们再来一次,玩一千次,一万次,几百万次,大数定律说:
“随着同分布、随机生成变量的数量增加,它们的样本 均值 (平均值)接近它们的理论均值。”
除了是统计学最重要的定律之一,这也是蒙特卡罗模拟的基础,允许我们通过统计试验的方法建立随机模型。
项目规划中的蒙特卡罗模拟

假设您有三项活动,估计如下(以月为单位):

从上表可以推断,根据 PERT 的估计,这三项活动将在 17.5 个月内完成。不过,最好的情况下,16 个月就能完成,最坏的情况下,21 个月就能完成。
现在,如果我们对这些任务运行蒙特卡罗模拟五百次,它将显示如下结果:

从上表可以看出,有一个:
- 2%的机会在 16 个月内完成项目
- 8%的机会在 17 个月内完成项目
- 55%的机会在 18 个月内完成项目
- 70%的机会在 19 个月内完成项目
- 95%的机会在 20 个月内完成项目
- 100%的机会在 21 个月内完成项目
如您所见,这种方法为您提供了更深入的数据分析,有助于您做出更明智的决策。
蒙特卡罗模拟中的建模不确定性
Mario Vanhoucke 博士在他的书《数据驱动的项目经理》中,提出了以下案例来对任何项目的活动进行统计建模:


- 如果活动没有风险,我们可以相信来自专家判断的单点评估。您可以用最可能的估计值来模拟活动。
- 如果活动具有低风险——估计相当精确,除了由于随机因素导致的意外变化——您可以使用不对称β或三角形。
- 如果活动具有已知的风险——差异的原因是众所周知的,并且项目管理团队知道如果原因发生,活动将会提前或推迟——那么您可以使用不对称* beta 或三角形。*
- 如果活动具有未知风险——项目经理不具备产生可靠评估的适当知识——您可以设置一系列可能的值,并将活动建模为均匀分布。
- 如果活动是一个 黑天鹅——超出预期的情况,概率很低,影响很大——你可以把它们当做假设来管理。关于蒙特卡罗的分析,你可以把它们建模为无风险活动。
这本书使用了一个网球场馆建设项目的案例研究。请参见下表中的活动持续时间估计值。

为了考虑风险,活动用三个点建模:乐观、悲观和最有可能。为了选择统计分布的类型,我们必须考虑活动的定性风险分析:
- 对称三角形或贝塔,如果活动概率低
- 不对称三角形或贝塔,如果活动具有中等概率
- 如果活动具有高概率,则是一致的
蒙特卡罗模拟工具
Oracle 的 Crystal Ball、PALISADE 的@ Risk、Sim Tools 是在 Excel 电子表格和模型中执行蒙特卡洛模拟的几种流行工具。这些工具模拟了数千个不同的“假设”案例,将每个计算的输入和结果保存为单独的场景。输出揭示了可能结果的范围及其发生的概率。
Microsoft Excel 提供统计函数来执行蒙特卡罗模拟。
结论
蒙特卡洛模拟是一种数据驱动的方法,用于量化风险、了解项目风险、预测结果。在您的项目中使用蒙特卡罗分析的好处是:
- 它提供了对您满足项目里程碑和最后期限的可能性的早期识别。
- 它创建了一个更现实的预算和时间表。
- 预测进度和成本超支的可能性。
- 量化风险以更好地评估影响。
- 它为决策提供客观数据。
管理数据科学项目的软件依赖性
保持项目依赖关系清晰和可重复的分步指南。

Emile Perron 在 Unsplash 上的照片
开发软件项目时,虚拟环境是的必备条件。它们允许您创建独立的 Python 安装,防止您的项目相互冲突,并让其他人复制您的设置。
然而,使用虚拟环境只是开发可重复数据项目的第一步。这篇文章讨论了另一个重要的主题:依赖性管理,它涉及到正确地记录虚拟环境,以简化可再现性,并使它们在部署到生产环境时变得可靠。
关于 Python 环境的更深入的描述,参见另一篇文章。
依赖性管理器如何工作
TL;dr;软件包管理器使用试探法来安装相互兼容的软件包版本。大量的依赖项和版本约束可能会导致解析环境时失败。
当您安装一个软件包时,您的软件包管理器(pip,conda)必须安装所请求的软件包的依赖项以及这些依赖项的依赖项,直到所有要求都得到满足。
包通常有版本约束。例如,在编写时,scikit-learn 需要 numpy 1.13.3 或更高版本。当包共享依赖关系时,包管理器必须找到满足所有约束的版本(这个过程被称为依赖关系解析),这样做在计算上是很昂贵的,当前的包管理器使用试探法在合理的时间内找到解决方案。
对于大量的依赖项,规划求解可能无法找到解决方案。一些包管理器会抛出一个错误,但是其他的可能只是打印一个警告消息。为了避免这些问题,了解项目的依赖性是很重要的。
开发和生产依赖关系
TL;dr;对开发(即训练模型所需的包)和生产(即进行预测所需的包)中的依赖项进行分组。
在从事数据科学项目时,可能会有一些只在开发时需要的包,但在生产环境中并不需要。例如,如果您正在开发一个模型,您可能会使用 matplotlib 在 jupyter 笔记本中生成一些评估图表,但是对于通过 API 提供预测,您不需要这些。
这使您有机会简化生产环境中的依赖关系。下一节将讨论如何做到这一点。
维护依赖文件
TL;dr;为开发/生产依赖项保留单独的文件。手动添加/删除包,并尽可能保持它们的灵活性(通过不固定特定版本),以简化依赖关系解析,并根据可用的最新兼容版本测试您的项目。
pip和conda是 Python 使用最广泛的包管理器;两者都可以从文本文件中设置依赖关系。我推荐使用conda(通过 miniconda ),因为它可以处理比pip更多的依赖。你甚至可以安装非 Python 包,比如 R 。如果有你不能使用conda install安装的包,你仍然可以在 conda 环境中使用pip install。
在conda中,您可以在 YAML 文件中记录您的依赖关系,如下所示:
虽然您可以自动生成这些文件,但最好手动维护它们。一个很好的做法就是加上一个简短的评论,让其他人知道(甚至是你未来的自己!)为什么需要套餐。在开发过程中,我们可能会试验一些包,但很快就将其丢弃,最好的方法是将其从环境文件中删除,但如果您忘记这样做,注释将有助于您将来决定丢弃哪些依赖项。
保持依赖关系的灵活性,并在必要时只固定特定的版本,添加到环境中的版本约束越多,遇到求解程序无法满足所有约束的可能性就越大。
安装依赖关系
TL;dr;在设置环境时总是寻找错误,有时您可能需要固定版本来解决问题。
一旦指定创建环境文件,就可以使用以下命令创建 conda 虚拟环境:
如果您有一组合理的依赖项,您的环境应该安装得很好,但是有一些因素可能会给出错误/警告。始终检查命令输出是否有问题。根据求解程序的配置,该命令可能会拒绝创建环境或打印警告消息。
我提到解决者试图找到满足所有包需求的解决方案,但这是在假设包维护者拥有最新需求的情况下。假设包 X 依赖于包 Y,但 X 没有为 Y 设置任何版本约束。新版本的 Y 发布后会破坏 X。下一次安装 X 时,如果求解器安装了不兼容版本的 Y,则会导致安装失败(从求解器的角度来看,这不是问题,因为 X 没有为 Y 设置任何约束)。这些情况很难调试,因为您必须通过反复试验找到一个工作版本,然后将正确的版本固定在依赖文件中。
不从头测试环境设置的时间越长,破坏环境设置的风险就越大。因此,持续测试依赖文件是很重要的。
测试您的开发环境
TL;dr;在最近创建的环境中连续运行您的项目测试,以检测由于包更新引起的中断。
因为你的开发包没有固定到一个特定的版本,包管理器将尝试安装最新的兼容版本,这从开发的角度来看是好的,因为包得到了改进:新的特性,错误修复和/或安全补丁,保持你的依赖关系更新是一个好主意;但它们也可能带来突破性的变化。要检测它们,请确保您在一个新的、最近安装的环境中运行项目的测试。流程如下:
- 从干净的虚拟环境开始
- 安装依赖关系文件的依赖关系
- 配置您的项目
- 运行测试
最好是,在每次修改源代码时自动运行这个过程(这被称为持续集成)。如果这不是一个选项,定期手动运行上述步骤。
自动化项目设置和测试
TL;dr;使用 nox 和 pytest 在一个全新的环境中运行您的测试,打包您的项目,这样您就可以轻松地在您的测试中导入项目的模块
我发现的自动化环境设置和测试执行的最佳工具是 nox 和 pytest 。
Nox 是一个 Python 包,可以自动创建 conda 环境,然后在该环境中运行您的测试:
注意:在撰写本文时,nox(版本 2020.8.22)并不正式支持从 environment.yml 文件安装,但这种变通方法可以做到这一点, 单击此处 了解更多信息。
一旦您的环境准备好了,就包含启动测试套件的命令。我建议您使用 pytest,下面是一个测试文件的样子:
要执行上面文件中的测试,您只需在 nox 中运行pytest,这转化为添加:session.run('pytest')
到目前为止,我们已经完成了步骤 1、2 和 4。但是跳过了 3(配置项目)。正如您在前面的代码片段中看到的,为了测试您的代码,您必须使它可导入,最干净的方法是打包您的项目(要查看我们关于项目打包的帖子,单击此处)。
一旦你打包了你的项目,你就可以用pip install path/to/project来设置它。
测试您的开发和生产环境
TL;dr;开发单独的测试套件,您可以在一个具有开发依赖关系的环境中测试您的开发管道,并为 API 提供生产依赖关系。
您可以使用 nox 分别测试您的开发和生产环境。下面是一些示例代码:
要运行您的测试,只需在终端中执行nox。
锁定文件
TL;dr;提供自动生成的锁文件,其中包含带有固定版本的开发/生产依赖项列表,以避免将来由于 API 更改而中断您的项目。
如果不固定特定的版本,就无法知道求解器将安装的确切版本集,这对于开发目的来说很好,因为它给了您尝试新版本并检查是否可以升级它们的机会,但是您不希望在生产环境中出现这种不确定性。
解决这个问题的方法是提供另一个文件,该文件列出了所有的依赖项,但包括特定的版本,这被称为锁文件。这样,您的环境将始终解析为同一组版本。
您可以使用以下命令生成具有固定依赖关系的文件:
输出文件如下所示:
锁文件对于保证生产中的确定性环境非常重要,请确保从您已经测试过的环境中生成它们。例如,您可以在测试会话结束时添加conda env export命令:
除了固定版本之外,锁文件通常还提供其他功能,例如对每个包进行哈希处理,并将其与下载版本进行比较,以防止安装被篡改的软件。在撰写本文时,有一个名为 conda-lock 的新项目,旨在改进对 conda 锁文件的支持。
闭幕词
在你的项目中使用虚拟环境是开发更健壮的管道的第一步,但这并不是结束。将依赖项安装作为测试过程的一部分,保持较小的依赖项,将生产依赖项与开发依赖项分开,并提供锁文件,这些都是确保您的项目具有健壮设置的必要步骤。
最初发布于http://ploomber . io
管理洪水
理解关于机器学习的谷歌搜索

任何试图了解机器学习主题的人,无论是该领域的新人还是寻找最新新闻的专家,都已经开始用谷歌进行搜索。这并不奇怪——在一个变化如此迅速的领域,谷歌拥有点击鼠标就能找到难以置信的资源的神奇力量。然而,不幸的是,谷歌也能搜出许多过时的、写得不好的或错误的信息。如何理解你发现的东西,你应该依靠什么?在这篇小笔记中,首先是为学生写的,我看看谷歌的网络在搜索机器学习时捕捉到了什么,什么应该保留,什么应该丢弃。
第一种要注意的参考资料是书籍。是的,它们是过时的,它们可能很贵,而且它们通常落后前沿几年,但是由真正的专家精心编写的书是一件珍贵的事情。在这个领域,有几本书一直被引用;作为原始资料,我将它们视为我的黄金标准:
- 模式识别和机器学习作者克里斯多夫·毕晓普。现在 10 岁了,这本书涵盖了机器学习的各种方法,大部分是从贝叶斯的角度。这本书在讨论许多算法的数学和统计基础方面做得很好,并且有很多练习(有些非常难!)揭示了细节。
- 统计学习的要素 by Hastie 、 Tibshirani 和 Friedman 。这本书也是免费的,作者是斯坦福的三位统计学家,他们开创了统计学习中一些最广泛使用的技术。我发现这本书很适合毕晓普;它不太强调贝叶斯观点,但同样具有权威性——而且它还有许多练习,有些非常难!
- 贝叶斯数据分析,第三版,作者:Gelman,Carlin,Stern,Dunson,Vehtari 和 Rubin。这是一本关于应用贝叶斯统计的权威书籍。严格地说,这可能不是一本关于“机器学习”的书,但它是学习数据分析的贝叶斯观点的无价资源——这是一种在机器学习算法的开发中广泛存在的观点。据我所知,这本书不能在网上买到。
最后,如果没有奥莱利图书馆,任何从事计算机相关领域工作的人都无法长久生存。如果我想学习一门新的语言,获得一个重要工具的介绍,或者提高我在某个特定领域的编程技能,那就是我要去的地方。当我打这封信的时候,我可以看到我头顶上的书架上有五六本奥莱利的书。我很幸运在一所大学,它的图书馆订阅了奥雷利图书馆,所以我可以访问他们的整个目录。如果你没有那么幸运,你可能不得不真的购买这些书,或者支付订阅费,以获得全部的目录。
接下来,我们有从期刊或会议记录中发表的学术文章。在谷歌搜索中,这类文章通常会被标注为会议或期刊——例如,当我在谷歌上搜索“tsne 论文”时,第一个匹配项是最初的 van der Maaten 论文,它被标注为文章首次出现的“机器学习研究期刊”。
在学术界,发表在同行评审期刊或会议记录上的学术文章被认为具有该专业认可的印记。一般来说,这类出版物非常精炼,技术性很强,但它们比书籍更具时代感,有时会提供别处没有的细节。不幸的是,有如此多的期刊和会议,出版并不总是质量的可靠指标。记下出版物出现的地方是很重要的。
例如,神经网络中的一个首次会议是 NIPS (神经信息处理系统)。Krizhevsky、Suskever 和 Hinton 的论文ImageNet class ification with Deep convolutionary Neural Networks展示了训练巨大的神经网络进行大规模图像分类的可行性,该论文发表在 2012 年的 NIPS proceedings 上。这篇论文在 google scholar 上被引用了 55500 次,自发表以来大约每年 7000 次。这告诉你这项工作的影响力有多大,但也有点令人担忧——在过去 8 年中引用它的其他 55500 篇论文是什么?能都值得一读吗?
该领域的另一个重要期刊是《机器学习研究期刊。JMLR 在 2008 年发表了用 t-SNE 可视化数据;从那以后,那篇论文“只”被引用了 11500 次。
还有许多其他优秀的期刊和会议记录;例如,计算机科学领域的 STOC 和 FOCS 会议,以及主要专业协会(如 IEEE、美国统计协会和美国数学协会)出版的期刊。而且重要的作品也可以在相对不起眼的地方发表。所以不要势利,仅仅因为某个东西在哪里出版就排除它;但是请记住,仅仅因为一些东西被发表并不意味着它是有趣的,甚至是正确的。
在谷歌搜索中出现的下一个地方是arxiv。arxiv 是一个预印本服务器。这意味着科学领域的工作人员可以在 arxiv 服务器上发布他们的工作,然后才能在期刊或会议上发表,因为接受的审查过程可能需要很长时间。arxiv 非常流行,几乎每一篇重要的论文在正式出版之前都会出现在那里。然而,在那里张贴东西的障碍很低,而且有大量的材料。例如,搜索神经网络会在两天内发现大约 75 篇新文章,所以很容易被埋没。
在这三个更正式的渠道——书籍、期刊、会议和预印本——之后,是文学生态系统中更非正式的部分。这包含了博客文章、教程和自己发表的文章。这份说明就是这样一份非正式文件;媒介主持许多这样的活动。在媒介本身内部是拥有自己品牌的次级整合商,例如 TowardsDataScience 。以这种格式出现的文章可能非常有用;例如,它们可能包括关于特定任务的非常实用的、一步一步的说明。我发现这篇关于 python 可视化工具 Bokeh 的文章非常有帮助,而且写得非常清楚,我很感谢它的作者投入了大量的时间和精力。我还看到过其他一些文章,说得委婉一点,写得不太好,也不太有用。
搜索中出现的非正式生态系统的一个重要部分是来自大学课程的课程笔记。其中一些是纯金的——例如,著名的斯坦福 CS229 课程的笔记被贴了出来,包括几年前学生为那门课程完成的项目的样本。
我们快完成了。在你的谷歌搜索中,你会发现另外两件事可能会帮助你了解你正在努力学习的东西。第一个可能是显而易见的——代码及其文档。在这里,GitHub 和其他库是给社区的一份大礼,因为您不仅可以直接访问 tensorflow、keras、pytorch、scikit-learn、R 等重要工具的详细文档和教程,而且您甚至可以阅读代码来了解这些重要工具是如何工作的。
举个具体的例子,有一次我想学习如何从 twitter 上抓取数据。我谷歌了一下“抓取 twitter 数据 python”,找到了博文[如何从 Twitter](https://towardsdatascience.com/how-to-scrape-t\ weets-from-twitter-59287e20f0f1) 抓取推文。这反过来又把我引向了包 Tweepy,,在那里我可以阅读文档,也可以查看 tweepy github 库来查看源代码。
最后,还有mooc。Coursera 和 Udemy 是 MOOC 的两大提供商;它们是很好的例子,因为它们的运作方式不同。Coursera 课程是与大学共同开发的,通常由教师授课。Udemy 更多的是一个市场,托管别人写的课程;当人们注册一门课程时,作者可以从 Udemy 收集的钱中得到一份。底线是,这些 MOOCS 中有一些非常优秀——我通过 Coursera 完成了吴恩达的神经网络序列,非常棒——但也有一些不是;它们的价格相差很大;它们也不适合用来学习最初让你开始谷歌之旅的那件事。
我想差不多就这些了。我希望这篇关于“googlable”文献的综述对你下次试图找到你所参与的任何项目都需要的信息有所帮助。寻找快乐!
不确定性量化解释
进行基于模型的可靠预测的实践

(图片由作者提供)
通过赋予工程师再现详细自然过程的能力,计算机模拟正在改变工业工程实践的设计、分析和制造。尽管取得了巨大的成功,但有一个问题一直困扰着分析师和决策者:
这些模拟到底有多好?
不确定性量化,它融合了概率、统计、计算数学和学科科学,为回答这个问题提供了一个有希望的框架,并在最近几年获得了巨大的发展势头。在本文中,我们将讨论不确定性量化的以下方面:
- 动机:不确定性来自哪里,为什么它们很重要?
- 解决方案:V&V 和 IPAC 管理框架
- 挑战是:在实践中实施起来有多难?机器学习能有什么帮助?
所以让我们开始吧!
目录
1。计算机模拟中的不确定性
∘ 输入数据
∘ 模型形式
∘ 数值
2。不确定性量化框架
∘ 2.1 验证&验证框架
∘ 2.2 IPAC 框架
∘ 2.3 IPAC 在实践中:新冠肺炎疫情建模
∘ 2.4 不确定性量化是一个迭代的过程
3 .应用不确定性量化的挑战
4。未来的不确定性量化
5。重点外带
延伸阅读
关于作者
1.计算机模拟中的不确定性
从预测海平面上升到设计下一代火箭发动机,计算模型在描述这些复杂自然过程的行为方面发挥了至关重要的作用,并产生了指导决策的宝贵见解。在许多情况下,计算模型表现为一组数学方程(例如,偏微分方程)。然而,在相当长的时间里,这些方程只能模拟少数简单的学术问题,因此在帮助人们定量理解现实方面价值有限。从 20 世纪中期开始,由于数值算法和强大的计算机的快速发展,这种情况得到了显著改善。
以航空工业为例,现在工程师们普遍采用计算流体动力学(CFD)模拟器来优化飞机形状,采用计算结构动力学(CSD)模拟器来确定飞机机翼在湍流中的强度,以及采用计算气动声学(CAA)模拟器来预测喷气噪声水平。这种模拟驱动的产品开发的最终结果是什么?快速的产品原型,减少昂贵的物理实验,并缩短上市时间。
尽管花哨的后处理模拟结果在视觉上很吸引人,但它们不足以说服持怀疑态度的决策者:
- 如果一个结构模拟告诉我这座桥可以挡风,我应该批准建筑计划吗?
- 如果空气动力学模拟告诉我,发动机在雨天仍能产生足够的推力,我应该批准在洲际飞行的飞机上安装这个发动机吗?
- 如果天气模拟告诉我,飓风只会对 A 地区产生影响,我是否也应该疏散 B 地区的邻居?
显然,当生命受到威胁时,决策者会期望计算机模拟准确可靠,而不仅仅是一堆彩色的情节和动画。
事实上,决策者完全有权利怀疑模拟,仅仅是因为在计算机模拟中有许多不确定性的来源。三个主要问题如下:
输入数据
- 几何形状不确定性:由制造公差、进行模拟时简化的几何形状等引起;
- 模型参数不确定性:例如,当模拟心血管系统时,我们需要血管的弹性参数。显然,这些参数在不同的患者之间是不同的;
- 边界条件不确定性:例如,由于风和海浪的随机性质,施加在海上石油平台上的外部作用力具有高度不确定性,从而使其结构稳定性的预测变得复杂。
- 初始条件不确定性:例如,需要初始天气状态来预测飓风的轨迹。然而,由于有限的观测(卫星、气象气球等)和有限的测量精度,只能部分地推断正在形成的飓风的初始状态。
模型形式
也被称为模型偏差或差异,因为计算机试图模拟的数学模型,在一天结束时,只是对真正的底层物理的近似。有时,这种近似仅仅是因为我们缺乏知识,其他时候是因为我们有限的计算预算(例如,我们只能进行 2D 模拟,而不是真实世界的 3D 模拟)。
数字
这种不确定性来源与用于模拟数学模型的代码的准确性直接相关。离散化误差、迭代误差、舍入误差以及编码错误都会导致数值不确定性。
在这些不确定性中,有些是偶然不确定性,这是由于固有的变化或随机性而产生的。其中一些是认知上的不确定性,这是由于缺乏知识而产生的。换句话说,如果获得了足够的知识(通过实验、更高保真的求解器等)。)那么就可以减少不确定性。不管它们的类型如何,它们共有的一个共同特征是它们都可以使模拟结果偏离真实的底层物理过程。因此,难怪
"计算结果没有人相信,除了写代码的人."
2.不确定性量化框架
由于我们无法避免不确定性,我们需要量化它们,当我们
- 校准我们的计算模型
- 使用校准模型进行预测。
验证和确认(V&V)框架适用于第一种情况,而Iidentify-Propa cate-Aanalysis-Ccontrol(IPAC)四步管理程序适用于第二种情况。
2.1 验证和确认框架
V&V 框架旨在评估计算模型的可信度和质量。它包含两个部分:
验证:我们解方程对吗?
验证量化了使用代码求解数学模型时产生的与数值误差相关的不确定性。这在很大程度上是计算机科学和数学的练习,通常涉及模拟代码与相应的精确解析解的比较。
验证:我们正在解正确的方程吗?
验证解决了模型的不确定性。这在很大程度上是一个物理和工程的练习,它通常涉及模拟结果与实验测量的比较。
2.2 IPAC 框架
在了解了我们的计算模型的可信度之后,下一步将是使用我们的模型进行预测。为了有效管理这一过程中的不确定性,识别-传播-分析-控制框架通常被证明是有效的。
识别
该步骤旨在描述输入数据不确定性的各种来源:
- 对于随机不确定性,采用联合概率密度函数来描述不确定性参数的分布;
- 对于认知不确定性,概率箱、证据理论或模糊理论都是反映知识缺乏的有效方法。
贝叶斯统计在这里发挥了很大的作用。由于概率代表了贝叶斯范式中的信任程度,贝叶斯分析可以很容易地处理随机和认知的不确定性。
生生不息
这一步也被称为正向不确定性传播。它通过运行模拟将所有输入数据的不确定性以及 V & V 程序中量化的不确定性传播到感兴趣的输出。我们的兴趣可能是评估输出的变化,或者输出超过特定阈值的概率。后一种方法在风险管理中被广泛采用,在风险管理中,确定不期望的系统性能(例如,结构故障、系统不稳定等)的风险。)是首要目标。
蒙特卡罗方法提供了一种传播不确定性的直接方法。通过简单地向模拟代码提供不确定参数的不同实现,我们可以获得模拟结果的集合,从中我们可以构建直方图并提取相关的统计指标。
通常采用普通蒙特卡罗方法的方差减少变体。这包括拉丁超立方体抽样、拟蒙特卡罗抽样、重要性抽样、子集抽样等。此外,像多项式混沌展开这样的谱方法提供了一个优雅的公式来获得输出统计指标,这比传统的蒙特卡罗方法要快得多。
分析
在估计了由所有不确定性来源造成的总“损害”之后,后续任务将是确定最“有罪”的来源,即了解哪些不确定性来源对模拟结果的方差贡献最大,或者哪些不确定性来源驱使模拟结果超出阈值。这种不确定性来源的重要性排序也被称为全局敏感性分析。
全局敏感性分析将模拟输出的总方差分配给不同的不确定性来源及其相互作用。这种敏感性分析的结果通常以所谓的 Sobol 指数的形式进行总结。具有较大 Sobol 指数值的参数对模拟输出的变化贡献较大,而具有较小 Sobol 指数值的参数基本不起作用。
控制
最后,我们采取措施减轻各种不确定输入源的不利影响,并旨在获得可靠的输出预测。遵循上一步,我们可以将精力集中在降低最“有罪”的不确定性来源的不确定性水平上:
- 如果是认知型的,我们可以在第一步进行更多的实验或者观察更多的样本来提炼我们的知识;
- 如果它是随机型的,我们可以优化被模拟的系统的可调属性,使得系统的输出对噪声随机不确定性的响应变得更少(或更鲁棒)。这种做法也被称为不确定性下的优化。
2.3 实践中的 IPAC:新冠肺炎·疫情造型
为了使上述概念更加具体,让我们考虑 IPAC 如何帮助量化与新冠肺炎·疫情建模相关的不确定性。
流行病建模使用数学模型来模拟传染病的传播。有许多模型,从基本的 SIR 模型到更复杂的随机模拟模型,就像帝国理工学院的研究人员在他们改变了英国冠状病毒策略的开创性工作中使用的模型。
准确模拟一场流行病的过程不是一件容易的事情,建模不确定性的各种来源是罪魁祸首。首先,像传播率这样的模型参数还不完全清楚,因为新型冠状病毒是一种相当新的病毒,需要更多的研究来了解它的传播模式。此外,需要初始条件、如传染物的初始值来启动模拟。不幸的是,由于疫情爆发之初记录不全,这些数值非常不确定。
为了保证模拟的可靠性,我们可以遵循上面提到的 IPAC 框架:首先,我们从有关感染个体数量、死亡人数等官方数据中估计那些模型参数和初始条件。为此,可以使用贝叶斯统计(特别是马尔可夫链蒙特卡罗)来推导它们的联合概率分布。这是“识别”步骤,这里的结果是我们现在能够描述关于那些模型参数和初始条件的不确定性。
其次,我们执行前向不确定性传播。我们多次运行我们的流行病模型,每次都使用不同的模型参数和初始条件样本,这些样本来自先前导出的概率分布。基于模拟结果的集合,我们现在能够量化与我们感兴趣的输出相关联的不确定性,例如再生数 R(一个个体可以感染的人数)、流行病的持续时间、感染和死亡的总人数等。
接下来,我们可以执行全局灵敏度分析,以了解哪些不确定输入是最有问题的输入,即驱动大多数输出变化,以及哪些不确定输入的影响很小,我们可以基本上将它们视为常数。
最后,是时候采取行动了。基于我们从上一步中获得的知识,我们将知道应该进一步收集哪些现场数据以及多长时间收集一次,以便更好地估计最“有问题”的参数。这将使我们能够获得更准确和可靠的流行病学预测。
当然,我们不会就此止步。不确定性量化流行病模型可以作为评估各种非药物干预(例如,社会距离、关闭学校等)的有效性的有价值的工具。),从而为降低再生产数量 R 的可靠政策提供信息,并最终帮助我们赢得这场战斗。
2.4 不确定性量化是一个迭代过程
在我们进入下一节之前,值得一提的是,在实践中,不确定性量化经常以迭代的方式实现。以下是一些例子:
- 在“分析”步骤中进行的快速筛选分析(例如莫里斯筛选)可以告知从业者哪些来源是无影响的,因此无需在“传播”步骤中考虑它们(维度减少!).
- 在“控制”步骤中,我们已经计算了将输出变化降低到可接受的水平需要减少多少输入源的不确定性。这些信息在“识别”步骤中非常有价值,因为它告诉我们需要分配多少资源来更好地表征输入不确定性来源。
- 最后,通过迭代执行正向不确定性传播(“传播”步骤)和贝叶斯更新(“识别”步骤)与真实世界的观察,建立了一个全新的分析,称为数据同化。数据同化在天气预报中被大量使用,并充当隐藏的英雄,做出类似“明天下雨的概率是 30%”的声明。“有可能。
3.应用不确定性量化的挑战
最大的挑战是所需的高计算成本。这在很大程度上归因于需要用不确定输入的不同实现来重复运行模拟(蒙特卡罗家族方法的遗产)。
在工业实践中,单次模拟运行通常已经相当昂贵,更不用说多次运行了。举几个数字,对于现在在超级计算机上运行的大规模高分辨率模拟,计算时间通常从几天到几周,有时甚至几个月。同时,适当的蒙特卡罗分析需要至少几千次模拟运行来实现统计收敛。结论很明显,这不是出路。
为了解决这个问题,在所谓的 代理建模 方法论上已经花费了大量的精力。这就是机器学习进入这个领域的方式。高斯过程、支持向量回归、和神经网络是三个比较流行的例子。这里的目标是学习计算机模拟的输入和输出之间的关系,并将这种关系嵌入到评估起来很便宜的代理模型中。
之后,蒙特卡罗可以直接应用于这个运行成本低廉的代理模型,从而潜在地节省了大量的计算预算。

这里有一个例子。高斯过程已经被用于预测现代航空发动机燃烧系统中出现的不稳定现象。各种不确定性来源(例如,制造误差、随机操作条件等。)存在,且非常需要不确定性量化来提供可靠的不稳定性预测。通过训练高斯过程模型来近似昂贵的航空发动机燃烧室模拟器,蒙特卡罗模拟可以以超过 100 倍的计算速度执行,从而显著提高不确定性管理过程的效率。
虽然看起来很有前途,但代理建模无法避免成为维度诅咒的受害者。当不确定参数的数量增加时,拟合精确替代模型的计算成本呈指数增长。在这种情况下,在训练代理模型之前执行模型降阶变得势在必行。
结果是、特征选择和模型降阶技术,例如主成分分析、各种正则化回归技术等。,近年来越来越受欢迎。
4.不确定性量化的未来
近年来,有几个趋势变得很明显:
首先,3D 打印和物联网等新兴概念正在改变制造业,具有量化不确定性的计算机模拟确保了其实际部署的可靠性。因此,越来越多的努力花费在研究基本算法以及现实的实现上。
其次,UQ 专家和领域专家的合作越来越密切。领域知识提供了关于输入-输出关系的有价值的见解,从而弥补了 UQ 分析中用于替代模型构建的训练数据的缺乏。此外,领域知识告知输入的敏感性,从而实现计算资源的更好分配。
最后,机器学习和不确定性量化之间的联系将进一步加强。证据是越来越多的不确定性量化会议开始设立专门的小型研讨会和研讨会,邀请人们贡献展示机器学习工具的潜力。通过机器学习技术的增强,我们可以期待在计算机模拟中对不确定性进行更经济、更准确和更稳健的量化。
5.关键要点
不确定性量化对于在广泛的工程领域提供可靠的基于模拟的预测至关重要。通过这篇文章,我们已经谈到:
- 模拟不确定性的来源(输入数据、模型形式、数值计算)及其类型(任意的和认知的);
- 管理模拟不确定性的 V & V 框架和“识别-传播-分析-控制”框架;
- 机器学习技术为实现更经济、更准确、更稳健的不确定性量化提供了有前途的方法。
在本文中,我们仅从鸟瞰的角度讨论了不确定性管理。实际上,许多技术细节使得管理不确定性成为可能。我们将在下面的文章中讨论它们。
延伸阅读:
[1] Ralph C. Smith,不确定性量化:理论、实现和应用,SIAM 计算科学&工程,2014。
【2】Ryan g . MCC larren,不确定性量化与预测计算科学,施普林格,2018。
关于作者
我是一名博士研究员,研究航空航天应用的不确定性量化和可靠性分析。统计学和数据科学是我日常工作的核心。我喜欢分享我在迷人的统计世界中学到的东西。查看我以前的帖子以了解更多信息,并在 中 和Linkedin上与我联系。
使用 MLflow 管理您的机器学习实验
告别繁琐的实验跟踪和杂乱的模型监控

我仍然记得我和我的队友在从事机器学习(ML)项目时的那段痛苦时光。
单调而又刻意地,我们手动地将无数实验的结果转移到 Google Sheet 上,并将保存的模型组织到文件夹中。当然,我们确实试图尽可能地自动化这个过程,但是管理我们的 ML 实验仍然是一件混乱的事情。
如果上述情况听起来像是你正在经历的事情,希望这篇文章能够帮助你摆脱困境,减轻你的痛苦。
作为管理 ML 实验的最佳开源解决方案之一(见其他工具此处), ML flow 将极大地改善您的福祉(作为数据科学家、机器学习专家等)。)并让您和您的团队保持理智,同时跟踪您的模型💪。
MLflow 如何帮助我?
只需将几行代码集成到您的脚本中,您就可以将您的模型参数和指标自动记录到一个有组织的仪表板中,如下所示。

单击表中的每一行将会显示更多的细节,包括为该次运行保存的模型的路径(一次运行基本上就是一次模型训练)。

如前所述,重要的是,只需在脚本中添加几行代码,所有这些都可以自动化。
在下面的示例代码片段中,我们在与 MLflow 相关的所有代码行上方放置了注释。
一般来说,在我们的示例中有三个主要部分:
1.设置实验:在使用mlflow.start_run()开始运行之前,我们在这里设置一个实验名称(mlflow.set_experiment())和路径(mlflow.set_tracking_uri())来记录我们的运行。
2.训练模型:这里没什么特别的,就是正常的模型训练。
3.日志:日志参数(mlflow.log_params())、度量(mlflow.log_metric())和模型(mlflow.sklearn.log_model())。
运行代码后,您可以在终端中执行mlflow ui,将会有一个链接指向您的 MLflow 仪表板。
简单利落对吧?😎
然而,到目前为止,我们向您展示的是本地环境。如果我们想和其他队友合作呢?这就是远程服务器发挥作用的地方,本文的下一节将向您展示这样做的步骤。
在谷歌云上部署 MLflow 的步骤
我们首先列出要采取的一般步骤,然后用截图详细说明每个步骤(随意点击每个步骤进行导航)。拥有一个 Google Cloud 帐户是遵循这些步骤的唯一先决条件。请注意,谷歌云为新注册用户提供免费试用,所以你可以免费试用。
1.设置虚拟机(VM)
我们的第一步是通过谷歌云控制台设置一个计算引擎虚拟机实例。
a)登录您的谷歌云控制台后,启用计算引擎 API

b)启动谷歌云壳
您应该会在控制台页面的右上角看到一个类似于下面红框中按钮的按钮。点击它,会弹出一个终端。我们将使用这个终端来启动我们的虚拟机。

点击红框中的按钮,启动谷歌云外壳
c)创建一个计算引擎虚拟机实例
在 Google Cloud Shell 中键入以下内容,创建一个名为 mlflow-server 的 VM 实例。
gcloud compute instances create mlflow-server \
--machine-type n1-standard-1 \
--zone us-central1-a \
--tags mlflow-server \
--metadata startup-script='#! /bin/bash
sudo apt update
sudo apt-get -y install tmux
echo Installing python3-pip
sudo apt install -y python3-pip
export PATH="$HOME/.local/bin:$PATH"
echo Installing mlflow and google_cloud_storage
pip3 install mlflow google-cloud-storage'
上面代码中参数的简要描述:
- machine-type 为我们的虚拟机指定 CPU 和 RAM 的数量。您可以从该列表中选择其他类型。
- 区域是指您的集群所在的数据中心区域。你可以选择离你的用户不太远的地方。
- 标签允许我们在以后添加网络防火墙规则时识别实例。
- 元数据启动脚本提供了一个 bash 脚本,它将在我们的实例启动时执行,安装所需的各种包。
d)创建防火墙规则
这是为了允许在端口 5000 上访问我们的 MLflow 服务器。
gcloud compute firewall-rules create mlflow-server \
--direction=INGRESS --priority=999 --network=default \
--action=ALLOW --rules=tcp:5000 --source-ranges=[0.0.0.0/0](http://0.0.0.0/0) \
--target-tags=mlflow-server
2.创建云存储桶
在 Google Cloud Shell 中运行下面的代码,用您选择的唯一名称替换 < BUCKET_NAME > 。这个桶将是我们以后存放模型的地方。
gsutil mb gs://<BUCKET_NAME>
3.启动 MLflow 服务器
我们现在将 SSH 到我们的 mlflow-server 实例中。
转到计算引擎页面并为您的实例单击 SSH 按钮。您的 VM 实例的终端应该会弹出。

当终端准备就绪时,记下显示在计算引擎页面上的 mlflow-server 实例的内部和外部 IP。我们以后会需要它们。
在启动我们的 MLflow 服务器之前,让我们做一个快速检查,以确保所有东西都已安装。由于我们的启动脚本需要几分钟的时间来完成执行,如果您太快地使用 SSH,这些包可能还没有全部安装好。要检查是否安装了 MLflow,请在终端中键入:
mlflow --version
如果已经安装了 MLflow,您应该可以看到它的版本。如果没有,不要担心,要么再等一会儿,要么执行我们的 bash 脚本中步骤 1c 下的命令来手动安装包。

如果已经安装了 MLflow,我们现在可以通过执行以下命令使用 tmux 打开一个新窗口:
tmux
通过运行下面的代码启动我们的 MLflow 服务器,将 < BUCKET_NAME > 和 < INTERNAL_IP > 分别替换为步骤 2 中的 BUCKET 名称和前面提到的您的内部 IP 地址。
mlflow server \
--backend-store-uri sqlite:///mlflow.db \
--default-artifact-root gs://<BUCKET_NAME> \
--host <INTERNAL_IP>
如果您看到类似以下截图的内容,恭喜您的 MLflow 服务器已经启动并运行😄。您现在可以在浏览器中访问<External_IP>:5000来查看您的 MLflow 仪表盘。

4.添加用户验证
如果您不介意让拥有您外部 IP 地址的任何人查看您的 MLflow 仪表板,那么您可以跳过这一步。但我猜你不是一个暴露狂,对吗?还是你?😱
要添加用户认证,首先让我们通过按下Ctrl+c暂时停止我们的 MLflow 服务器。然后在用Ctrl+b d拆窗户之前,说出终结者的那句名言“我会回来的”。
a)安装 Nginx 和 Apache 实用程序
在我们终端的主窗口中,执行:
sudo apt-get install nginx apache2-utils
Nginx 将设置我们的 web 服务器,而 Apache 工具将为我们提供对htpasswd命令的访问,我们将使用该命令创建密码文件。
b)添加密码文件
运行以下程序,将 <用户名> 替换为酷名。
sudo htpasswd -c /etc/nginx/.htpasswd <USERNAME>
然后设置你的无人能破译的密码。
如果您需要一个聚会,只需省去-c参数来添加额外的用户:
sudo htpasswd /etc/nginx/.htpasswd <ANOTHER_USER>
c)启用密码和反向代理
我们需要配置 Nginx,让我们的密码文件生效,并设置 MLflow 服务器的反向代理。我们通过修改default服务器块文件来做到这一点:
sudo nano /etc/nginx/sites-enabled/default
通过将位置下的内容替换为三个粗体行来修改文件:
server {
location / {
**proxy_pass** [**http://localhost:5000**](http://localhost:5000/)**;
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;**
}
}
按Ctrl+x y Enter保存修改并退出编辑器。
重新启动 Nginx 以使更改生效:
sudo service nginx restart
使用tmux创建新会话或重新连接到我们之前的 tmux 会话:
tmux attach-session -t 0
再次启动我们的 MLflow 服务器,但这一次,我们的主机被设置为 localhost :
mlflow server \
--backend-store-uri sqlite:///mlflow.db \
--default-artifact-root gs://<BUCKET_NAME> \
--host localhost
d)启用 HTTP 流量
最后,我们按照这个链接中的步骤,为我们的实例启用 HTTP 流量,以允许访问我们的 Nginx web 服务器。实际上,当您在计算引擎页面上单击我们的 mlflow-server 实例时,您可以在防火墙部分下编辑并选择允许 HTTP 流量和允许 HTTPS 流量。
现在,如果您访问您的外部 IP(省去 :5000 ,只访问外部 IP),您应该被提示输入凭证。键入您之前设置的用户名和密码,然后“打开芝麻”,您的 MLflow 仪表盘又回到了您的眼前。
5.修改代码以访问服务器
为了让我们的脚本登录到服务器,我们需要通过提供一些凭证作为环境变量来修改我们的代码。
a)创建并下载服务帐户 json
按照此处的步骤创建新的服务账户密钥。
b) Pip 在本地安装谷歌云存储
google-cloud-storage 包需要安装在客户端和服务器上,以便访问 google 云存储。我们已经通过启动脚本在服务器上安装了这个包,所以您只需要在本地安装它。
c)将凭证设置为环境变量
在您的代码中,添加以下内容以使您的脚本能够访问服务器,并相应地替换它们:
- <google_application_credentials>:下载服务账号密钥的路径</google_application_credentials>
- <mlflow_tracking_username>:用户名</mlflow_tracking_username>
- <mlflow_tracking_password>:密码</mlflow_tracking_password>
import os# Set path to service account json file
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = <GOOGLE_APPLICATION_CREDENTIALS># Set username and password if authentication was added
os.environ['MLFLOW_TRACKING_USERNAME'] = <MLFLOW_TRACKING_USERNAME>
os.environ['MLFLOW_TRACKING_PASSWORD'] = <MLFLOW_TRACKING_PASSWORD>
d)将外部 IP 设置为 MLflow 跟踪 URI
在前面的示例代码中,mlflow.set_tracking_uri()被设置为本地文件夹路径。现在将其设置为< EXTERNAL_IP > :80,例如:http://35.225.50.9:80。
mlflow.set_tracking_uri(<EXTERNAL_IP>:80)
现在,您可以轻松地与您的队友协作,并将您的模型登录到服务器。👏 👏 👏
为了测试方便,我们的完整示例代码可以在这里找到。
通过上面的指南,我们希望您现在能够在本地和 Google Cloud 上部署 MLflow 来管理您的 ML 实验。此外,在您进行实验之后,MLflow 在您将模型部署到生产环境中之后,仍然可以用来监控您的模型。
感谢阅读,我希望这篇文章是有用的:)也请随时评论您可能有的任何问题或建议。
参考
您可以通过运行以下命令来安装 MLflow:注意 MLflow 在 MacOS 上工作。如果您在使用默认系统 Python 时遇到问题…
www.mlflow.org](https://www.mlflow.org/docs/latest/quickstart.html) [## 向 MLflow 添加身份验证
这是 MLflow 的第三次安装,我们将在 MLflow 跟踪服务器前添加一个 nginx 反向代理…
karimlahrichi.com](https://karimlahrichi.com/2020/03/13/add-authentication-to-mlflow/)
潜在图形神经网络:流形学习 2.0?
基于潜在图的深度学习
图形神经网络对以图形形式出现的数据利用关系归纳偏差。然而,在许多情况下,我们没有现成的图表。这种情况下图形深度学习还能应用吗?在这篇文章中,我将潜在图学习的最新作品与流形学习的旧技术进行了比较。
在过去的几年里,人们对开发图结构数据的 ML 方法兴趣高涨。这种数据自然会出现在许多应用中,例如社会科学(例如 Twitter 或脸书上的用户图)、化学(分子可以建模为由键连接的原子的图)或生物学(不同生物分子之间的相互作用通常建模为称为相互作用组的图)。图形神经网络(GNNs),我在我的以前的帖子中已经广泛介绍过,是一种特别流行的在这种图形上学习的方法,通过局部操作,共享参数在相邻节点之间交换信息。
然而,在某些情况下,我们没有给一个图形作为输入来工作的奢侈。这是许多生物学问题的典型情况,其中诸如蛋白质-蛋白质相互作用的图在最好的情况下只是部分已知,因为发现相互作用的实验是昂贵和嘈杂的。因此,我们感兴趣的是从数据中推断出图形,并对其应用 GNN[1]——我称这种设置为“潜在图形学习”[2]。潜在图可能是特定于应用的,并针对下游任务进行了优化。此外,有时这样的图表甚至可能比任务本身更重要,因为它可以传达关于数据的重要见解,并提供解释结果的方法。
潜在图学习的一种思维方式是具有空边集的图。在这种设置中,输入是作为某个高维特征空间中的点云提供的。与 PointNet [3]等在集合上进行深度学习的方法不同,这些方法将一些共享的可学习的逐点函数应用于每个点,我们还寻求跨点传递信息。这是通过在由点要素本身构建的图上传递消息来完成的。
第一个这种架构,动态图形 CNN (DGCNN) [4],是由麻省理工学院的王月开发的,我很高兴在该机构休假期间与他合作。受处理 3D 点云分析的计算机图形中的问题的启发,该想法是使用图形作为点云下面的局部平滑流形结构的粗略表示。岳的一个重要观察是,该图不需要在整个神经网络中保持不变,事实上它可以而且应该动态更新——这就是该方法的名称。我们论文中的下图说明了为什么这在计算机图形问题中是有用的:

动态图 CNN 动态构建一个用于特征扩散的k-最近邻图。该图是任务相关的,并且在每一层之后更新。该图(取自[4])描绘了与红点的距离(黄色代表更近的点),表明在分段任务中,更深层次的图形捕捉的是语义关系,而不是几何关系,如成对的机翼、发动机等。
DGCNNs 的局限性之一是使用相同的空间来构建图形和图形上的要素。在最近与来自 TUM 的 Anees Kazi 和我的博士后 Luca Cosmo 的合作中,我们提出了一种新的架构,称为可微分图模块(DGM) [5],通过解耦图和特征构造来扩展 DGCNN,如下图所示:

可微分图形模块(DGM)提供了一种从输入数据构建图形和在图形上扩散的特征的机制。图来自[5]。
当应用于医学领域的问题时,DGM 展示了令人印象深刻的结果,例如根据脑成像数据进行疾病预测。在这些任务中,为我们提供了多个患者的电子健康记录,包括人口统计特征(如年龄、性别等)和脑成像特征,并试图预测患者是否患有神经系统疾病。先前的工作显示了 GNNs 在这类任务中的应用,在根据人口统计学特征手工构建的“患者图”上使用扩散[6]。DGM 提供了学习图形的优势,这可能传达了对特定诊断任务中某些特征如何相互依赖的洞察。作为奖励,DGM 还在点云分类游戏中击败了 DGCNN,尽管只是略微领先。
GCNN 和 DGM 在概念上与一个叫做流形学习或 非线性降维 的算法家族有相似之处,这些算法在 21 世纪初我还是学生的时候在机器学习领域非常流行,现在仍被用于数据可视化。流形学习方法的基本假设是数据具有内在的低维结构。尽管数据可以在数百甚至数千维的空间中表示,但它只有几个自由度,如下例所示:

虽然该数据集中的手部图像是高维的(64x64 像素导致 4096 维),但它们本质上是低维的,并且可以用两个自由度来解释:手腕旋转和手指伸展。流形学习算法能够捕获数据集的这种低维内在结构,并将其表示在欧几里德空间中。图来自 Isomap 论文【9】补充材料 。
流形学习的目的是捕捉这些自由度(通过重建底层“流形”,因此得名[7]),并将数据的维度降低到其固有维度。与线性降维(如 PCA )的重要区别在于,由于数据的非欧几里德结构,可能无法通过线性投影恢复流形[8]:

线性降维(左)vs 流形学习。“瑞士滚面”( 由约书亚·特南鲍姆 创造,此处显示其 1D 化身)是多种学习论文中常见的例子。
各种学习算法在处理“流形”恢复的方式上有所不同,但却有一个共同的蓝图。首先,他们创建数据的表示,这通常是通过构建一个捕获其局部结构的k-最近邻图来完成的。其次,他们计算数据的低维表示(嵌入),试图保留原始数据的结构。这是大多数多种学习方法不同的地方。例如,Isomap [9]试图保持图的测地线距离,局部线性嵌入[10]找到相邻点的局部表示,拉普拉斯特征映射[11]使用图的拉普拉斯算子的特征函数作为低维嵌入。这种新的表示将原始的非欧几里德结构“展平”到更容易处理的欧几里德空间中。第三,一旦计算出表示,就对其应用机器学习算法(通常是聚类)。

多种多样学习方法的蓝图:首先,将数据表示为图形。其次,计算该图的低维嵌入。第三,对这个低维表示应用 ML 算法。
O 挑战之一是图的构建与 ML 算法相分离,有时需要精细的参数调整(例如邻居的数量或邻居半径),以便找出如何构建图来使下游任务工作良好。也许流形学习算法的一个更严重的缺点是,数据很少以其原始形式表现为低维。例如,在处理图像时,必须使用各种手工制作的特征提取技术作为预处理步骤。
图形深度学习通过用单个图形神经网络取代上面概述的三阶段过程,为这一过程提供了一种现代方式。例如,在动态图形 CNN 或 DGM 中,图形的构建和学习是同一架构的一部分:

潜在图形学习可被视为流形学习问题的现代设置,其中图形被学习为针对一些下游任务优化的端到端 GNN 流水线的一部分。
这种方法的吸引力在于可以将单个数据点的处理和它们在同一管道中所处的空间结合起来。在图像的例子中,可以使用传统的 CNN 从每个图像中提取视觉特征,并使用 GNN 来模拟它们之间的关系。我的博士生 Jan Svoboda 的工作中使用了这种方法:他为 CNN 提出了一个基于图形的正则化层(称为 PeerNet),允许在多个图像之间交换信息[12]。PeerNets 在聚合来自多个位置的信息的方式上与非本地均值滤波器[13]相似,主要区别在于聚合发生在多个图像上,而不是单个图像上。我们表明,这种规范化极大地降低了标准 CNN 极易受到的对抗性扰动的影响[14]。

PeerNets 是标准 CNN 中基于图形的正则化层,它聚集了来自多个图像的相似像素,以降低对敌对干扰的敏感性。图来自[12]。
T 这里有许多潜在图形学习的其他有趣应用。一种是少量学习,基于图形的技术可以帮助从几个例子中进行归纳。少量学习在计算机视觉中变得越来越重要,因为数据标记的成本很高[5]。另一个领域是生物学,人们经常通过实验观察生物分子(如蛋白质)的表达水平,并试图重建它们的相互作用和信号网络[15]。第三个问题是物理系统的分析,其中一个图可以描述多个对象之间的相互作用[16]。特别是,处理复杂粒子相互作用的高能物理学家最近对基于图形的方法表现出浓厚的兴趣[17]。最后但并非最不重要的是 NLP 中的问题,其中图形神经网络可以被视为变压器架构的推广。许多提到的问题也提出了在图结构上结合先验的问题,这在很大程度上仍然是开放的:例如,人们可能希望迫使图遵守某些构造规则或与一些统计模型兼容[18]。
我相信潜在图形学习虽然不是全新的,但它为老问题提供了一个新的视角。这肯定是一个有趣的图形 ML 问题的设置,为 GNN 研究人员提供了一个新的游乐场。
[1]一类略有不同但相关的方法试图将作为输入提供的图与用于图神经网络中消息传递的计算图分离,参见例如 J. Halcrow 等人 Grale:设计用于图学习的网络 (2020)。arXiv:2007.12002 年。人们可能希望这样做有多种原因,其中之一是打破与某些图中邻域大小的指数增长相关的瓶颈,如 U. Alon 和 E. Yahav,关于图神经网络的瓶颈及其实际意义 (2020)。arXiv:2006.05205。
[2]在董晓文的博士论文《信号处理》中考虑了一些数据背后的图形重建问题,我于 2014 年 5 月参加了其辩护委员会,就在我儿子出生前几天。X. Dong 等人的《从数据中学习图形:信号表示透视》(2019),IEEE Signal Processing Magazine 36(3):44–63 很好地总结了这方面的工作。从网络游戏的角度来看,这些方法的一个更近的化身是 Y. Leng 等人的工作在网络上学习二次游戏 (2020)。继续。ICML,今年早些时候我是他在麻省理工学院博士委员会的成员。
[3] C. Qi 等 PointNet:用于 3D 分类和分割的点集上的深度学习 (2017),Proc .CVPR。PointNet 是一种用于对集合进行深度学习的架构,其中共享函数被应用于每个点的表示,并且可以被认为是 GNN 应用于具有空边集的图的平凡情况。
[4] Y. Wang 等点云上学习的动态图 CNN(2019)。ACM Trans 图形 38(5):146。这篇论文在计算机图形社区中非常流行,并且经常被用作点云方法的基线。具有讽刺意味的是,它在 2018 年被 SIGGRAPH 拒绝,并在收集了 600 多次引用后,仅在两年后的同一场会议上发表。
[5] A. Kazi 等,图卷积网络的可微图模(DGM)(2020)arXiv:2002.04999。我们展示了多种应用,包括医学成像、3D 点云分析和少量镜头学习。参见我们的论文 L. Cosmo 等人用于自动诊断的潜在患者网络学习 (2020)。继续。专注于这种方法的医学应用。Anees 是我 2019 年在帝国理工学院小组的访问博士生。
[6]据我所知,GNNs 用于脑部疾病预测的第一次使用是由 S. Parisot 等人使用图卷积网络的疾病预测:应用于自闭症谱系障碍和阿尔茨海默病 (2017)。继续。米凯。这种方法的主要缺点是根据人口统计特征手工构建图表。
[7]从形式上讲,它不是微分几何意义上的“流形”,因为例如局部维数可以在不同的点上变化。然而,这是一个方便的比喻。
[8]更正确的说法是“非欧几里得”而不是“非线性”。
[9] J. B. Tenenbaum 等人,非线性维数约减的全局几何框架 (2000),科学 290:2319–2323。介绍了 Isomap 算法,该算法通过尝试保留数据流形上的测地线距离来嵌入数据流形,使用 k -NN 图进行近似。图上的测地线距离是连接任何一对点的最短路径的长度,通过 Dijkstra 算法计算。赋予这样的距离度量,数据集被认为是一个(非欧几里德)度量空间。在度量几何中,低维空间中成对欧几里得距离等于图测地线距离的点的配置称为等距嵌入。通常,等距嵌入是不存在的,人们不得不求助于某种意义上最能保持距离的近似。计算这种近似值的一种方法是借助于多维标度 (MDS)算法。
[10] S. T. Roweis 和 L. K. Saul,通过局部线性嵌入进行非线性降维 (2000)。科学 290:2323–2326。
[11] M,Belkin 和 P. Niyogi,拉普拉斯特征映射和用于嵌入和聚类的谱技术 (2001)。继续。乳头。
[12] J. Svoboda 等人 PeerNets:利用同伴智慧对抗对抗性攻击 (2019),Proc .ICLR 使用聚集来自多个图像的信息的 GNN 模块来降低 CNN 对输入的对抗性扰动的敏感性。
[13]非局部均值是由 A. Buades 等人提出的一种非线性图像滤波技术,一种用于图像去噪的非局部算法 (2005),Proc .CVPR。它可以被视为深度学习中使用的现代注意力机制的先驱。非局部均值本身是边缘保持扩散方法的变体,例如我的博士导师 Ron Kimmel 在 R. Kimmel 等人的论文中提出的 Beltrami 流。计算机视觉中的尺度空间理论,或 C. Tomasi 和 R. Manduchi 的双边滤波器,灰度和彩色图像的双边滤波 (1998)。继续。ICCV。
[14]对抗性扰动是一种精心构建的输入噪声,它显著降低了 CNN 的性能,例如在图像分类中。这种现象在 C. Szegedy 等人的神经网络的有趣特性 (2014),Proc。,并产生了多个后续工作,这些工作显示了像改变单个像素一样极端的奇异对抗性攻击(J. Su 等人一个像素攻击用于愚弄深度神经网络 (2017),arXiv:1710.08864)或数据独立的“通用”扰动(S. M. Moosavi-Dezfooli 等人,通用对抗性扰动 (2017),Proc .CVPR)。
[15] Y. Yu 等, DAG-GNN:用图神经网络进行 DAG 结构学习 (2019)。继续。ICML。
[16] T. Kipf 等人,交互系统的神经关系推理 (2019)。继续。ICML。通过使用变分自动编码器来恢复“解释”系统物理的图形,其中潜在向量表示底层交互图形,解码器是图形神经网络。
[17]GNNs 在高能物理中的应用是一个有趣的话题,值得另文讨论。我和我的博士生费德里科·蒙蒂一起与冰立方合作开发了可能是第一个基于 GNN 的粒子物理方法。我们的论文 N. Choma,F. Monti 等人,【IceCube 信号分类的图形神经网络 (2018),Proc .ICMLA,我们使用 MoNet 架构进行天体物理中微子分类,获得了最佳论文奖。在最近的一项工作中,S. R. Qasim 等人,使用距离加权图网络学习不规则粒子检测器几何图形的表示 (2019),欧洲物理杂志 C 79,使用了类似于 DGM 的 DGCNN 的变体,称为 GravNet,用于粒子重建。
[18]一类稍微相关的方法是生成图模型,参见例如 Y. Li 等人的学习图的深度生成模型 (2018)。arXiv:1803.03324。其中一个应用是生成符合严格构造规则的化合物的分子图。
[19]在过去的几年中,出现了更多关于潜在图学习论文的作品——如果我省略了一些,这是因为我的目标不是详尽无遗,而是展示一个原则。我将参考 L. Franceschi 等人的另一项工作为图形神经网络学习离散结构 (2019)。继续。ICML,其中也提到了与 Isomap 和流形学习技术的关系。
感谢 Ben Chamberlain、Dong Xiaowen、Fabrizio、Anees Kazi 和校对了这篇文章,并感谢 Gal Mishne 指出了瑞士面包卷的起源。对图形 ML 和几何深度学习感兴趣?查看我的 博客 关于走向数据科学, 订阅我的 帖子,获取 中等会员 ,或者关注我的 推特 。
流形学习[t-SNE,LLE,Isomap,+]变得简单

资料来源:Pixabay,Jennifer Chu。图片免费分享。
降维的核心
主成分分析是一种强大的方法,但它经常失败,因为它假设数据可以线性建模。主成分分析将新特征表示为现有特征的线性组合,方法是将每个特征乘以一个系数。为了解决 PCA 的局限性,通过应用具有不同特定结构的数据,已经产生了各种技术。然而,流形学习试图找到一种可以推广到所有数据结构的方法。
不同的数据结构指的是数据中不同的属性。例如,它可能是线性可分的,也可能非常稀疏。数据中的关系可以是相切的、平行的、包络的或正交的。PCA 在数据结构的一个非常具体的子集上工作得很好,因为它在线性的假设上操作。
为了把事情放在上下文中,考虑 300×300 像素的头像。在完美的条件下,每个图像都将完美地居中,但在现实中,还有许多额外的自由度需要考虑,如照明或脸部的倾斜。如果我们将头像视为 90,000 维空间中的一个点,改变各种效果,如倾斜头部或朝不同方向看,可以在空间中非线性地移动它,即使它是同一类的同一对象。

由作者创建。
这种数据经常出现在现实世界的数据集中。除了这种影响之外,当出现偏斜分布、极值和多个虚拟(一位热编码)变量时,PCA 也很慌乱(参见非线性 PCA 以获得此的解决方案)。需要一种通用的降维方法。
多元学习指的就是这个任务。流形学习中有许多方法可能以前已经见过,例如 t-SNE 和局部线性嵌入(LLE)。有许多文章和论文深入研究了这些算法的技术和数学细节,但这一篇将集中在一般的直觉和实现上。
请注意,虽然有一些受监督的维度减少的变体(例如线性/二次判别分析),但流形学习通常指的是无监督的减少,其中类不呈现给算法(但可能存在)。
PCA 试图创建几个线性超平面来表示维度,很像作为数据估计的多重回归构造,而流形学习试图学习流形,流形是多维空间内的平滑曲面。如下图所示,这些通常是由图像上的细微变换形成的,否则会欺骗 PCA。

资料来源:阿伦·詹森。图片免费分享。
然后,可以提取与流形相切的“局部线性面片”。这些小块通常足够丰富,可以准确地表示流形。因为这些流形不是由任何一个数学函数来模拟的,而是由几个小的线性块来模拟的,所以这些线性邻域可以模拟任何流形。尽管这可能不是某些算法处理流形建模的明确方式,但基本思想是非常相似的。
以下是流形学习算法的基本假设或方面:
- 数据中存在非线性关系,可以通过流形进行建模——跨越多个维度的表面,平滑,不太“波动”(太复杂)。流形是连续的。
- 维护数据的多维形状并不重要。除了用特定的方向“展平”或“投影”数据(如 PCA)来保持数据的总体形状,还可以执行更复杂的操作,如展开一个盘绕的条带或翻转一个球体。
- 对流形建模的最佳方法是将曲面视为由几个邻域组成。如果每个数据点设法不与所有其他点保持距离,而仅与接近它的点保持距离,则几何关系可以在数据中保持。
这个想法可以通过查看解开这个盘绕数据集的不同方法来很好地理解。左边是一个更像 PCA 的方法来保持数据的形状,其中每个点都是相互连接的。然而,右边是一种方法,其中只评估数据点邻域之间的距离。

来源:杰克·范德普拉斯。图片免费分享。
这种对邻域之外的点的相对忽视导致了有趣的结果。例如,考虑这个瑞士卷数据集,它在三维空间中被卷绕,在二维空间中被简化为一条带状。在某些情况下,这种效果并不理想。然而,如果这条曲线是图像中相机倾斜或音频质量外部影响的结果,流形学习通过微妙地解开这些复杂的非线性关系给我们带来了巨大的帮助。

来源:数据科学大侠。图片免费分享。
在 Swiss Roll 数据集上,主成分分析甚至像核主成分分析这样的专门变体都无法捕捉值的梯度。另一方面,局部线性嵌入(LLE),一种流形学习算法,能够。

资料来源:詹妮弗·朱。免费分享图片
让我们更详细地了解三种流行的流形学习算法:IsoMap、局部线性嵌入和 t-SNE。
流形学习中最早的探索之一是 Isomap 算法,是等距映射的缩写。Isomap 寻求一种维持点之间“测地线距离”的低维表示。测地线距离是曲面距离的概括。因此,Isomap 不是用毕达哥拉斯定理导出的距离公式来测量纯欧几里得距离,而是沿着发现的流形来优化距离。

来源:sklearn。图片免费分享。
在 MNIST 数据集上训练时,Isomap 的性能优于 PCA,显示了不同类型数字的正确分割。某些数字组之间的接近和距离揭示了数据的结构。例如,距离很近的“5”和“3”(在左下方)看起来确实很相似。
下面是 Isomap 在 Python 中的实现。由于 MNIST 是一个非常大的数据集,您可能只想使用.fit_transform(X[:100])在前 100 个训练示例上训练 Isomap。
局部线性嵌入使用各种切线线性补片(如上图所示)来模拟流形。它可以被认为是对这些邻域中的每一个局部地执行 PCA,产生线性超平面,然后全局地比较结果以找到最佳的非线性嵌入。LLE 的目标是以扭曲的方式“展开”或“解开”数据的结构,因此 LLE 往往会在中心具有较高的密度,并延伸射线。

来源:sklearn。图片免费分享。
注意,LLE 在 MNIST 数据集上的表现相对较差。这很可能是因为 MNIST 数据集由多个流形组成,而 LLE 是为处理更简单的数据集而设计的(如瑞士卷)。在这种情况下,它的性能与 PCA 相当,甚至更差。这有道理;它的“将一个函数表示为几个小的线性函数”策略可能不适用于大型复杂的数据集结构。
LLE 的实现如下,假设数据集(X)已经被加载。
t-SNE 是高维可视化最流行的选择之一,代表 t-分布式随机邻居嵌入。该算法将原始空间中的关系转换成 t 分布,或者具有小样本量和相对未知的标准偏差的正态分布。这使得 SNE 霸王龙对局部结构非常敏感,这是流形学习中的一个常见主题。它被认为是首选的可视化方法,因为它具有许多优点:
- 它能够揭示多种尺度下的数据结构。
- 它揭示了存在于多个流形和簇中的数据
- 更倾向于将点聚集在中心。
等映射和 LLE 最适合用来展开一个单一、连续的低维流形。另一方面,t-SNE 专注于数据的局部结构,并试图“提取”聚类的局部组,而不是试图“展开”或“展开”它。这使得 t-SNE 在用多个流形理清高维数据方面占据上风。它使用梯度下降进行训练,并试图最小化分布之间的熵。从这个意义上说,它几乎就像一个简化的、无监督的神经网络。
t-SNE 是非常强大的,因为这种“集群”与“展开”的流形学习方法。对于像 MNIST 这样的高维多流形数据集,旋转和移动会导致非线性关系,t-SNE 的表现甚至优于被贴上标签的 LDA 。

来源:sklearn。图片免费分享。
然而,SNE 霸王龙也有一些缺点:
- t-SNE 的计算开销非常大(比较上图中的运行时)。在百万样本数据集上可能需要几个小时,而 PCA 可以在几秒或几分钟内完成。
- 该算法依赖于随机性(随机)来挑选种子以构建嵌入,如果种子碰巧放置不当,则会增加其运行时间并降低性能。
- 全局结构没有被显式地保留(即更强调聚类而不是展示全局结构)。然而,在 sklearn 的实现中,这个问题可以通过用 PCA 初始化点来解决,PCA 是专门为保持全局结构而构建的。
t-SNE 也可以在 sklearn 中实现:
SNE 霸王龙的作者劳伦斯·范·德·马腾说,当 SNE 霸王龙产量很低时,要考虑以下几点:
作为一个健全的检查,试着对你的数据运行主成分分析,把它减少到二维。如果这也给出了不好的结果,那么可能首先你的数据中没有非常好的结构。如果 PCA 工作正常,但 t-SNE 不行,我相当肯定你做错了什么。
他为什么这么说?作为击中要害的额外提醒,流形学习不是 PCA 的另一种变体,而是一种推广。在主成分分析中表现良好的东西几乎肯定在 t-SNE 或其他流形学习技术中表现良好,因为它们是一般化的。
就像一个苹果也是一个水果一样(一个概括),如果某个事物不能产生与它的概括相似的结果,通常是有问题的。另一方面,如果两种方法都失败了,数据可能天生就很难建模。
要点
- PCA 不能模拟非线性关系,因为它是线性的。
- 非线性关系经常出现在数据集中,因为光照或倾斜等外力可以在欧氏空间中非线性地移动同一类的数据点。
- 流形学习试图推广 PCA 以对所有种类的数据集结构执行维数减少,其主要思想是流形或弯曲的连续表面应该通过保持和优先考虑局部而不是全局距离来建模。
- Isomap 试图保持测地线距离,或者不是在欧几里得空间而是在流形的曲面上测量的距离。
- 局部线性嵌入可以被认为是将流形表示为几个线性面片,在这些面片上执行 PCA。
- t-SNE 更多地采用“提取”方法,而不是“展开”方法,但仍然像其他流形学习算法一样,通过使用概率和 t 分布来优先保留局部距离。
附加技术读物
感谢阅读!
使用 MongoDB 操作数据
使用 PyMongo 学习 CRUD 的基础知识

马库斯·斯皮斯克在 Unsplash 上拍摄的照片
访问第 1 部分这里来设置你的 MongoDB。
介绍
在上一篇文章中,我们设法了解了为什么 MongoDB 如此强大,以及如何设置它和导入我们的数据。
设置好一切之后,我们现在可以用 PyMongo 学习 MongoDB 的基础知识了。我将带您了解 CRUD 操作,它代表:
- c——创建:创建数据并将其插入到数据库中
- r-Read:从数据库中读取数据
- U —更新:选择并更新数据库中的数据
- d-删除:删除数据库中的数据
用 Pymongo 连接到 Python
下面的代码显示了我们如何连接到我们的客户端:
import pymongo
from pymongo import MongoClient
import pprintclient = MongoClient("<CONNECTION STRING>")
用自己的字符串替换<CONNECTION STIRNG>。如果您不确定它是什么,请参考本系列的第 1 部分!它应该是这样的:
mongodb+srv://analytics:[analytics-pw@mflix-b23yi.mongodb.net](mailto:analytics-pw@mflix-b23yi.mongodb.net)
创造
只需使用insert_one()功能即可插入数据:
from datetime import datetimenew_data = {
"_id": "unique_id_here",
"name": "random_name",
"email": "[random_email@email.com](mailto:random_email@email.com)",
"text": "This is a random text!",
"date": datetime.utcnow()
}insert_result = client.sample_mflix.movies.insert_one(new_data)
pprint.pprint(insert_result.acknowledged)
pprint.pprint(insert_result.inserted_id)

输出
在上面的代码中,我们将新数据定义为一个字典。您可以包含任意数量的字段(记住,MongoDB 是灵活的,您不需要有一组固定的键)。请注意我们是如何用client.sample_mflix.movies来引用我们的数据库的。它遵循client.database.collections的层次结构。
最重要的领域是_id。MongoDB 中的每个文档都由一个惟一的标识符标识。如果您要插入两个具有相同标识符的数据,您将会遇到一个错误。
让我们用 Compass 验证新数据是否已插入:

当你想在 Compass 中搜索某个东西时,你必须用下面的格式{'<KEY>':'<VALUE'}来指定它。
insert_one()返回我们两个输出:
- 已确认:如果插入成功,则为真,否则为假
- inserted_id:文档的唯一 id。您可以使用这个 ID 在 Compass 中搜索新数据
但是如果我想插入很多数据呢?
from datetime import datetimenew_data_1 = {
"_id": "unique_id_here_1",
"name": "random_name",
"email": "[random_email@email.com](mailto:random_email@email.com)",
"text": "This is a random text!",
"date": datetime.utcnow()
}new_data_2 = {
"_id": "unique_id_here_2",
"name": "random_name",
"email": "[random_email@email.com](mailto:random_email@email.com)",
"text": "This is a random text!",
"date": datetime.utcnow()
}final_data = [new_data_1,new_data_2]insert_result = client.sample_mflix.movies.insert_many(final_data)
你只需要把insert_one改成insert_many。就这么简单!
阅读
有很多方法可以读取你的数据。您可以使用 MongoDB 提供的许多其他功能进行过滤、分组、排序、限制、计数、求和。我将介绍一些基础知识。
find_one()
find_one()允许我们检索数据库中的第一批数据
client.sample_mflix.movies.find_one()
投影取景器
finder允许我们指定想要过滤的关键字和值。projection允许我们指定我们想要返回的内容。
finder = {
'countries': {'$all': ['USA', 'Italy']}
}
projection={
'title':1,
'countries':1,
'rated': 1
}
pprint.pprint(list(client.sample_mflix.movies.find(finder,projection)))
'$all'表示'countries'字段必须包含所有指定的内容。在我们的例子中,我们想要检索在美国和意大利制作的电影。请注意,这种语法非常类似于您在 Compass 的搜索栏中键入的内容。- 在
projection下,我们指定想要返回的键。如果要返回,请将值设置为 1;如果不想返回该键,请将值设置为 0。如果您忽略该键,它将被视为您不想返回该键。

结果子集
总计
PyMongo 中的大部分数据读写都可以使用一个聚合框架来完成。聚合是一种集合类方法。这意味着它只能应用于集合/表。聚合框架需要管道或“模板”:
pipeline = [
{
'$group': {
'_id': {"rated": "$rated"},
'count': {"$sum": 1}
}
},
{
'$sort': {'count': -1}
}
]pprint.pprint(list(client.sample_mflix.movies.aggregate(pipeline)))
'$groupstage 允许我们通过指定的键对输出进行分组。'_id':{"rated":"$rated"}是我们指定想要分组的关键字的地方。在这种情况下,我想按惟一的rated分组。美元符号($)是字段路径标识符。它允许我们从数据库中检索精确的值。'count': {"$sum": 1}将自动为每个唯一的rated增加 1。'$sort':{'count': -1}告诉我们的管道按照计数的降序(-1)对结果进行排序。

结果
方面
Facet 允许我们很好地对数据进行分组。它类似于$group ,但它允许我们定制我们想要的数据分组方式。
pipeline = [
{
'$sortByCount': '$countries'
},
{
'$facet':{
'top country combinations': [{'$limit': 10}],
'unusual combinations shared by' : [{
'$skip' : 10
},
{
'$bucketAuto': {
'groupBy': "$count",
'buckets': 5,
'output': {
'country combinations': {"$sum":1}
}
}
}
]
}
}
]pprint.pprint(list(client.sample_mflix.movies.aggregate(pipeline)))
‘top country combinations’: [{‘$limit’: 10}]告诉我们的渠道产生前 10 个国家及其各自的数量‘$skip’ : 10允许我们跳过前 10 个结果,因为它已经被归类到'top country combinations'下‘$bucketAuto’: {是一种根据特定指标将剩余结果分组到指定最大数量的桶/箱中的方法。

结果
在结果中,我们首先受到电影数量排名前 10 位的国家的欢迎。继续,我们有 3 个桶。对于 MongoDB,min是包含性的,max是排他性的。这意味着有些电影的国家组合与最少 2 部其他电影和最多 6 部其他电影相似。这类电影的数量是 469 部。另一方面,我们还有min: 1和max: 1。这意味着有 1695 部电影拥有独特的国家组合。
清理、过滤和修改数据到另一个集合中
对于这一节,我将参考原来的movies_initial.csv,因为它是不干净的。在将数据导出到另一个名为movies_subset的集合之前,我们将清理一部分数据。
pipeline = [
{
'$limit': 100
},
{
'$project': {
'title': 1,
'directors': {'$split': ["$director", ", "]},
'released': {
'$cond': {
'if': {'$ne': ["$released", ""]},
'then': {
'$dateFromString': {
'dateString': "$released"
}
},
'else': ""}},
'imdb': {
'id': "$imdbID",
'rating': "$imdbRating",
'votes': "$imdbVotes"
}
}
},
{
'$out': "movies_subset"
}
]pprint.pprint(list(client.mflix.movies_initial.aggregate(pipeline)))
- 我们首先将要检索的数据数量限制为 100
- 我们想要标题字段
- 目录字段被拆分成一个数组。例如,
"Mike, Tom, Harry"将被分割成["Mike", "Tom", "Harry"] - 在 released 字段中,如果字段不为空,我们实际上是将日期和时间字符串转换为 DateTime 对象。如果字段为空,我们将返回一个空字符串。
‘if’: {‘$ne’: [“$released”, “”]}指定如果我们的 released 字段不等于空字符串,我们将继续使用子句中的内容。- 最后
$out允许我们将最终数据导出到一个新的集合中

我们现在有了新的系列!
过滤器
有三种方法可以过滤你的结果。
- $匹配
pipeline = [
{
'$match': {'countries': ['USA', 'Italy']}
}
]
pprint.pprint(list(client.sample_mflix.movies.aggregate(pipeline)))
2.探测器
finder = {'countries': ['USA', 'Italy']}
pprint.pprint(list(client.sample_mflix.movies.find(finder)))
3.指南针
{'countries': ['USA', 'Italy'], 'rated' : "UNRATED"}
以上 3 个都一样。嗯……不完全一样,我在第三点里面偷偷加了一个滤镜。但是您可以看到如何在一行中输入多个过滤器!
注意, *$all* 和 *$match* 非常不同。 *$match* 要求完全匹配。 *$all* 只要找到指定的值就会返回结果。
经营者
您可以在过滤器或搜索中包含某些比较运算符。
# find all movies except the ones which are of adult genre
filters = {
'year': {'$gte': 1989, '$lt': 2000},
'genre': { '$not' : {'$eq': 'Adult'} }
}pprint.pprint(list(client.sample_mflix.movies.find(filters)))
$gte代表“大于或等于”$lt代表“小于”{ ‘$not’ : {‘$eq’: ‘Adult’} }表示我们需要不等于“成人”的值
有 20 多个操作员。我强烈建议您查看文档!
排序和限制
排序和限制非常简单。我们经常把它们结合起来,使我们的输出可读。您不仅可以将它们输入到聚合框架中,还可以将其用作 Python 方法。
from pymongo import DESCENDING
sort_key = "imdb.rating"movies = client.sample_mflix.movies.find({}) \
.sort(sort_key, DESCENDING).limit(100)list(movies)
首先,我们指定我们想要排序值的关键字。注意,我们键入imdb.rating是因为rating(一个标量)嵌套在imdb(一个数组)中。
注意,在我们的.find()方法中,我们输入了一个空字典。这告诉我们的查找器搜索整个集合。
最后,我们按降序对结果进行排序,只返回前 100 个结果。
更新
之前,我们学习了如何将数据修改到新的集合中。现在,我们将看看如何就地修改我们的数据。
逐文档更新一个文档
我们在代码中所做的是,首先,遍历标题为“泰坦尼克号”的所有电影。接下来,我添加了两个字段,comments和num_mflix_comments,并实例化了它们。最后,我删除了poster字段,因为我不再需要它们了。
titanic_filter = {'title': "Titanic"}for movie in client.sample_mflix.movies.find(titanic_filter):
update_doc = {
"$set": {
"comments": [],
"num_mflix_comments": 0
},
"$unset": {
"poster": ""
}
}
client.sample_mflix.movies.update_one({'_id': movie['_id']}, update_doc)
$set用指定的值替换字段的值$unset仅删除存在的特定字段
我们可以使用 Compass 验证代码是否有效:

update_one一次更新一个文档。如果是一个小数据集,这不是问题。然而,如果我们有一个大的数据集,我们会想要批量更新我们的数据
批量更新文档
批量更新集合与逐个更新非常相似。不同之处在于,每次迭代,我们将更新保存在一个数组中,而不是更新。同时,我们跟踪我们所处的迭代次数。当我们达到批量时,我们将使用bulk_write将所有更新写入我们的数据库
from pymongo import UpdateOnetitanic_filter = {'title': "Titanic"}
batch_size = 10
updates = []
count = 0for movie in client.sample_mflix.movies.find(titanic_filter):
update_doc = {
"$set": {
"comments": [],
"num_mflix_comments": 0
},
"$unset": {
"poster": ""
}
}
updates.append(UpdateOne({'_id': movie['_id']}, update_doc))count += 1
if count == batch_size:
client.sampel_mflix.movies.bulk_write(updates)
updates = []
count = 0if updates:
client.sampel_mflix.movies.bulk_write(updates)
一定要记住用最后两行代码来捕捉最后一批代码!
删除
我们只需要两个方法delete_one()和delete_many()。
我们来看看收视率低于 3.5 的电影有多少
filter = {"imdb.rating": {'$lte':3.5}}before = list(client.sample_mflix.movies.find(filter))
len(before)

我们注意到有 178 部电影。我们删除其中一个:
client.sample_mflix.movies.delete_one(filter)

我们现在只剩下 177 个,因为我们删除了其中一个。
现在,让我们删除所有评分低于 3.5 的电影
client.sample_mflix.movies.delete_many(filter)

成功!
结论
恭喜你!您现在可以在 MongoDB 中操作数据了。我强烈建议您查看文档。我只能解释这么多功能。然而,文档包含了完成项目所需的每一种方法。我非常相信学会如何阅读文档是成为一名软件工程师/数据科学家的重要部分。
参考
- 【https://www.coursera.org/learn/introduction-mongodb
- https://docs.mongodb.com/
- 代号:https://github.com/bensjx/MongoDB_Demo/
机器学习中激活的权威指南
列出你需要的所有激活功能

作者图片
对于任何机器学习模型,最关键的决定之一是选择使用哪种激活。让我们来看看你想知道的所有激活功能。这个列表的顺序正在被越来越多地使用。
索引
如果你想直接进入其中,这里有一个快速列表。
- 恒等函数和二元步长
- 乙状结肠的
- Softmax
- 双曲正切值
- SoftPlus
- 指数线性单位(ELU)及其缩放版本,SELU
- 整流线性单位(ReLU)及其变体。
有这么多要讲的,我们现在就开始吧。
恒等函数和二元步长
恒等函数 实际上是将输入作为输出返回的函数。因此,

这个函数最近很少被使用,而且你是否想要使用它也是非常值得怀疑的。
恒等函数的图形简单如下。

作者图片
二进制步骤 函数如果数字为正数则返回 1,否则返回 0。这是一个很少使用的功能。因此,

图表如下图所示,

作者图片
Sigmoid 函数

作者图片
这个函数以前是所有机器学习中使用最多的。该函数将一个数字映射到 1 和 0 之间,图形如下图所示。

sigmoid 函数现在仅限于逻辑回归和神经网络的二进制分类问题的输出节点(输出 0 或 1),尽管早期它也用于隐藏单元。
Softmax 函数
softmax 函数将一和概率应用于向量的各个分量。数学上,

因此,它也被称为标准化指数运算。
单独地,应用下面的指数图。

作者图片
应用于多类分类问题的神经网络输出节点。
双曲正切

作者图片
双曲正切函数是 sigmoid 的后继者,因为它在神经网络的隐藏层中始终给出更好的性能。您可能会观察到,双曲正切图与 sigmoid 非常相似,只是它稳定在-1 和 1,并以 0 为中心。
数学上它是双曲正弦和余弦的比值,

如今,双曲正切函数也很少用于隐藏层,尽管一些特定的模型也使用双曲正切函数。range -1 和 1 的输出需求的一些问题在输出节点使用 tanh。
SoftPlus 功能

作者图片
SoftPlus 函数是 ReLU 的更软或更平滑的版本,您将在后面看到。
数学上,

当 ReLU 给出零梯度时,SoftPlus 允许平滑梯度。因此,在这种情况下,您可以使用 SoftPlus 而不是 ReLU。应当注意,SoftPlus 函数在计算上要昂贵得多。
指数线性单位

作者图片
ELU 或指数线性单位是一个新的和高精度的在隐藏层中被广泛使用的激活函数。它是一个参数化函数,即它有一个参数(技术上是一个超参数或可调参数)称为α,符号为α。如果是正数,ELU 返回数字本身,并给出 alpha 乘以输入的幂减 1。
数学上,

其中α通常是一个介于 0.1 和 0.3 之间的数字
ELU 比 ReLU 有潜力获得更好的精度。然而,它的计算量更大。
标度指数线性单位

作者图片
SELU 或按比例缩放的指数线性单位是对 ELU 的修改,可更好地帮助提高精度和归一化。增加一个额外的超参数λ,符号为λ。SELU 被给定为,

值为α = 1.67326,λ = 1.0507
SELU 比 ELU 工作得更好,但是由于另一个增加的乘法,它在计算上更加昂贵。
整流线性单元

作者图片
现今最常用的激活函数之一是整流线性单元或 ReLU 函数。让它如此吸引人的是它的简单性和有效性。该函数通过使负值为零来消除负值。它保留实际输入的值。
数学上,

尽管 ReLU 的性能不如 eLU、SELU 或其变体,但它的计算效率很高,因此是最常用的激活函数。
泄漏 ReLU

作者图片
ReLU 激活功能具有使负梯度归零的不期望的属性,这导致了被称为死亡 ReLU 的问题。为了解决这个问题,泄漏 ReLU 或 LReLU 通过将负值乘以值 0.01 来减小负值。
数学上,

虽然泄漏 ReLU 通常能找到更好的最优解,但它的计算开销更大,因此需要更多的时间。因此,它较少用于以速度为更重要标准且计算资源较少的任务。
参数化 ReLU
PReLU 或参数化 ReLU 将泄漏 ReLU 中的系数 x 变成一个参数,而不是一个固定的数字,可以通过反向传播来学习。这个用符号 α 写成α。当配制时,

PReLU 通常会找到比 ReLU 或 Leaky ReLU 更好的最优解,但会花费更多的历元和时间。因为它有一个额外的参数α,所以计算量很大。
s 形 ReLU
SReLU 或 S 形 ReLU 可以学习凹凸函数。具体来说,它由三个分段线性函数组成,由四个可学习的参数表示。
SReLU 是一个复杂的函数,因此它可以学习复杂性。
SReLU 被表述为

SReLU 是这个激活列表中计算开销最大的函数。这也是名单上最好的激活准确度之一。当计算资源高时,可以使用 SReLU。
正弦关系

Sine ReLU 可能是列表中最新的函数。这是怀尔德·罗德里格斯发明的。要了解这个功能,可以看中文。效果很好,值得一试。其公式为

提到的ε可以携带 0.0025 的基值,尽管他对密集层使用 0.25。
在我看来,SineReLU 在某些数据集上可以得到比以前所有函数更好的结果。这是你可以尝试的另一个功能。此外,它在计算上比 Leaky-ReLU 和 ReLU 更昂贵,尽管它可以胜过它们。
结论
选择太多了!选择哪一个最终取决于您,并且它的有效性也会随着您的应用程序而变化,所以请测试它们!随着经验的积累,你可能会对使用什么功能有一些直觉
我真的希望这对你有所帮助。如果你有任何建议,请在评论中给出反馈。
注:所有 LateX 方程式图片均由作者提供
使用 Python 手动计算 OLS 回归的系数
这是一个关于如何在不使用任何统计软件包的情况下计算 OLS 回归系数的简单演练(带有代码示例)。

我写这篇教程有两个原因。前阵子,我在想背后到底藏着什么。飞腾()和。像 scikit-learn 、 statsmodels 和无数其他库这样的流行统计软件包的 predict() 方法。在谷歌上花了相当多的时间后,我没有找到足够简单的教程,不得不自己钻研最近的统计学书籍。第二,虽然我使用 Medium 已经有一段时间了,但这是我第一次在这里写文章,我想看看它会是什么样子😀。
我将首先简要解释回归的逻辑——如果您熟悉基本概念,可以跳过这一部分。了解普通最小二乘(OLS)回归背后的理论和基本代数有助于解释结果以及理解模型的局限性。
什么是 OLS 回归?
回归是一种研究因变量和(一个或多个)自变量之间关系的方法。在一个简单的双轴图表上,单变量 OLS 回归将基本上试图通过我们观察到的数据点绘制一条“最佳拟合线”;多元回归更难想象。但是,不管预测变量的数量是多少,OLS 回归都试图找到方程的系数(通常由字母 β 表示):

让我们快速定义我们将使用的符号:
Y —因变量
X —自变量
β — OLS 系数
ϵ — 误差项
k —观测值数量
n —预测值数量
误差项 ϵ 代表我们(通常)无法完美拟合数据的事实,在我们的模型估计和数据的真实值之间会有“误差”。最小二乘回归的目标是最小化这些平方误差(因此得名):

这些系数是如何计算的?
OLS 回归的美妙之处在于,通过以矩阵形式重写上述方程并求一阶导数,可以在数值上获得最佳系数:

一阶条件给出:

正如我们所见,OLS 系数本身是 X 和y的线性组合
Python 实现
现在,说到文章的重点。为了与常用的包保持一致,我们将编写两个方法:。合体()和。预测()。我们的数据操作将使用 numpy 包进行。如果您从另一个文件导入数据,例如在中。csv* 格式,你可以使用 pandas 库来这样做。*
让我们导入模块:
*如果您决定可视化预测,matplotlib 导入将会派上用场
接下来,我们将为我们的模型创建一个类,并创建一个将 OLS 回归拟合到给定的 x 和 y 变量的方法——这些变量必须作为 numpy 数组传入。根据先前执行的向量形式推导来获得系数( np.linalg.inv() 是用于矩阵求逆的 numpy 函数,并且@符号表示向量乘法):
我们的。fit() 方法将计算出的系数存储在selfβas属性中,以允许其他方法稍后访问它们。注意,我们增加了一个可选参数截距;如果我们决定用截距来拟合我们的模型,该方法将向独立变量的数组中添加一个向量 1。
我们现在创建。预测()(方法:
*注意额外的缩进,因为这个方法是模型类的一部分
我们(非常)简单的方法利用向量乘法来获得“预测”值— y_hat 。
作为一个额外的(可选的)接触,我们可以添加一个方法来可视化地输出预测(注意:在当前的形式中,它只对带有截距的单变量回归有效):
最后,让我们执行我们使用样本数据创建的方法(如果您不想生成图形,请删除第 7 行中对 plot_predictions() 的调用,代之以在我们的。预测()方法):
如果您遵循了所有的步骤,您应该已经成功地计算出了系数,并且生成了类似于下面的内容:

如果你想玩玩代码,完整版可以从 GitHub 库这里获得。
不用说,这是一个非常基本的练习,尽管如此,它有效地说明了 OLS 贝塔来自哪里,以及它们的(数学)意义是什么。弄清楚这一点对我的进一步研究有很大帮助。最后,我前面提到的统计软件包,除了计算的系数之外,通常还会计算各种其他指标——统计显著性、置信区间、R 平方等等。这些都可以用数字来计算,但是一旦你理解了基本概念,我建议你依赖(经过良好测试的)库。
使用 SimPy 进行制造模拟
离散事件模拟
使用 SimPy 和 Python 创建吉他工厂模拟
你好。在本教程中,我们将使用 SimPy 建立一个吉他工厂!尽管这只是一个玩具示例,我们还是会介绍一些非常酷的东西,您可以用它们来进行自己的模拟。我们将把代码扔在这里,但是如果你想看最终版本,它在我的 GitHub 上。
1.简单
首先, SimPy 是什么?在文档中,他们将其定义为:“SimPy 是基于标准 Python 的基于流程的离散事件仿真框架”。你可以在这里看到完整的文档,这是我强烈推荐的。在那里你不仅可以找到你能做的事情,还可以找到很多简单但非常有用的教程。如果您没有安装 SimPy,一个简单的 pip 就可以完成:
pip install simpy
2.吉他工厂
我们将从零开始建立一个吉他工厂,从非常简单的东西开始到一个更复杂的系统。在这个例子中,我们正在制作一种类型的吉他。琴身和琴颈是分开制造的,但是由相同类型的木材制成。然后它们被传递到绘画区。之后,将琴身、琴颈和电子元件组合在一起,就制成了吉他。
让我们来看看:

让我解释一下流程图:
- 有两个主要容器。木材和电子。这些容器中有大量的木材/电子元件将在生产过程中使用。
- body make 从容器中取出一块木头,将其改造成一个身体,并将其存放在身体仓库中。同样的事情发生在脖子制造者身上,但是从一块木头上,他会得到两个脖子。颈部存放在颈部存放处。
- 油漆工挑选琴颈和琴身,上漆,存放在琴身存放处 2 和琴颈存放处 2 。
- 装配工挑选琴身、琴颈和一片电子元件,组装吉他,存放在发货集装箱中。
- 大量吉他制作完成后,商店会派人来取货。
- 当木材或电子产品的原材料低于某一水平时,就会给供应商打电话。在 T 天后,供应商到达工厂,将原材料重新装满容器。
3.密码
第 1 部分:简单模型
让我们从最简单的形式开始我们的模型:
我们开始简单地导入。之后,我们将创建类 Guitar_Factory 并添加前两个容器。请注意,我们将容器的容量设置为上面显示的变量。当然,派遣开始时是空的。如果我们用完了木材,这个过程不会停止,但也不会创造出更多的吉他。如果调度已满,也会发生同样的事情。注意 env 参数。这只是发生这一切的简单环境。我们将在后面的代码中对此进行定义。
现在我们将添加身体制造商和颈部制造商:
我们开始创造我们的第一个两个雇员。该函数有两个参数:SimPy 环境和 guitar_factory 类(注意,guitar_factory 不同于我们在前面的要点中定义的 Guitar_Factory 类)。那里发生的事情非常简单:
- 在模拟运行时,制作者将拿走一块木头(yield guitar _ factory . wood . get(1))。
- 它将在的一段时间内保持那个木块(这就是 env.timeout 函数所做的)。这模拟了将一块木头转化为吉他琴身/琴颈所需的时间。
- 在那个时间单元(在我们的例子中是 1)过去之后,制造者将把那个片段放入一个名为 dispatch 的容器中。请注意,琴身制作者将从一块木头制作一把吉他琴身。取而代之的是,琴颈制造者将从一块木头上制作出两个琴颈。因此,您可以灵活地选择您想要的原材料数量,并交付您想要的其他产品,只需更改数量即可。
最后:
我们的模拟将运行 40 小时(每个工作日 8 小时* 5 个工作日),这是在中定义的,直到= total_time 参数传递给 env.run 函数。 body_maker_process 和 neck_maker_process 将创建我们的“员工”。最后,我们添加了一个打印,这样我们就可以知道我们做了多少身体和脖子。注意,我们用guitar _ factory . dispatch . level得到那个结果。这相当于说“返回调度容器中的物品数量”:

如果你想要第 1 部分的完整代码,这里的就是。
第 2 部分:添加一些东西
现在,我们将添加油漆和组装到我们的模型。为此,我们将增加:
- 预油漆和后油漆容器,以及油漆工。
- 电子集装箱和装配工。
这里没什么新鲜的。我们增加了电子、预喷漆和后喷漆容器,并设置它们的容量。
正如我们对身体和颈部制作者所做的那样,我们创建了画师和装配工。注意,喷漆需要 4 个小时,但它同时工作超过 10 件,而组装使用 2 个后期喷漆件(1 个琴身和 1 个琴颈)加上 1 个电子件,工作一个小时后交付一把吉他。
然后,我们添加一些打印,环境过程创建和运行模拟!再次,第 2 部分的完整代码是这里。

第 3 部分:库存警报、供应商呼叫和正态分布
现在我们要添加一些非常酷的东西。系好安全带!
到目前为止,我们已经为员工的活动设定了固定的时间。比如我们说过装配工做一把吉他需要 1 个小时。按照这个参数,总是需要一个小时,一分钟也不能多,一分钟也不能少。我们都知道那不是真的。活动需要不同的时间,即使它们随着时间重复。这里我们假设时间的分布是正态的,但是你可以使用任何你想要的分布。还要注意,我们正在定义每种类型的员工数量。我们将通过导入随机库并定义进行更改所需的参数来开始这一部分:
让我们解释一下:
- num_body 设置我们将要使用的主体制造商的数量(在本例中是 2)
- 这是人体制造者用一块木头制作一个人体所需要的平均时间。
- std_body 是标准误差。
现在我们将对创建我们的雇员的函数进行更改:
很容易注意到,现在, body_time 不会总是为 1。事实上,它将是一个随机数字,取自正态分布,平均值为 1,标准误差为 0.1。还要注意 assembling_time :我们取随机 1 和 1 之间的最大值。换句话说,我们在说组装一把吉他不会少于一个小时。
我们必须改变员工的创建过程,创建一个新功能,允许我们为每种类型创建多个员工:
当然,对于 neck_maker_gen 、 paint_maker_gen 和 assembler_maker_gen 来说,这将是相同的代码。使用循环中的,我们将创建 2 个 body makers(记住我们定义了变量 num_body = 2)。因此,我们将有 2 名制衣师、1 名制颈师、1 名油漆工和 4 名装配工。
现在我们将创建库存警报和供应商调用。它是这样工作的:
- 我们的报警器将持续监控集装箱的库存量。
- 如果当前水平低于我们将定义的临界水平,它将呼叫供应商。
- 一段 T 时间后,供应商将抵达我们的工厂,用 N 数量的原材料重新装满我们的集装箱。
首先,我们需要定义我们的临界水平:
正如我们所见,木材供应商需要 2 个工作日才能到达。然后,我定义的临界水平取决于制造琴身或琴颈的平均时间、琴身制造商和琴颈制造商的数量、供应商到达的 2 个工作日,以及 1 个保证金日。我们不希望库存过多。股票是放在那里的钱,这是不好的。但我们也不想缺货,因为如果缺货发生,我们将继续为无法工作的人支付工资。临界水平是两者之间权衡,你需要自己定义。每个企业都不一样。
让我们添加警报:
我们对 init 函数做了一些修改,增加了 wood_control 和 electronic_control 进程。在我们查看木材 _ 库存 _ 控制之前,请注意电子 _ 库存 _ 控制功能不存在。该功能与 wood_stock_control 非常相似,因此您可以尝试自己创建它。如果你不能或者不想,完整的代码会在这部分的最后。
- 因此,第一个 yield env.timeout(0) 意味着一旦模拟开始,这个流程将开始执行。例如,我们可以将该值(0)更改为 8。这样,该过程将在 8 个时间单位后开始。
- 正如我们前面解释的,while True 意味着该流程将在模拟运行的所有时间内执行。
- 然后,它将检查库存水平是否等于或小于前面定义的临界水平。如果股票 es 高于该水平,它将关闭 1 个时间单位(见 else 语句)。
- 的库存水平等于或低于临界水平,将执行打印,通知在某一天和某一小时的水平是 N,并且已经进行了供应商呼叫。
- 2 天(16 小时)后,供应商到达,将重新装满 300 个木箱。这就是yield self . wood . put(300)的意思。
- 最后,打印新的库存水平,警报将关闭 1 天( yield env.timeout(8) )。
我们进行了 5 天的模拟:

第 3 部分的完整代码可以在这里找到。
第四部分。调度呼叫和容器
老实说,到目前为止,我们一直在以某种方式作弊。在身体和脖子被制作出来后,它们被存放在同一个容器里,我们把它们当作一样东西。现在我们将为每一部分实现 separe 容器,这样我们就可以正确地处理它们:
我们已经知道如何制作容器。请注意这里的两件事:吉他制造变量和 T2 调度控制变量。当然,我们需要修改制体和制颈工序:
现在,我们将车身存放在 body_pre_paint 容器中。同样的事情也发生在制颈器上。画家也需要修改:
我们现在要建立一个控制过程,就像我们在电子或木材上所做的那样。这个过程将跟踪准备发货的吉他的库存水平,并打电话给商店,让他们现在可以来取货。出于跟踪的目的,我们创建了一个名为 guitars_made 的全局变量,这样我们就可以存储商店取走的吉他数量:
我们在这里做的第一件事是用语句 global 调用全局变量 guitars_made。如果发货库存水平等于或高于 50 把吉他,我们就给商店打电话。4 个小时后,他们来挑选吉他,他们拿走所有可用的吉他,而不仅仅是我们打电话时已经准备好的 50 把。因此,当他们拿走吉他时,我们用语句guitars_made+= self . dispatch . level对我们的 guitars _ made 变量求和。然后,控制过程持续 8 小时。汇编程序也需要修改,你可以自己尝试,或者从完整代码中获取。
最后,添加一些照片并运行模拟:

我们完了。当然,第 4 部分的完整代码在开头的链接中。非常感谢你阅读我的文章,希望你能喜欢,并能从中得到一些有用的东西。
下次见!
熊猫的多种旋转方式
Pythoneers 爱好者的数据探索技巧

Tekton 在 Unsplash 拍摄的照片
Pandas 提供了无数的数据探索工具,这些工具使用起来很直观,值得一试。本文探索了这样一个工具,旋转。在许多情况下,数据是以线性表格/非透视/堆叠形式的原始状态获取的,如下所示:

使用透视更容易理解的表格数据示例
这是一种非常方便的数据处理形式,尤其是在处理 Tableau、Power BI、Qlik 等可视化工具时。大多数解释或支点,如“每个客户/日期/产品的订单”都内置于这些工具中。
这种桌子的旋转形式使得用工具可视化或用熊猫进一步处理变得乏味。但是,在某些情况下,可能需要以表格形式查看原始数据,而交叉表或透视是人眼最喜欢、最直观的显示形式。这也是从数据源提取数据的首选格式,因为它将数据压缩到更少的行中,并避免重复输入。下面是用 excel (Gesamtergebnis 的意思是总计,原谅我的德语)透视的上述数据的例子:

显示订购产品数量的透视
在这篇文章中,我将比较熊猫的各种旋转方式。Pandas 提供了以下函数来透视数据: crosstab、pivot、pivot_table 和 groupby 。对于本例,您只需要以下库:
import pandas as pd
交叉表透视
交叉表是熊猫最直观、最简单的旋转方式。它会自动计算相应行的列值的出现次数。您可以使用聚合函数(aggfunc)指定一个不同的聚合来填充这个透视。
现在,我想看看每位客户订购的每种产品的总数量(按其客户 ID):
orders_db = pd.read_excel(‘path/to/orders/orders_database.xlsx’)crosstab_pivot = pd.crosstab(orders_db.CustomerID,
orders_db.Product,values=orders_db.Quantity,
aggfunc=’sum’,
margins=True,margins_name=’Total_Qtty’).fillna(0)
交叉表的工作方式很直观。因为我们希望在数据透视表结果中看到“数量”的总和,所以我们将该列作为“总和”传递给值和聚合函数。kwargs 'margin '和' margin_name '指定我们是否希望输出包含类似于 excel 的总计列。

这里是交叉表透视表的输出
在交叉表中,如果不指定 values 参数,它将返回列值出现的频率:
crosstab_pivot = pd.crosstab(orders_db.CustomerID,
orders_db.Product,
margins=True,margins_name=’Total_Qtty’).fillna(0)

每个客户的产品出现频率
如果要将多列/多行分组到透视,只需将列作为列表传递,如下所示:
crosstab_pivot = pd.crosstab(
[orders_db.CustomerID,
orders_db.Date,orders_db.Address],
[orders_db.Product],
values = orders_db.Quantity,
aggfunc=’sum’,margins=True,margins_name=’Total
Qtty.’).fillna(0)pd.set_option('max_columns',100)print(crosstab_pivot)

多个分组列的交叉表结果
使用名为“normalize”的关键字参数,您可以选择将所有值表示为总数的百分比。包括 normalize = " index "/" columns "/" all "以将您的值规范化为总计。以下是跨列标准化的输出:

跨列标准化的输出量
带枢轴旋转
pandas 提供了一个非常基本的 pivot 函数,只有在索引-列组合是惟一的情况下才能使用。它不会对值列进行任何聚合,也不会像 crosstab 那样简单地返回一个计数。举个和上面一样的例子:

订单数据库摘录:PRSDNT +产品 A 的多个数量值
客户 ID PRSDNT 用不同的订单号两次订购了相同的产品 A 。因为 pivot 函数不执行聚合,所以它不知道在该列中为“值”填充什么。
pivot_db = orders_db.pivot(index = ‘Customer ID’,
columns = ‘Product’,values=’Quantity’)

这将适用于索引+列的唯一组合,如下例所示:

此条目对于 SHRLK1,产品组合具有唯一值
pivot_db = orders_db[orders_db.Name==’Holmes’].pivot(index =
‘Customer ID’,columns = ‘Product’,values=’Quantity’)

解决办法
当我们有这样不明确的条目时,这是现实应用程序中的大多数情况,我们使用更灵活的 pivot_table 函数,它允许聚合。
使用数据透视表旋转 _table
数据透视表功能类似于交叉表
pd.pivot_table(orders_db, values=’Quantity’,
index=[‘Customer ID’,’Address’],
columns=’Product’,
aggfunc=[‘sum’,len,’mean’],
margins=True,fill_value=0)
您还可以传递多个聚合函数,为每个聚合函数返回一组列。这里已经传递了[sum,len,mean],len 表示条目的计数。您还可以通过传递一个类似于索引列表的列表,将这种方法扩展到多个值。



使用 pandas crosstab 还是 pivot_table 是一个选择问题。请注意,您不需要将数据放在交叉表的数据框中。你也可以交叉表数组,序列等。
与分组一起旋转
Groupby 是一个非常方便的熊猫功能,你应该经常使用。让我们看看我们的是如何通过进行分组的。我们希望获得客户订购的每种产品的总数量:
方法 1:
orders_db.groupby(['Customer ID','Address','Product'])
['Quantity'].sum()

方法二:
groupedby_db = orders_db.groupby([‘CustomerID’,’Address’,’Product’]).agg({‘Quantity’:’sum’})
在这种方法中,您可以指定如何聚合每一列。(例如,如果您有另一个名为“weight”的列,您需要它的平均值,您可以将其指定为:
orders_db.groupby([‘CustomerID’,’Address’,’Product’]).agg({‘Quantity’:’sum’, ‘weight’:’mean’})
您也可以使用 groupby 的便捷过滤功能将过滤器应用到您的组中。假设您只想查看订购了至少 4 件或更多产品的客户及其地址:
big_orders = orders_db.groupby([‘CustomerID’,
’Product’]).filter(lambda x:
x[‘Quantity’].sum()>3)
该筛选器采用一个 lambda 函数参数,该参数指定特定列聚合应该满足的函数。

这是关于熊猫的基本旋转。回头见,更多熊猫黑客!
通过动画可视化数据的多种方式
通过动画增强您的数据科学演示

人们都说一图胜千言,意思是一部动画胜过千言万语。为什么?因为动画是一系列的画面,对吧?。作为人类,我们总是更关注视觉的存在,以解释我们的数据中正在发生的现象,但有时静态图片不能完全解释。这就是动画对发生的事情有意义的地方。
我们并不总是需要动画来帮助我们理解我们的数据,但是像时间序列数据这样的数据有时最好以动画的形式呈现。股票价格、每天的通话次数、一段时间内的注册百分比等等都是时间序列数据的一个例子。这些数据可以用动画来显示。

matplotlib 的股票价格动画示例
在本文中,我想介绍如何使用 Python 编程语言和各种库创建一个简单的动画来简化这个过程。这包括 Matplotlib 、赛璐珞和 Plotly 。
Matplotlib 动画
Matplotlib 是一个可视化的“祖父”库,基于 MATLAB 编程语言。许多可视化库的开发都是基于这个模块,我很确定几乎每个开始可视化研究的人都会从这个模块开始。
在 matplotlib 模块中,有一个 API 专门用于通过提供必要的基类来创建动画。有两个类,分别是FuncAnimation和ArtistAnimation。在这里,我将介绍由FuncAnimation班制作的动画,因为它是最简单的一个。
我将通过上面的股票价格动画的例子来展示这个类是如何工作的。为了准备,我们需要以下小饰品:
- 要在您的系统上将动画保存为 mp4 或 gif,需要安装FFmpeg或ImageMagick。****
- 我通过使用Yahoo _ historical模块获取股票价格数据。使用 pip 或 conda 安装模块。
现在让我们尝试创建我们的动画。首先,我们需要获得我们的股票价格数据。
****import pandas as pd
from yahoo_historical import Fetcher#Acquire our stock price data. Here I choose to take BBCA.JK stock price (BCA Indonesia Bank) from 1 January 2012 until now with 1 day interval. The data would be automatically imported as Pandas DataFrame objectBBCA = Fetcher('BBCA.JK', [2012,1,1], interval = '1d').getHistorical()BBCA.head()****

BBCA。JK 股票价格数据
为了确保我们的数据不包含任何 NaN 值,我们可以做一个快速检查。
****BBCA.isna().any()****

没有 NaN 值,有了这个数据,我们可以对数据进行预处理。因为我们想要创建一个时间序列动画,我们需要首先将数据转换成 Datetime 对象。
****BBCA['Date'] = pd.to_datetime(BBCA['Date'])****
我想把 BBCA 的高价拍成动画。JK 加班所以现在让我们从使用 matplotlib 的FuncAnimation类创建的动画开始。
****#importing libraries
import matplotlib.pyplot as plt
import matplotlib.animation as animation#Set the figure for the animation framework
fig = plt.figure(figsize = (10,6))#creating a subplot
ax1 = fig.add_subplot(1,1,1)#Preparing empty list as we want to animate the graph one data at a time rather than all at once
date = []
adjclose = []#Using FuncAnimation we need to create an animation function which return and/or done a repetitive actiondef animate(i):
#Append the empty list with the data located at the index i
date.append(BBCA['Date'].loc[i])
adjclose.append(BBCA['Adj Close'].loc[i]) #Clear the subplot each time the animate is called
ax1.clear()
ax1.plot(date, adjclose)
ax1.tick_params(axis = 'x', labelrotation = 90)
ax1.set_xlabel('Date')
ax1.set_ylabel('Price')
ax1.set_title('BBCA Stock graph with matplotlib') ani = animation.FuncAnimation(fig = fig, func = animate, frames = len(BBCA), interval = 20)
plt.show()****
在这里,我将更详细地解释 FuncAnimation 的参数。这里的重要参数是:
- 图参数作为动画的框架
- func 为每一帧调用的动画函数的参数
- 帧参数是传入 func 参数和动画每一帧的数据源。如果提供了 int,它将等同于函数 range(int)。
- 间隔参数控制每帧之间的间隔,单位为毫秒
要将动画保存为 mp4 或 gif,只需运行以下代码。
**#You could decide wheteher it is gif or mp4 by change the extension nameani.save('bbca_stock.gif', writer='imagemagick')**
或者,如果您使用 Jupyter 笔记本,并希望直接在笔记本中查看动画,您可以运行以下代码。
**from matplotlib import rc
rc('animation', html='html5')ani**

这就是如何使用 matplotlib 模块创建简单的动画。在下一节中,我将介绍简化动画创建过程的其他模块。
赛璐珞
赛璐珞 是一个简化 matplotlib 中创建动画过程的模块。我们只使用 matplotlib 中的图形,并从那里创建一个Camera类来将每个图形的快照作为一帧。动画是从帧系列创建的。

使用赛璐珞的股票价格动画示例
我们将尝试使用赛璐珞创建一个简单的股票价格动画,就像上面的例子一样。为了准备,我们需要先安装赛璐珞。
**pip install celluloid**
用赛璐珞制作动画依赖于人物的重复。想象一下,我们拍了一张连拍照片,然后从这张照片中,我们快速翻转它来创建一个动画。下面是它在代码块中的写法。
**#Importing Camera class from Celluloid module
from celluloid import Camera#Set the BBCA date as index to simplify the plotting procrss
test = BBCA.set_index('Date')#Create the figure for animation creation
fig = plt.figure(figsize = (10,6))#Create camera object by inputting the figure object
camera = Camera(fig)#Looping the plotting process and taking a snapshot for each frame. I set the loop to take 50 data each time to had a faster interval.for i in range(49,len(BBCA),50):
test['Adj Close'][0:i].plot(color = 'blue')
plt.xlabel('Date')
plt.ylabel('Price')
plt.title('BBCA Stock graph with Celluloid')
#Snap the figure in each loop process
camera.snap()
#Create the animation
animation = camera.animate()animation.save('bbca_stock_celluloid.gif', writer='imagemagick')**
阴谋地
Plotly 是一个可视化模块,号称是 ML 和数据科学模型的领先前端。从静态图形、交互式可视化到分析仪表板;Plotly 提供了所有这些。动画也包含在 Plotly 模块中,只有几行代码。
首先,我们需要安装 plotly 模块。
**pip install plotly**
在 plotly 模块中有丰富的函数,但是在我们的例子中,现在我们将使用 plotly express 来创建一个快速绘图。我们还将使用 plotly 模块中可用的人口数据。
**import plotly.express as px
df = px.data.gapminder()
df.head()**

我们的数据会像这样。我们收集了一些国家,每一次都有 5 年时间间隔,各列显示了他们的国家状况。让我们尝试使用 plotly 从这些数据中创建一个快速动画。
**#Creating animation using plotly express
fig = px.scatter(df, x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90])
fig.show()**
上述代码中需要记住的一些参数是:
- animation_frame 控制动画进度。我们首先按照从早到晚的顺序对这个值进行排序(如果您愿意,也可以反过来)。
- animation_group 用于提供跨动画帧的对象恒定性:具有匹配“animation_group”的行将被视为在每个帧中描述相同的对象。
这是我的 Jupyter 笔记本上的动画的结果。

plotly 的一个缺点是我们不能将动画导出到我们的系统中(我们可以导出静态图片,但不能导出动画)。所以,我们只有在使用 Jupyter 笔记本或者将它集成到我们的 Plotly 仪表盘时才会使用动画流程。正如我们所看到的,代码产生了一个交互式的情节,我们可以在其中播放动画(如果我们愿意,我们也可以在我们的情节中悬停)。
几乎所有由 plotly express 创建的图都提供了创建动画的能力,因此它不仅限于散点图。如果你想知道所有的情节,请参考文档。
结论
在这里,我向你展示了一个简单的方法,通过动画和几个模块来展示你的数据;这包括 Matplotlib 、赛璐珞和 Plotly 。只需几行代码和逻辑,我们就可以用一个漂亮的动画来增强我们的演示。
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
地图图层:类型和用例
深入探究地图图层的类型及其追踪地面资源和活动的用例

外卖食品
在本文中,我们将深入探讨不同类型的地图图层,以及您应该根据使用情况选择哪一种图层。因此,如果你不清楚什么时候应该使用热点图,什么时候应该使用基于网格的图层,请继续阅读!
介绍
图层是用于在地图上显示地理数据集的机制。它们包含多组点、线或面(面)要素,并定义地理数据集在地图上的符号化方式。
通俗地说,图层是指地图上某个东西的可视化。例如,点图层可用于查找旧金山所有优步行程的起点,或者弧图层可用于显示英国航空公司一天内的所有行程。
地图图层是对地图进行分析的基本单位。它不仅使数据表达更加清晰和直观,而且使地理数据的叠加成为可能。可视化和查看每个区域的数据分布,可以更容易地挖掘更深入和具体的信息,并做出更好的决策。
为什么我们需要地图图层?
1.向您的地图添加上下文
图层使地图更具上下文相关性,并帮助您关注特定方面,如资产、道路和兴趣点。地图图层使您更容易处理地图中的一组特定对象。例如,使用地图图层,您可以针对您的案例仅定位和评估一个区域中的少数几个点或建筑物。
2.帮助您更快地发现变化
地图是对地面上正在发生的事情的再现。通过地图图层,您可以看到各种测量和指标如何随着时间的推移而变化。例如,保险公司的商业地产团队可以使用它来跟踪正在修改其地产的家庭/地产所有者,或者在不同的情况下,地理科学家使用它来研究土地覆盖的变化。
地图图层的类型
我们已经根据地图层呈现的特征的数量对其进行了分类:
要点
点图层根据给定事件或对象的位置坐标(经度和纬度)为其绘制点。点图层专门用于显示地理信息分布广泛的数据&帮助您在地图上精确、快速地定位点事件。

点图层的一些属性如下:
- 颜色:点图层的颜色可以描述数值
- 填充:填充通常表示活动的强度
- 半径:半径表示一个事件或物体在地图中覆盖的区域
- 图标:图标用形状区分点。
何时使用: 点地图对于有时间戳的事件很有用,比如某个特定地区的网站流量。点是地图上精确定位位置或感兴趣点的好选择。例如,分析纽约所有优步游乐设施的起点。点地图可用于检测和跟踪道路事故等事件。
弧
弧层在两点之间绘制一条弧。弧线对于可视化两点之间的距离以及比较地图上两个位置之间的距离非常有用。弧线不显示两点之间的路径,而只显示两点之间的距离。
Arcs 地图通常用于可视化始发地-目的地流量数据。弧线通常表示起点和终点之间流动相互作用的方向和强度。

arc 图层的属性如下:
- 颜色:弧线层的颜色可以描绘一个特定的事件(起点,终点)
- 不透明度/笔画宽度:这两个可以用来显示流动相互作用的强度。
何时使用:
由于弧线层涉及到两点,并画出一条描绘两点间直线距离的弧线,所以在我们需要演示一个物体从 A 点到 b 点的往返运动的情况下,这是很有用的。
例如,arc 图层可用于描绘从特定公交车站到城市中不同地点的所有公交线路。此外,食品配送公司可以使用它们来跟踪特定餐馆的配送数量。此类地图图层可用于分析的其他一些示例包括人口迁移和航空路线。
线
线基本上是弧层的 2D 版本。两者都用线来表示地图上两点之间的距离,但如果是线,线会平放在地图上。地图的属性包括:
- 颜色:彩色内嵌地图代表观察或分析下的特定事件或物体。
- 划水:这是指水流的强度。

何时使用: 线路适用于涉及路线分配的情况,因此对于将货物从 A 点运输到 b 点的企业也很有用。物流或供应链公司就是一个很好的例子。此外,线图可以显示特定道路的交通强度,因此也可用于移动性分析。
热图
热图是表示地理范围内每个点的权重的一种方式。它可用于显示地理区域内任何现象的分布或密度变化。

热图的一个缺点是,它们只是在地图上给你一个直观的数据表示,因此没有量化区域。因此,很难确定哪些领域不存在这种现象。通俗地说,热图为您提供了地图中场景的抽象可视化。颜色表示特定点上事件强度的百分比。
何时使用: 如前所述,热图可用于可视化一种现象(疫情/干旱)的发生强度,在这种情况下,已建立的边界和边界并不太重要。
例如,假设我们代表某个特定地方的空气污染水平。较深的颜色代表有害颗粒的浓度较高,因此表明那里的空气污染更严重。它还可以用来显示特定区域的植被分布或地形的陡度。
在此阅读更多关于热图以及我们为什么不喜欢使用热图进行地理空间分析的信息。
“我们在亚马逊的成功取决于我们每年、每月、每周、每天进行多少次实验。”——杰夫…
blog.locale.ai](https://blog.locale.ai/making-location-based-experimentation-a-part-of-our-dna/)
多边形
多边形图层用于表示湖泊、城市甚至森林的边界。多边形地图为地图带来了精细的粒度,因此对于区域或城市分析非常有帮助。通常,多边形地图对于查看特定的邻域或区域非常有用。在多边形贴图中,每个区域都根据预先安排的键进行着色,每个着色或键代表一个值范围。

何时使用 :
多边形地图最适合用来显示某些特征在不同区域的分布情况。用于映射特定地区的纳税人数量或显示特定城市的销售额。它还可以用来描述特定地区的就业/失业水平。
六宾
六边形将点(或经度)聚合成六边形。因此,颜色或高度显示了事件的数量或特定六邻体蛋白的强度。在现场,我们是六边形的忠实粉丝。等等,为什么是六边形?这篇博客解释了原因:
[## 空间建模花絮:Hexbins vs Geohashes?
如果你是一个像优步一样的两度市场,你会迎合数百万通过你的司机请求搭车的用户…
blog.locale.ai](https://blog.locale.ai/spatial-modelling-tidbits-honeycomb-or-fishnets/)
一种六边形图层实际上是 H3,它使用六边形层次空间索引来可视化空间数据。由优步开源,H3 使用六边形,因为六边形减少了量化误差,当物体穿过一个地理区域时出现。点击阅读更多关于优步如何使用 H3 图层分析乘车和定价的信息。
六边形贴图的属性是:
- 颜色:在这种情况下,颜色就像显示数值的点颜色。
- 高度:这也显示了数值(也就是说,高度越大,数值越大)。然而,它们甚至可以用来显示另一个指标。
何时使用 :
六边形也可用于显示 2D 空间的分布。例如,具有特定关键字或标签的用户的推文可以沿着 X 轴代表纬度和 Y 轴代表经度的两个轴被映射到特定区域。
当必须以精细的粒度进行分析时,也使用六边形。例如,特定区域的投票率或测量特定区域的人口密度。优步还根据邻近地区司机和乘客的供需情况,使用 H3 来决定特定区域的高峰定价。
地理哈希
Geohash 基本上是一种分层数据结构,它将 2D 空间点(纬度和经度)转换为数字和字母的短字符串。他们把地球分成 4 行 8 列 32 个单元的网格。geohash 的美妙之处在于它的构造方式。简而言之,geohash 是一种格网空间索引,通过每增加一位,世界被递归地划分为越来越小的格网
S2 图层实际上是一种表示三维球体上地理空间数据的 geohash。由谷歌开发的 S2 图层使得使用单一坐标系统建立一个没有水流或奇点的低失真的全球地理数据库成为可能。
S2 图层对于空间索引和作为像元集合的近似区域非常有用。它在显示建筑物结构或人口密度的地方非常有用。有趣的是,S2 基本上是一种动态形式的点地图,其中事件的值/强度随时间而变化。S2 层利用了一个非常聪明的构造,称为希尔伯特曲线,它基本上是一条占据空间的曲线,覆盖了该空间内的所有区域。使 S2 与众不同的一个原因是,它能够将任意区域近似为离散的 S2 单元的集合。正是这个特性使得构建大型分布式空间索引变得非常容易。

何时使用: S2 地图图层的一个很好的用例是追踪一段时间内商品房的增加或追踪房地产建设项目。它还可以用于查找在禁止区域建造的或高度超过允许限制的非法建筑
流程图
流图基本上是随时间变化的弧图/层。它们用于可视化起点/终点流量数据。起点和终点可以是点或曲面。线/弧的宽度或颜色表示起点和终点之间的流向值。每个空间点要么是起点,要么是终点。
何时使用: 流图是绘制和可视化交通流量、人口迁移以及物流公司车队管理的好选择。

类似阅读:
今天,每个人都使用谷歌地图导航到任何地方。同样,为什么不是每个公司都应该有自己的地图…
blog.locale.ai](https://blog.locale.ai/how-analyzing-supply-demand-gaps-can-optimize-your-unit-economics/) [## 使用地理空间数据了解微观移动模式
我的用户如何在这个城市移动?他们去哪里了?这个城市的“流”是什么样子的?这是如何改变的…
blog.locale.ai](https://blog.locale.ai/understanding-micro-mobility-patterns-using-geospatial-data/)
在现场,我们正在构建一个“”运营分析平台,使用位置数据为按需公司的供应和运营团队服务。如果你想进一步钻研,可以查看我们的 网站 out 或者在LinkedIn或者Twitter上与 Aditi 取得联系。**
使用 Valhalla 的 Meili 进行地图匹配
处理 GPS 误差的生产就绪解决方案

作者图片
GPS 不够精确的问题并不新鲜,“捕捉到道路”功能主要是将 GPS 轨迹与道路进行匹配。大多数有这个问题的项目都是通过谷歌地图道路应用编程接口或者 OSRM 匹配服务应用编程接口来解决这个问题。但我要向你展示我走过的路,我没有后悔任何事。
问题
我的主要问题是计算汽车每天和每月行驶的距离。同样重要的是,我试图构建一个可以每天都这样做的生产解决方案,而不仅仅是研究部分。
因为我在 GeoJSON 中已经有了多个预处理的 GPS 轨迹,所以我创建了一个 Python 脚本,它使用geopy.distance.geodesic函数计算距离,并在整个行程的地理点上循环。据我粗略估计,这种方法有时会有超过 30%的错误率,这实际上是非常可怕的。我来解释一下原因。
如下图所示,有时 GPS 追踪并不精确。显然,司机使用的是这里的道路,但我们从 GPS 上获得的地理点位于道路附近,而不是道路上。

作者图片
解决办法
首先,我想自己解决这个问题。我认为这可以通过一些数学计算来完成,但谢天谢地,我很快就明白了这个问题更多的是在进行数学计算之前从哪里获得道路的坐标,并发现 OSRM /谷歌地图 API 可以为我完成整个过程。
谷歌地图 API 并没有让我感到惊讶,因为它只能在他们的 Snap to Roads 方法中获得最多 100 个地理点,这对于汽车的 GPS 跟踪来说是非常低的。另一方面,OSRM API 看起来不错,直到我偶然发现瓦尔哈拉。
瓦尔哈拉殿堂
正如他们的 GitHub 知识库中完美指出的,Valhalla 是一个开源路由引擎和附带的库,用于 OpenStreetMap 数据。Valhalla 还包括时间+距离矩阵计算、等时线、高程采样、地图匹配和旅游优化(旅行推销员)等工具。
以下是我能想到的使用瓦尔哈拉的好处:
- 并行化。您可以在不同的服务器上使用不同的地图安装。例如,您有法国和德国的用户,您可以在服务器 1 中设置法国地图,在服务器 2 中设置德国地图,并根据您的业务逻辑向它们中的任何一个发送代理请求。此外,你可以建立一个大的星球地图或几个大陆地图,无论哪个最适合你——瓦尔哈拉已经准备好了。
- 定制。您可以管理自己的配置,使用许多可选参数请求信息,这些参数实际上可以引导您找到更好的解决方案。
- 性能。Valhalla 是用 C++写的。说真的。还需要我多解释吗?它快得惊人。
- 本地化。我主要对路线步骤的英语、俄语和印地语本地化感兴趣,并惊讶地在瓦尔哈拉看到所有这些。
- 易于安装。Valhalla 可以安装在各种平台上:Ubuntu、Debian、苹果 macOS 和微软 Windows。
- 开放性。贡献是允许的,也是受欢迎的。麻省理工许可下的开源。
魅力
梅里是瓦尔哈拉内部的主要模块之一。它的功能是执行地图匹配(捕捉道路功能),这正是我需要解决我的问题。
为了简要说明其工作原理,Meili 首先在给定位置的给定半径内找到最近的候选路段,然后在隐马尔可夫模型(HMM)的上下文中使用维特比算法检测最高概率地图匹配(维特比路径)。
我不打算用这些算法的细节以及如何在您的机器上设置 Valhalla 和运行服务器的信息来填充这篇文章。在 GitHub 上有很完美的解释,建议你为此去一趟。
而是让我们实际一点,用 Python,熊猫和 Valhalla 的 Meili 来修复我们的 GPS 痕迹。
数据
为了简化这个例子,我将使用包含这些列的 Pandas 数据帧(df_trip ):
- 经度
- 纬度
- 时间(日期时间)
我的示例由 82 行组成,代表实际 GPS 轨迹的地理点:

作者图片
向 Meili 发送请求
让我们准备一个请求的正文:
现在让我们添加头并对本地服务器执行一个实际的请求:
这里有一个服务器日志,上面有瓦尔哈拉的正确回应:
如果瓦尔哈拉没有回复 200,主要是因为:
- GPS 追踪实际上并不在公路附近。
- GPS 跟踪是在我们没有为其构建磁贴的国家进行的(回到 Valhalla 的 GitHub ,用正确国家的 pbf 文件重新做 README 的“运行”部分)。
- GPS 轨迹有缺陷(例如,多条轨迹合并为一条,时间和坐标相差很大)。
处理响应
我用这个代码来处理来自 Meili 的响应。它并不漂亮,但很有效:
下面是这段代码的结果:

作者图片
结果增加了 3 个新列:
- name —它包含我们的司机当时使用的街道名称。很酷,如果你问我。
- 距离——Valhalla 也计算了地球点之间的距离,这完美地解决了我在本文中为自己设定的首要目标。
- 位置——这一列包含了我们从梅里(抓拍到马路上)得到的坐标。
要保存无法捕捉到任何道路的地理点(例如,停车场上的一些运动),您可以使用此代码来解析我们之前从 Meili 获得的“位置”列:
结果
因此,我们有一个非常整洁的 GPS 跟踪,捕捉到实际的道路,如下所示:

作者图片
让我们结合两种 GPS 轨迹(优化的和非优化的)来看看区别:

作者图片
最后的话
我选择 Valhalla 而不是 OSRM API 的主要原因是,Valhalla 是一个生产就绪的解决方案,还有许多其他好处。
出于快速研究的目的,您可以使用 OSRM API 而不是 Valhalla,因为您可以在没有预先设置环境的情况下完成这项工作。
我想对所有 Valhalla 的贡献者说一声非常感谢。尤其是《魅力》的创作者,https://github.com/ptpt()和凯文·克莱泽(https://github.com/kevinkreiser)。你们太棒了。
希望这篇文章对你有所帮助。欢迎在 LinkedIn上联系我或者在下面留言。
你也可以探索完整的 Jupyter 笔记本,通过一些小的添加来解决这个问题。
mAP(平均精度)可能会让你困惑!
剧透警告:地图不是精度的平均值。

问号(Jules Bss 在 Unsplash 上拍摄的照片)
如果把 mAP(平均精度)理解为精度的平均值,这是可以理解的。然而,你不能远离事实!
让我解释一下。
在计算机视觉中,mAP 是用于对象检测(即,定位和分类)的流行评估度量。本地化决定了一个实例的位置(如边界框坐标),分类告诉你它是什么(如狗或猫)。

图像分类和定位
许多对象检测算法,如更快的 R-CNN、MobileNet SSD 和 YOLO,使用 mAP 来评估他们的模型,以发布他们的研究。
你可能会问,如果这是一个如此受欢迎的指标,为什么它仍然令人困惑?
很公平!
mAP 代表平均精度(看标题你可能已经猜到了)。
你可能认为这是精度的平均值。
如果您还不知道:
精确度衡量你的预测有多准确。即你的预测正确的百分比。
它衡量你的模型做出的预测有多少是正确的。

TP =真阳性(预测为阳性且正确)
FP =假阳性(预测为阳性,但不正确)
如果是这种情况,让我们为下图计算贴图:

高级驾驶员辅助系统(ADAS)的物体检测示例
从图像中,我们得到:
真阳性(TP) = 1
假阳性(FP) = 0

因为我们只有一个值,所以平均精度是 1。
查看地图得分,您可能最终会在应用程序中使用该模型。那将是一场灾难。
这就是问题所在!不要让这个术语误导你。
mAP 不是通过取精度值的平均值来计算的。
对象检测系统根据边界框和类别标签进行预测。

物体检测示例检测到一只猫(原始猫照片由 Kote Puerto 在 Unsplash 上拍摄)
对于每个边界框,我们测量预测边界框和地面真实边界框之间的重叠。这通过 IoU(并集上的交集)来衡量。

对于对象检测任务,我们使用给定 IoU 阈值的 IoU 值来计算精度和召回率。
例如,如果 IoU 阈值为 0.5,预测的 IoU 值为 0.7,则我们将该预测归类为真正(TF)。另一方面,如果 IoU 为 0.3,我们将其归类为假阳性(FP)。

这也意味着,对于一个预测,通过改变 IoU 阈值,我们可能会得到不同的二进制真或假阳性。

另一个需要理解的重要术语是回忆。
回忆衡量你发现所有积极因素的程度。例如,我们可以在我们的前 K 个预测中找到 80%的可能正例。

TP =真阳性(预测为阳性且正确)
FN =假阴性(未能预测到那里的物体)
平均精度(AP)的一般定义是找到上述精度-召回曲线下的面积。
mAP (mean average precision)是 AP 的平均值。
在某些情况下,会为每个类别计算 AP 并进行平均以获得地图。但在其他情况下,它们的意思是一样的。比如对于 COCO 挑战评测,AP 和 mAP 没有区别。
AP 是所有类别的平均值。传统上,这被称为“平均平均精度”(mAP)。我们不区分 AP 和 mAP(AR 和 mAR 也是一样),并假设这种差异在上下文中很明显。可可评价
根据存在的不同检测挑战,通过对所有类别和/或总 IoU 阈值取平均 AP 来计算平均精度或 mAP 分数。
在 PASCAL VOC2007 challenge 中,一个对象类的 AP 是针对 0.5 的 IoU 阈值计算的。所以贴图是所有对象类的平均值。
对于 COCO 2017 挑战赛,该地图是所有对象类别和 10 个 IoU 阈值的平均值。

4 个对象类别的 SSD 模型的精度-召回曲线,其中 IoU 阈值为 0.5。范·埃滕(2019 年 1 月)
因此,对于上面的 ADAS 图像,让我们使用实际公式来计算地图:
这里我们假设置信度得分阈值为 0.5,IoU 阈值也为 0.5。
因此,我们计算 IoU 阈值为 0.5 时的 AP。
为简单起见,我们将计算 11 点插值 AP 的平均值。在最新的研究中,更先进的技术已被引入计算 AP。
真阳性(TP) = 1
假阳性(FP) = 0
假阴性(FN) = 1


我们绘制了 11 点插值的精确召回曲线。

我们现在通过 PR 曲线下的面积来计算 AP。这是通过将召回平均分为 11 个部分来实现的:{0,0.1,0.2,…,0.9,1}。

所以图像的 mAP@0.5 是 0.545,而不是 1。
希望这能澄清你对地图的误解。
原载于【www.xailient.com/blogs】
想训练和评估一个计算机视觉模型?点击这里。
找一个预先训练好的人脸检测模型。点击此处下载。
查看这篇文章了解更多关于创建一个健壮的对象检测模型的细节。
参考文献:
范·埃滕,A. (2019,1 月)。利用窗口网络的卫星图像多尺度快速探测。在 2019 年 IEEE 计算机视觉应用冬季会议(WACV) (第 735–743 页)。IEEE。
编辑描述
cocodataset.org](http://cocodataset.org/#detection-eval)
http://host.robots.ox.ac.uk/pascal/VOC/
如果你评估过物体探测的模型,或者读过这方面的论文,你可能会遇到平均…
medium.com](https://medium.com/@timothycarlen/understanding-the-map-evaluation-metric-for-object-detection-a07fe6962cf3) [## 分解平均精度(mAP)
在这种情况下,AP 所做的是惩罚那些不能用 TPs 引导集合来排序 G '的模型。它提供了一个…
towardsdatascience.com](/breaking-down-mean-average-precision-map-ae462f623a52#1a59)
作者
萨拜娜·波克尔*
绘制 2019-20 澳大利亚森林火灾
一个案例研究,展示了如何通过 5 个简单的步骤使用深度学习从卫星图像中监控火灾的日常进展

澳大利亚东海岸的丛林大火。图片来自 NASA 。
2019-20 澳大利亚森林大火的极端程度在 2020 年初成为世界各地的头条新闻。在气候变暖的情况下,像这样的极端事件预计会变得更加频繁。监控火灾的程度对于评估损失非常重要,对于从森林管理到火灾碳排放和空气污染的广泛应用也是如此。分辨率高达每像素约 500 米的日常卫星图像有助于监测燃烧区域。然而,这并不是一项简单的任务,因为图像中经常出现云和烟雾。作为一个基于图像的问题,监测烧伤区域的日常进展是计算机视觉领域的一项非常适合的任务。
在这个故事中,我展示了如何使用 BA-Net 模型(我是该模型的作者之一)来绘制澳大利亚的火灾地图,以及如何使用Github 资源库中提供的开源代码和预先训练的模型作为名为 banet 的 Python 包,在地球上的几乎任何地方做同样的事情。
如果您只对结果感兴趣,在 5 个步骤之后,您可以直接跳到“可视化结果”部分。
第一步。定义研究区域
banet . geo中的 Region 类应该如下使用,其中 bbox 参数接收一个带有区域左、下、右、上边界的列表。 pixel_size 应保持为 0.01(约 1 公里),以接近这里将使用的卫星数据的分辨率。
r **=** Region(name**=**'Australia', bbox**=**[146, **-**39, 154, **-**26], pixel_size**=**0.01)
r**.**export('data/regions/R_Australia.json')
步骤二。下载 VIIRS 现行火灾数据

研究区域内活跃火灾的散点图。作者创造的形象。
VIIRS Active Fires 是一种产品,提供对卫星通过期间活跃的火的辐射功率的近实时估计。这些极地轨道卫星一天两次观察地球上的大部分地点。数据可以从页面下载;在“创建新请求”之后;选择区域;选择“VI IRS S-NPP”;选择研究周期(或至少 15 天)前一个月开始和后一个月结束的时间范围。至于文件格式,应该是选择 CSV。提交请求后,应该会很快得到处理。然后可以下载数据并保存为“热点{name}”。csv”,使用步骤 1 中定义的“名称”。
绘制所有活动火灾事件的结果如上图所示,其中颜色代表从 2019 年 1 月 1 日开始计数的燃烧日。
****第三步。下载 VIIRS 图像数据
下面的 bash 代码利用 banet 命令行实用程序从 Nasa 地球数据下载数据。
#!/bin/bash -l
region**=**"Australia"
tstart**=**"2019-08-01 00:00:00"
tend**=**"2020-02-17 23:59:59"
path_save**=**"/data/Australia/rawdata"
regions_path**=**"/data/regions"
banet_viirs750_download $region "$tstart" "$tend" $path_save $regions_path
需要将 region 变量设置为步骤 1 中定义的名称,并将 regions_path 设置为保存 JSON 文件的相应目录。
第四步。数据预处理
对于这一步,banet 包中提供了另一个实用函数。该程序包括读取步骤 3 中下载的原始数据(HDF 格式),并保存每天的 mat 文件,包括:
- 红色、近红外(NIR)和中红外(MIR)反射率;
- 网格化活跃火灾数据。
#!/bin/bash -l
region**=**"Australia"
viirs_path**=**"/data/Australia/rawdata"
save_path**=**"/data/Australia/dataset"
fires_path**=**"/data/ActiveFires"
regions_path**=**"/data/regions"
banet_create_dataset $region $viirs_path $fires_path $save_path $regions_path
注意 fires_path 应该设置为保存步骤 2 中获得的 CSV 文件的目录。
第五步。使用 BA-Net 生成烧毁区域地图
同样,banet 包提供了一个实用的命令行函数来处理这个步骤。该过程包括加载 64 天的序列,并将大图像裁剪成 128×128 的图像块,将每个图像块输入到模型中,然后合并这些图像块以获得整个图像的结果。
#!/bin/bash -l
region**=**"Australia"
tstart**=**"2019-08-01 00:00:00"
tend**=**"2020-02-17 23:59:59"
input_path**=**"/data/Australia/dataset"
output_path**=**"/data/Australia/output"
regions_path**=**"/data/regions"
banet_predict_times $region "$tstart" "$tend" $input_path $output_path $regions_path
注意输入路径应该对应于步骤 4 的保存路径——数据集存储的目录。
可视化结果
完成上述 5 个步骤后,结果将保存在输出路径中。下图显示了模型给出的置信水平(左)和燃烧日(右)。此后,仅考虑置信水平至少为 0.5 的像素。

从 BA-Net 模型获得的置信水平图(左)和燃烧天数图(右)。作者创造的形象。
请注意,燃烧日期的进展通常是平稳的,与其他现有产品形成对比,如本故事或 BA-Net 学术论文中所讨论的。燃烧日期的改进使得每日燃烧面积的表示更加准确,如下图所示。

所有研究区域的每日燃烧面积。作者创造的形象。
请注意 2019 年底和 2020 年初烧毁面积的极值——这是澳大利亚火灾成为全球头条新闻的时期。
柱状图代表的总过火面积为 6 688 147 ha 。相比之下,维基百科中提到的新南威尔士州、维多利亚州和澳大利亚首都直辖区的总面积为 6 956 688 公顷。这些数字不能直接比较,因为这里我们包括了南昆士兰的小火灾,并且只考虑了维多利亚州的一部分。然而,这是一场势均力敌的比赛。
在这个尺度上,可能会高估燃烧区域,因为燃烧区域内通常有较小的未燃烧区域。为了更好地识别这些区域,需要更高分辨率的图像,如 Sentinel-2 (10 米像素大小)。然而,这些图像每 5 天才有一次,无法绘制火灾的每日进展情况。
前进的道路
最近几年,遥感数据的深度学习应用开始蓬勃发展。我相信这种趋势在可预见的未来将会继续。我预计在接下来的几年里,火烧区测绘将会是一个有重大进展的课题。从几颗卫星上不断检索的时空数据量之大使得这个问题具有挑战性。由 GPU 和 TPUs 驱动的深度学习为大量有待探索的新可能性开辟了道路。
关于我
** [## 我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…
towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7)
感谢阅读!祝您愉快!**
用 Python 绘制鳄梨价格图
使用 GeoPandas、GeoPy 和 Matplotlib 制作美丽的 choropleth 地图。

来自 Pexels 的彼得·德·温克的照片
我喜欢鳄梨。它们美味又健康,我喜欢吃。我知道这使我成为一个千年的基本陈词滥调,但是心想要心想要的!当我在 Kaggle 上看到 Justin Kiggins 发布的鳄梨价格数据集时,我立刻想看看它,玩玩它。这包含由 Hass Avocado Board 编辑的关于 2015 年至 2018 年间美国鳄梨销售的信息。
这个数据集中包含了很多有用的信息,我可以选择一些不同的东西来探索(也许以后我还会这样做)。我在 twitter 上看到了一些很酷的 choropleth 地图,想尝试一下。我发现每个价格观察都与一个特定的地区相关联,于是我决定试试能否以某种方式将这些信息从文本形式转换成地图形式。

剧透:我可以!
在这篇文章中,我将带你一步一步地了解我是如何做到的,你可以在这里找到我的包含代码的完整 Jupyter 笔记本。这是我第一次尝试使用 Python 制作这种地图,所以我欢迎所有关于我如何使这个过程更容易的反馈和想法!
导入和简化数据
让我们开始吧!我做的第一件事是导入我的库和数据本身。使用 pd.read_csv()直接从 csv 文件创建熊猫数据帧。
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as pltdata = pd.read_csv('avocado.csv', index_col = 'Date')
这给了我们一个很好的数据框架。

但是现在对我们来说这些信息太多了。我想制作一个包括价格和地区数据的地图(也许以后会对数量和年份做些什么),所以让我们去掉很多列。
columns_to_drop = ['Unnamed: 0', '4046', '4225', '4770', 'Total Bags', 'Small Bags', 'Large Bags', 'XLarge Bags', 'type']avo_df = data.drop(columns_to_drop, axis=1)

显示(avo_df.head())
不错!那更精简。做一些探索性的数据分析让我对我正在查看的数据集有了一个概念,数据集中一个鳄梨的最高价格是 3.25 美元(!)—最便宜的是 0.44 美元——便宜了 7 倍多。那是某种变异!在我们的数据集中,一个鳄梨的中值价格是 1.37 美元,平均值是 1.41 美元,标准差是 0.40 美元。这给出了数据中价格分布的概念。
视觉上做一些 EDA 总是有帮助的。这里有一个 AveragePrice 柱的直方图,让我们对总体分布有一个更清晰的感觉。

不一定要很漂亮,别担心。
为了制作我想要制作的地图(显示每个地区鳄梨价格的 choropleth,以清楚地显示价格的地区差异),我想要将每个地区许多不同的价格测量值合并为一个值。探索同比或销量的差异可能会很有趣(谁买的鳄梨最多?),但要回答我给自己定的问题,我想把这些都压下去。
这里有几个选择,但我认为最清楚和最诚实的方法是取所有平均价格数据的简单平均值,按地区分组。我们如何做到这一点?
首先,我们需要识别所有的区域。
regions = avo_df.region.unique()
这为我们提供了数据集中包含的所有区域的列表:
['Albany' 'Atlanta' 'BaltimoreWashington' 'Boise' 'Boston'
'BuffaloRochester' 'California' 'Charlotte' 'Chicago' 'CincinnatiDayton' 'Columbus' 'DallasFtWorth' 'Denver' 'Detroit' 'GrandRapids' 'GreatLakes' 'HarrisburgScranton' 'HartfordSpringfield' 'Houston' 'Indianapolis' 'Jacksonville' 'LasVegas' 'LosAngeles' 'Louisville' 'MiamiFtLauderdale' 'Midsouth' 'Nashville' 'NewOrleansMobile' 'NewYork' 'Northeast' 'NorthernNewEngland' 'Orlando' 'Philadelphia' 'PhoenixTucson' 'Pittsburgh' 'Plains' 'Portland' 'RaleighGreensboro' 'RichmondNorfolk' 'Roanoke' 'Sacramento' 'SanDiego' 'SanFrancisco' 'Seattle' 'SouthCarolina' 'SouthCentral' 'Southeast' 'Spokane' 'StLouis' 'Syracuse' 'Tampa' 'TotalUS' 'West' 'WestTexNewMexico']
现在我们想用这个列表对我们的数据框架进行分组,得出每个地区的平均价格值
group_by_region = avo_df.groupby(by=['region'])
avo_df_avg = group_by_region.mean()
avo_df_avg = avo_df_avg.drop(['year'], axis=1)
这应该能行。
使用 GeoPy 进行地理编码
现在我们每个地区都有一个价格值,但是每个地区都存储为文本,例如' Albany ',' SanDiego ',' Roanoke '等。Matplotlib 很聪明,但还不足以聪明到仅仅根据文本在地图上绘制这些内容。我们需要找到一种方法从这些地名中获取地理数据(具体来说,是坐标)。
嗯,我们不是第一个想这么做的人!我们可以使用 GeoPy 的地理编码特性来实现这一点。在玩了一段时间后,我用了 Bing 地图(它可以免费获得一个 API 密钥,我可以让它工作!),但是还有其他可用的地理编码服务,所以可以随意尝试。
from geopy.geocoders import Bing
from geopy.extra.rate_limiter import RateLimitergeolocator = Bing(api_key='[GetYourOwnAPIKeyYouScallywag](https://docs.microsoft.com/en-us/bingmaps/getting-started/bing-maps-dev-center-help/getting-a-bing-maps-key)', timeout=30)
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=2)regions_dict = {i : geolocator.geocode(i) for i in regions}
我发现使用 RateLimiter 有助于避免过多的请求使 API 过载,但是它会显著增加请求运行的时间,并且对您来说可能是不必要的,所以请记住这一点。
这将返回一个充满信息的字典,我们只需要其中的坐标。我们可以使用以下步骤将其转换为准备好加入现有数据框架的数据框架:
regions_df = pd.DataFrame(regions_dict)
regions_df_melted = regions_df.iloc[1:2,:].melt()
regions_df_melted.columns = ['region', 'co-ordinates']
这是产生的数据帧的头部。

现在,我们的数据集中有了每个地区的坐标,我们希望将其加入到现有的数据框架中,这样我们就有了一个包含每个地区的平均价格和坐标的数据框架。令人高兴的是,pandas 使用其合并功能使这变得非常容易。谢谢,熊猫们!
df = pd.merge(avo_df_avg, regions_df_melted, left_on='region', right_on='region')
我们的下一步是将所有这些整合在一起,创建一个 GeoPandas 地理数据框架,其中包含每个地区的平均价格,以及我们在地图上绘制每个地区所需的地理信息。要做到这一点,我们首先需要创建一个纬度列和一个经度列(GeoPandas 非常合理地希望获得这些信息来创建它的“geometry”列,这是它存储地理数据的方式)。
df[['latitude', 'longitude']] = pd.DataFrame(df['co-ordinates'].tolist(), index=df.index)avo_gdf = gpd.GeoDataFrame(
df, geometry=gpd.points_from_xy(df.longitude, df.latitude))
太好了!现在我们有了一个包含所有数据的地理数据框架。让我们快速看一下它是什么样子的!
avo_gdf.plot()

嗯,这个我还不确定。
好吧——我承认这看起来还不太鼓舞人心,但我向你保证,我们会成功的!如果你眯着眼睛看,你会发现大部分数据看起来确实像是在美国。我们在右下角有一个异常值,稍后会解释和处理。
但是现在,从现在开始!
使用 Shapely 显示地图,作为显示我们感兴趣的数据的基础
正如我们在上面看到的,仅仅得到我们的地理数据框架并不能立即产生我们梦想中的美丽的 choropleth。我们需要给 Python(和 Matplotlib)关于我们想要如何呈现这些信息的指令。毕竟,我们是数据分析师,我们正在决定如何呈现我们的数据,并且有大量的方法可供我们选择。这种灵活性意味着我们还有一些工作要做!
因此,我们希望将鳄梨价格的地理数据框架叠加到美国大陆的地图上。我们如何做到这一点?有一个非常有用的 Python 库叫做 shapely,可以在这里帮到我们。mattymecks 有一个关于所有这些东西的超级有用的帖子在这里——如果你想弄明白这一点,我强烈建议读一读整篇帖子。
形状文件将形状存储为多边形,它只是一系列相互连接的坐标。因此,一个三角形将被保存为由它们的坐标标识的 3 个点,一个正方形由 4 个点标识,而更复杂的形状由数千个或更多的点标识。
无论如何,对于我们的目的,你只需要知道形状文件存在,并能提供我们正在寻找的地图。但是去哪里找最好的呢?当然,最好的方法是用疯狂的谷歌搜索,但是我也许可以帮你省点劲,给你指出美国人口普查局提供的老虎/线条轮廓。如果那些家伙不知道美国各州、领土和领地的形状,那么我不知道谁会知道!
下载这些文件,解压并保存在你的活动文件夹中。然后从 Shapely 导入点和多边形,你就可以开始摇滚了!
from shapely.geometry import Point, Polygonusa = gpd.read_file('tl_2017_us_state.shp')
好吧,我们来看看那个坏男孩。
usa.plot()

好吧——不完美,但我们正在努力。
我们可以在这里看到我们所需要的基础。为什么这张地图有这么多空白?我以为美国只是在西半球?好吧,这里不涉及太多的地缘政治细节,我们只说有一些属于美利坚合众国的领土在我们首先想到的其他地理位置。
让我们仔细看看这里的形状数据。
print(usa.shape)
print(usa.NAME)----(56, 15)0 West Virginia
1 Florida
2 Illinois
3 Minnesota
4 Maryland
5 Rhode Island
6 Idaho
7 New Hampshire
8 North Carolina
9 Vermont
10 Connecticut
11 Delaware
12 New Mexico
13 California
14 New Jersey
15 Wisconsin
16 Oregon
17 Nebraska
18 Pennsylvania
19 Washington
20 Louisiana
21 Georgia
22 Alabama
23 Utah
24 Ohio
25 Texas
26 Colorado
27 South Carolina
28 Oklahoma
29 Tennessee
30 Wyoming
31 Hawaii
32 North Dakota
33 Kentucky
34 United States Virgin Islands
35 Commonwealth of the Northern Mariana Islands
36 Guam
37 Maine
38 New York
39 Nevada
40 Alaska
41 American Samoa
42 Michigan
43 Arkansas
44 Mississippi
45 Missouri
46 Montana
47 Kansas
48 Indiana
49 Puerto Rico
50 South Dakota
51 Massachusetts
52 Virginia
53 District of Columbia
54 Iowa
55 Arizona
Name: NAME, dtype: object
我们已经确认我们的鳄梨价格数据仅限于美国大陆(除了一个奇怪的异常值,我保证我们会发现),所以我们可以去掉一些其他条目。
to_drop = ['Commonwealth of the Northern Mariana Islands', 'United States Virgin Islands', 'Hawaii', 'Alaska', 'Guam', 'Puerto Rico', 'American Samoa']for index, row in usa.iterrows():
if row['NAME'] in to_drop :
usa.drop(index, inplace=True)usa.plot()

这还差不多!
现在,我们已经准备好了美国的形状文件来形成我们地图的基础,并且我们已经有了地理位置上的价格数据,可以开始了。但是,有一些奇怪的事情正在发生,特别是我们地图上的那个异常值。现在是时候对此进行调查,并对我们的数据进行一些合理性检查了。
清理我们的数据—最后一步
如果我们显示整个数据框(这里太大了,无法显示,但如果您在家继续,我鼓励您这样做),我们可以看到,我们的一些坐标是南向的(例如,25 号入口——中南部),一些是可疑的圆形(例如,29 号入口——东北),还有一些偏离很远(例如,52 号入口——西部——这是我们在地图上的异常值!).这里发生的事情是,我们来自 Hass Avocado Board (通过 Justin Kiggens )的原始 CSV 文件包含一些主要地区(如中南部、东北部和西部)的一些元地区汇总数据。
当我们使用我们的地理定位器(在我们的例子中是 Bing 地图,但是这个问题会发生在我们使用的任何一个服务上)时,这个服务尽力提供一个精确的位置。在某些情况下(如中南大学)它不能,所以我们最终与南。在其他地方(如东北),它发现了一些非常普遍的东西,并随之而来。在另外一些地方(比如 West ),它能够定位到具有该名称的某个地方,但不是我们要寻找的地方(在这种情况下,它返回赞比亚 Western 的坐标)。这就是为什么在可能的情况下通过用不同的方式绘制数据并调查看起来可疑的事情来检查数据是很重要的。
就我们的目的而言,我们不需要这个元区域数据,所以我们可以一起删除它。
to_drop = ['Midsouth', 'Northeast', 'Plains', 'SouthCentral', 'Southeast', 'TotalUS', 'West']for index, row in avo_gdf.iterrows():
if row['region'] in to_drop :
df.drop(index, inplace=True)
通过 Matplotlib 将所有这些整合在一起
既然我们已经改进了 df,我们的数据框架,我们已经将 shapefile 保存为 usa,让我们使用相同的 CRS — 坐标参考系统将它们放在一起。这将确保我们的地理数据框架使用相同的参考系统,因此只要我们每个地区的坐标是准确的,它们就会准确地显示在美国地图上。这里我使用了 epsg:4326 ,因为 Shapefile 已经在使用它了。
crs = {'init': 'epsg:4326'}
avo_gdf = gpd.GeoDataFrame(df, crs=crs)
usa_gdf = gpd.GeoDataFrame(usa, crs=crs)
就是这个!我们准备好出发了!
借助来自 Matplotlib 的一些漂亮的特性,我们可以让它变得非常漂亮。
from mpl_toolkits.axes_grid1 import make_axes_locatable
# This is a function to allow us to make the legend prettyfig, ax = plt.subplots(figsize = (20,16))
plt.title('Avocado Prices by region in the United States', fontsize=26, fontfamily='serif') #this part makes the legend the same size as our map, for prettiness
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1) usa.boundary.plot(ax=ax, color='DarkSlateBlue')
# using the boundary method here to get the outlines of the states, an aesthetic decisionavo_gdf.plot(cmap='Greens', column='AveragePrice', legend=True, ax=ax, s=2000, alpha=0.7, cax=cax) # this saves a copy of the viz as a jpg so we can easily share it with our friends on twitter!
plt.savefig('Avocado Prices.jpg', format='jpg')

瞧啊。
现在我们已经实现了美丽的 choropleth,直到现在只存在于我们的梦想!恭喜我们!看起来我们想避开美国东北部和旧金山,而是去俄亥俄州或德克萨斯州过廉价鳄梨的生活。
我希望这有助于您了解我们如何使用 GeoPandas、GeoPy 和 Matplotlib 中的一些强大工具来获取文本和数字形式的数据,使用 API 来查找坐标,然后创建一个吸引人且清晰的可视化效果,向人们展示我们想要突出显示的信息。
非常感谢您抽出时间陪我踏上这段旅程。我随时欢迎您的反馈——请通过 Twitter @ craigdoedata 与我联系,并告诉我如何才能更有效地完成这项工作!我仍然在学习,我也想知道你的秘密,所以请与我分享。
同样,整个 Jupyter 笔记本和相关文件都在我的 Github 页面上,我鼓励你使用它们。
下次见!

更像这样?访问craigdoedata . de
测绘普查数据
如何在 Python 中访问和映射人口数据

瑞安·威尔森在 Unsplash 上拍摄的照片
根据 2010 年的人口普查,今天我来看看西雅图的种族构成。为此,我将使用综合公共使用微数据系列 ( IPUMS)国家历史地理信息系统(NHGIS)。你也可以使用data.census.gov,我发现它要慢得多(这么多风车!)比 IPUMS 国家地理信息系统。
注意:滚动到底部查看术语表。
获取人口普查数据
为了绘制人口普查数据,我们既要寻找感兴趣级别的 GIS shapefiles,也要寻找匹配级别的信息表。
来自 IPUMS:
“IPUMS 提供跨越时间和空间的世界各地的人口普查和调查数据。IPUMS 集成和文档使研究变化、进行比较研究、合并不同数据类型的信息以及分析家庭和社区环境中的个人变得容易。免费提供的数据和服务。”
点击查看所有数据库。或者 GIS 和人口普查数据库这里。要使用这个系统,你需要选择你的数据集,注册一个账户,然后等待系统发邮件告诉你你的数据集准备好了(大约。等我 15 分钟)。
挑选数据集
点击(当前)绿色方框,根据地理区域、年份、主题、数据集进行过滤。
在弹出的地理区域中,您需要了解人口普查如何进行地理测量。对于目前没有被分类为“美洲印第安人、阿拉斯加土著人、夏威夷土著人地区”的地区,您可以从上到下阅读标准的层次结构,将国家划分为地区,每个地区划分为部门,每个部门划分为州,等等。或者,您可以自下而上地阅读标准层次结构:人口普查区块分为区块组,区块组分为人口普查区域,人口普查区域分为县,等等。

https://www2.census.gov/geo/pdfs/reference/geodiagram.pdf?#
需要注意的一点是,人口普查区域、区块组和人口普查区块不遵循垂直中心(州、县)之外的任何划分。在人口普查中,城市是“地方”,其边界不一定在人口普查区块、区块组或区域的创建中得到考虑。您也可以在这些交替的级别/类别上收集数据,但是在尝试将这些数据“汇总”到更大的分组中或“深入”到更小的范围时,您需要小心。
设置过滤器后,单击“选择数据”下的选项卡,从“源表”移动到“时间序列表”或“GIS 文件”你会把范围缩小到你所在的州、县等。下一步。
选择您感兴趣的数据后,从屏幕右上角的“数据推车”中单击继续。
选择数据选项
根据您的数据集和地理级别,您可以在此页面上按州缩小数据范围。如果您使用的是县一级的数据,则不能选择州一级的过滤。
您已经准备好“继续”检查您的数据推车。
注册一个账户

Avel Chuklanov 在 Unsplash 上拍摄的照片
这里很标准,虽然有很多必填字段。
如果您不是以专业身份使用数据,您可以使用“个人/非专业用途”作为机构或雇主的名称,或者如果更合适的话,使用“自雇人士/顾问”。
最需要注意的是使用条款:
- "重新分发:未经许可,你不能重新分发数据."
- "引用:适当引用 NHGIS 数据. "
等待你的数据邮件
它将从nhgis@umn.edu和链接跟随,在那里你可以下载,修改,或重新提交你的数据请求。
来源:census.gov
尽管 data.census.gov的数据表功能看起来还很困难(在撰写本文时),但我发现 shapefile(又名制图边界文件)页面更加用户友好。有点奇怪的是:这里的是 1990 年至 2018 年的页面,还有一个单独的 2019 年页面。新发布的 2019 年数据方便地包括一系列规模选项。
当您使用下拉菜单进行选择时,它会自动开始下载。也许不是最直观的,但至少它们是拉上的。所以任何误点击都不会有太大的影响。
理解数据
来自 IPUMS 的每个表格文件都带有一个“代码本”文本文件,包含数据摘要、数据字典、引用和使用提醒。您可以从人口普查局了解更多有关具体数据、分类和感兴趣的问题。
请注意,这些 shapefiles 是一般化的,带来了优点和缺点(由人口普查局提供):优点—小比例下的外观、磁盘空间、显示时间。缺点:不完善的面积和周长表示,不准确的地址地理编码,一些被排除的区域,并不总是跨年度对齐。
我需要对人口普查局的地理项目大声喊出来。它们是大量直观且有用的资源。
绘制数据图表
在 pandas 和 geopandas 中加载数据
对于一些文件,我用pd.read_csv()没有问题,但在一个文件上,我用了**UnicodeDecodeError**。我不确定是否是文件的问题(也许是 excel 的问题?)或一个字符,但我发现将编码设置为 latin1 对我有用:
counties = pd.read_csv('counties.csv', encoding='latin-1')
GeoPandas 过去安装起来很棘手,但似乎最新版本已经解决了很多问题(全部?)的这些问题。尽管如此,使用一个新的或者以geopandas为中心的环境对你来说还是有意义的。你可以在这里找到他们的安装建议。今天我将使用geopandas进行绘图,所以我也将在我的新环境中安装matplotlib和descartes。我还没有尝试过 PyGEOS 的实验性使用(在我写这篇文章的时候),但是它看起来很棒,尤其是如果你想要速度的话。
缩小到目标城市
我下载的数据集包含了华盛顿州所有的人口普查区块。全部 196 万。
起初,我计划使用 GeoPandas / Shapely intersects 函数以及地点地图中的西雅图地理信息。但是,当我看到 places 地理数据集包含地名时,我决定使用数字的地点代码数据进行过滤。
或者,您可以在 census.gov 搜索[年份] FIPS 代码,下载相应的文件(在我的例子中是“州、县、小民事部门和 FIPS 地方法人代码”),然后快速搜索您的位置。
这两种策略都需要额外下载。
关于地图投影的一句话

西雅图人口普查区块地图顺时针旋转约 15 度
我注意到人口普查区块形状文件被设置为人口普查放置形状的不同投影。您可以选择重新定向地图,以匹配人口普查地点形状、您正在使用的其他数据(例如,来自城市的数据),或者不匹配。在这种情况下,我将重新定位到我更习惯的视图。
你可以检查一个文件的方向/ crs,使用*geo_object*.crs或者使用方便的警告信息,如果你使用匀称的几何比较(即包含、触及等。)
设置投影:seattle_blocks_map.to_crs(“EPSG:4269”)
基于要素对地图进行着色

对于基本的 choropleth,在绘图调用中添加一个列参数。你可以在 GeoPandas 上阅读更多关于 choropleths 的内容。或者查看我的代码来创建带有图例的地图,并使用灰色背景来填充任何空白:
# to make nice looking legends
from mpl_toolkits.axes_grid1 import make_axes_locatable# create the plot for sizing
fig, ax = plt.subplots(figsize=(20,20))# lay down a background map for areas with no people
seattle_blocks_map.plot(ax=ax, color='grey', alpha=.5)# set the legend specifications
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)# add the map with the choropleth
seattle_blocks_map.plot(ax=ax,
column='white_rate',
cmap='Purples_r',
legend=True,
cax=cax,
missing_kwds={"color": "lightgrey"},
)
我很高兴能更深入地挖掘这些数据,看看 2020 年的数字出来时发生了多大的变化!
通用、可重复使用的解决方案
在为西雅图绘制地图后,我对其他城市感到好奇,并决定制定一个更通用的解决方案。为此,我创建了一个函数来获取数据文件路径,并执行与上面相同的操作,这使我可以毫不费力地为华盛顿接下来的四个最大的城市绘制类似的地图。在另一轮数据下载后,我将不得不报告其他州的城市。




你可以在这里找到 jupyter 笔记本。编码快乐!

词汇表:
- 地点:在普查数据中,地点指城市/城镇/等。
- crs :坐标参考系统。你的(球形)几何形状在二维平面上的投影。
- shapefile :一组包含几何图形和地理数据集中其他信息的文件。在这篇帖子中了解更多信息。
引用:
- 明尼苏达大学 IPUMS·nhg is,www.nhgis.org
- 地图边界文件描述。美国人口调查局。https://www . census . gov/programs-surveys/geography/technical-documentation/naming-conventi on/cartographic-boundary-file . html
使用开放数据立方体绘制 2019–2020 澳大利亚森林火灾图
理解大数据
在开放数据立方体 python 环境中使用分析就绪 Sentinel-2 数据评估火灾范围和火灾严重程度。

差分标准化燃烧比。包含由澳大利亚数字地球处理的修改的哥白尼数据(2020)。哥白尼数据(2020)。
2019 年至 2020 年,澳大利亚遭受了有史以来最具破坏性的火灾。在发生的不幸事件中,1020 万公顷土地被烧毁,3100 所房屋被毁,30 亿头动物死亡,33 人丧生[1]。然而,火灾的社会经济和生态影响远远超出了直接损失。对火灾事件进行定量和定性的评估和分析是为政策制定者和决策者提供灾后恢复信息的关键。
开放数据立方体倡议是专门为释放遥感图像的全部潜力而设计的开源项目的一个极好的例子。数据立方体吸收并索引 Landsat-8 和 Sentinel-2 图像等图像源,并通过应用高级大气、双向反射和地形校正优化这两种数据源的使用,使数据可以立即进行分析[2]。
在本故事中,我将向您介绍如何使用国家计算基础设施上的数据立方体的数字地球澳大利亚实例来创建一个脚本,该脚本查询多光谱影像的深层时态堆栈,以对 110 公里×130 公里的区域场景进行火灾前和火灾后评估。使用火灾事件前两个月和后三个月的图像,不到十分钟就可以得出火灾范围和严重程度的结果。
以下示例是使用国家计算基础设施的虚拟桌面界面(VDI)完成的,这是一个基于虚拟化 Linux 的环境,其中托管了数字地球澳大利亚的数据立方体和索引影像产品。在 VDI (32 GB 内存、4 个内核、2 GB 存储)上的 Jupyter 笔记本电脑中,结果在 28 分钟内产生。在 NCI 的 Gadi 超级计算机上编译并运行 python 脚本,10 分钟内就产生了结果(64GB RAM,16 个内核,10 GB 存储)。更多关于访问 NCI 的信息可以在这里找到。
对于那些对测试这段代码感兴趣的人,我建议先在沙盒环境中尝试一下,在创建帐户后,任何人都可以免费访问它。沙盒可以在这里找到。
步骤 1 —加载必要的模块并连接到 datacube。
步骤 2-建立时空查询参数。
步骤 3-对感兴趣的区域进行空间分块。
第 4 步-计算差值标准化燃烧比。
步骤 5-镶嵌空间块并导出结果。
直接的结果可以在上图中看到。该过程的准确性被评估为火灾严重性结果的 60-64%(分为未燃烧、低、中、高和极端的严重性类别)和火灾范围的 88-92%(分为未燃烧和燃烧的类别)。火灾严重程度的准确性较低是由于低、中和高严重程度等级之间的等级可分性较差——这是归一化燃烧比技术的一个已知问题[3]。其他误差来源包括由于时间窗口或火灾前后场景造成的季节性变化,这是通过计算像素分布随时间偏斜的像素中值来解决的。植被的非同质再生长也导致了一些错误分类。例如,草比中型和大型植被结构恢复得更快。这突出了理解你试图分析的生物物理现象的重要性。
归一化燃烧比是计算火灾范围和严重程度的一种简单而有效的计算方法。传统上受到多时相分析的长时间预处理步骤的阻碍,开放数据立方体计划打开了对分析就绪数据集的访问,允许更多的时间和计算资源专注于核心问题。该项目的开源协作性质,加上免费提供的图像来源和开放地理空间联盟标准,是未来惊人的遥感发现和解决世界上一些最大的环境监测挑战的有力秘诀。
请查看我的 github 资源库,获取与这个项目相关的源代码和笔记本—https://github.com/yobimania/dea-notebooks。
参考资料:
[1]:瓦尔多拉基斯等人。艾尔(2020)。从澳大利亚森林大火中吸取的教训:气候变化、空气污染和公共健康。JAMA 内科,180,635。
[2]:澳大利亚地球科学(2020)。地表反射 NBART 1(哨兵-2 MSI)。澳大利亚联邦。https://CMI . ga . gov . au/data-products/DEA/190/surface-reflectance-nbart-1-sentinel-2-MSI # basics
[3]:吉布森,R 等。艾尔(2020)。使用 sentinel 2 和 random forest 绘制澳大利亚东南部火灾严重程度的遥感方法。环境遥感 240,111702。
用 t-SNE 描绘科技世界
我们用 t-SNE 降维算法分析了 20 万篇科技新闻文章
克里斯托夫·乔迪、祖卡斯·纳瓦罗、米查什·帕利斯基、马切伊·维拉莫夫斯基(德拉布·UW,华沙大学)

基于 LDA、t-SNE 和 PCA 的文章聚类。图片作者:德拉布·UW
作为NGI项目的一部分, 德拉布·UW正在支持欧盟委员会的 下一代互联网 倡议,以识别与互联网相关的新兴技术和社会问题。我们的团队一直在尝试各种自然语言处理方法,以发现不同类型的在线媒体中的趋势和隐藏模式。你可以在这里 找到我们的工具和演示 。
这篇文章是我们展示最新科技新闻分析结果的迷你系列的一部分。我们有两个主要目标:
- 发现讨论新兴技术和社会问题的新闻中最重要的话题(参见我们之前的帖子!),
- 来映射这些主题之间的关系。
我们的文本挖掘练习基于一个科技新闻数据集,该数据集由 2016 年 1 月至 2019 年 5 月期间收集的 20 多万篇科技媒体文章组成。关于数据集的更多信息可以在我们的 Zenodo 知识库中获得。
在这一部分中,我们将展示如何使用降维技术 t-SNE 和流行主题建模算法(LDA)来映射面向科技的新闻文章。我们表明,这些方法一起应用可以加强和补充对方。
我们首先简要介绍一下 t-SNE 算法。然后,我们提出了我们的映射练习的结果。
t-SNE
t-SNE 由 van der Maaten 和 Hinton (2008)引入,并在多次尝试后找到一种保持局部结构的降维算法。与早期的算法相比,它设法获得了牵引力,据谷歌学术称,它已经被引用了近 1 万篇文章。
SNE,t-SNE 的基本算法,最小化全维和低维嵌入的概率分布之间的差异。目标是保持一个点选择另一个点作为其邻居的条件概率。该分布是高斯分布,并且给定点的标准偏差(其对于所有点不是恒定的)是基于困惑来选择的,困惑可以被理解为所考虑的最近邻居的数量。梯度下降找到局部最小值。
该算法存在拥挤问题——在三维空间中,可以找到 4 个彼此等距的点(四面体的角),而在二维空间中,可能只存在 3 个这样的点(三角形)。在从 3 维到 2 维的变换中保持这种相似性在数学上是不可能的,但是将低维分布切换到具有较重尾部的分布可以缓解拥挤问题。
不承诺维护数据的全局结构。然而,生物学的最新发展——其中 t-SNE 被广泛用于转录组学——描述了全球结构可视化方面的改进。该程序( Kobak,Berens 2018)使用 PCA 作为可视化的起点,并采用“困惑退火”——来自高困惑 t-SNE 的输出被用作较低困惑 t-SNE 的初始化。他们的可视化在某些方面与我们的数据不同——PCA 在转录组学中提供了相当好的结果,但在文本挖掘中作为独立的工具是无用的。
我们的结果表明,使用主成分分析作为 t-SNE 初始化有各种优势。我们将使用这种方法的组合在二维空间中对文章进行聚类:覆盖相似主题的文章将通过算法彼此靠近放置。
映射所有文章
我们能够从主题建模分析中观察到最流行的主题。然而,基于主题词的分析很难揭示进一步的细节。为了检查哪些文章讨论了各种主题,我们转向使用 t-SNE 进行文档聚类。

互动观想见:【https://mpalinski.github.io/ngi-fwd-deliv/】T4
该地图以二维方式呈现文章:相邻的文章以相似的词汇为特征,并且可能覆盖相同的主题。此外,我们还用颜色标记主题建模分析的结果:它标记了文档的主导主题。为了更好的可视性,地图为 8 个最常见的主题提供了不同的颜色,而其余的主题被合并到一个类别(“其他”)。地图还允许查看图表下方的文章标题。

互动可视化见:https://bit.ly/2r0ERx8
地图显示,LDA 和 t-SNE 对我们的文档进行了类似的分组:t-SNE 将颜色相同的文章放在一起。我们可以识别大群的绿色、蓝色、紫色等。文章。这支持了文本挖掘策略的健壮性。
此外,该图证明了我们的方法提供不同粒度水平的文章聚类的能力。基于对聚类的分析,我们能够在由 LDA 确定的大范围主题内识别更具体的区域。例如,LDA 返回了一大类主要涉及社交媒体危机问题的文章。t-SNE 帮助我们进一步将这些文章分为更小的集群:专注于特定的社交媒体平台(例如,Twitter 上的文章可以在(50,-10),脸书上的文章可以在(50,10),或川普总统使用社交媒体的文章(0,-30))。
t-SNE 的另一个优势由苹果-联邦调查局加密辩论(35,10)上的集群展示。基于 LDA 话题术语,我们将整个绿色话题命名为社交媒体危机,而这组文章还包括其他技术政策领域。SNE 霸王龙帮助我们认识到这些更微妙的细节。
同样值得注意的是,t-SNE 是如何将来自不同 LDA 主题、具有共同特征的文章组合在一起的。一个这样的例子是 Google 上的集群(20,10 ),其中包括关于 Youtube 问题的故事、商业新闻或关于 Google 智能手机软件开发的文章。
云彼此的接近似乎也是有意义和有信息的,因为它可以通过人工智能和机器人集群的例子来观察。在图的左上部分(-35,30),你可以找到一组关于机器人的文章。云的左边部分由讨论机器人技术的变革潜力(例如工作自动化)的文章组成,而右边部分涉及硬件问题(例如电池)。整个机器人集群靠近另一个与有意识人工智能和真正的自主人工智能相关的蓝色集群,位于东南方向(-30,20)。可以找到更多关于人工智能伦理方面的文章。正如我们所见,空间距离类似于这里的“主题距离”。
在其余集群中也可以观察到类似的规律:商业新闻、智能手机、网络安全、跨平台开发、流媒体和太空探索。
例如,在网络安全文章的情况下,关于分散式网络安全的群组(0,-55)和处理数据泄露的群组(15,-15)之间有明确的划分。后一个在逻辑上位于关于在线隐私问题的文章簇的旁边(10,-15)。
在智能手机子类别中,我们可以观察到与各种 VR 技术相关的文章(0,55)与智能手机相机技术的文章(0,40)接近。关于连续几代 iPhone 的新功能和销售的文章聚集在(35,20),就在与 iOS 相关的群集的右侧。
C 结论
我们证明了将 LDA 主题建模与 t-SNE 聚类相结合的有效性。主题建模在探索广泛的主题(例如,社交媒体危机、人工智能或商业新闻)以及对文章进行分组以供进一步分析时非常有用。然而,它对于更细微、更精细的分析的有用性是有限的。这就是 t-SNE 算法派上用场的地方。我们的结果表明,这种研究方法组合非常适合绘制科技新闻景观。特别是,我们的映射实践证明了我们的方法提供不同粒度水平的文章聚类的能力。
我们的完整报道还深入探讨了技术讨论中反复出现的总括性话题(即:人工智能&机器人、政策、媒体、商业和网络安全)。
用 Python 绘制美国人口普查数据
公共数据
制作纽约州公共交通使用的地图
如果你曾经想要创建你最喜欢的人口普查统计数据的快速地理可视化,那么你来对地方了!首先,你需要得到你感兴趣的人口普查数据。对于这个例子,我们将使用纽约州的交通数据。
数据下载
现在您需要导入所需的包。如果你是第一次接触 censusdata 软件包,请花点时间熟悉一下使用优秀文档或这个关于这个主题的介绍性博客
import pandas as pd
import censusdata
from tabulate import tabulate
现在我们需要下载我们感兴趣的数据。
df = censusdata.download('acs5',
2015,
censusdata.censusgeo([('state', '36'), ('county', '*')]),
['B08301_001E', 'B08301_010E'])
该方法参数的快速分解:
- ‘ACS 5’指的是 5 年美国社区调查,并指定我们下载的数据库。
- 2015 年是我们获取数据的年份
- census data . census geo([(' state ',' 36 '),(' county ',' * '))定义我们感兴趣的地理位置。“36”值是纽约州的 FIPS(联邦信息处理标准)代码,而“*”表示我们需要每个县。要查找您所在州或县的 FIPS 代码,请参考维基百科页面。
- ['B08301_001E ',' B08301_010E'] 这是我们感兴趣的具体两个表的列表。注意,这些是预先使用 censusdata 的搜索功能定位的。
数据帧准备
现在,让我们看看数据框中有什么。
print(tabulate(df, headers='keys', tablefmt='psql'))

好的,我们确实在这个表中得到了我们想要的原始信息,但是现在解释起来有点麻烦。例如,这里的 Id 值是 censusgeo 对象。Y ikes!
首先,我们将更改那些表 id 的现有列名,以反映它们的内容。
column_names = ['total_transpo', 'total_public_transpo']
df.columns = column_names
接下来,我们将设计一个新列,它只是公共交通的比率。
df['percent_public_transpo'] = df.apply(
lambda row: row['total_public_transpo']/row['total_transpo'],
axis = 1)
现在我们将在提取县名时重新定义索引。
new_indices = []
county_names = []for index in df.index.tolist():
new_index = index.geo[0][1] + index.geo[1][1]
new_indices.append(new_index)
county_name = index.name.split(',')[0]
county_names.append(county_name)df.index = new_indices
df['county_name'] = county_names
好吧,让我们再看看。

好多了!现在在地图上
绘图
为了进行映射,我们将使用一个名为figure _ factory的特性,它将为我们做很多工作。所以第一件事就是导入包。
*import plotly.figure_factory as ff*
现在创建地图只需要几行代码。
*fig = ff.create_choropleth(fips=df.index,
scope=['New York'],
values=df.percent_public_transpo,
title='NY Public Transit Use by County',
legend_title='% Public Transit')
fig.layout.template = None
fig.show()*

对于几行代码来说看起来相当不错!但是不要被愚弄了,我们通过以一种与 figure_factory 兼容的方式构建我们的数据框架,努力为我们的成功做好准备。例如,它以州代码* + 县代码的形式接收 FIPS 数据。因此,通过重命名我们的索引来遵循这种形式,我们可以简单地将直接的索引值传递到方法中*
最后,这张地图中的数据以我们预期的方式分布,一个巨大的热点以纽约市为中心,越往外越淡。
这就是它的全部,现在获取映射!
用 Wolfram 语言绘制野火地图
探索和测绘 NASA 野火卫星数据

最近野火在多个州蔓延。加州遭受了历史上最大的几场野火。俄勒冈州有 20 处大火,覆盖面积超过 40 万英亩。甚至华盛顿今年也不能幸免。
为了了解当前的野火在哪里,我实现了一个名为 WildfireData 的功能,该功能从美国宇航局的 Terra 和 Aqua 卫星上的 MODIS 仪器获取数据(代码包含在本文末尾):
此 WildfireData 函数可通过以下全局资源函数 URI 进行访问:
WildfireData = ResourceFunction[
"user:arnoudb/DeployedResources/Function/WildfireData"
]
我们现在可以立即使用该功能从 NASA 获取当前可用的野火数据:
data = WildfireData[]
输出是一个包含几列的数据集。第一列保存野火观测的地理位置,第二列保存其亮度:

(图片由作者提供)
我们可以从在地图上标出所有地点开始:
GeoGraphics[{Red, Point[data[All, "Location"]]}]
输出显示了观察到的野火:

(图片由作者提供)
在这个缩放级别,看起来南方有很多野火,但是我们可以放大到,例如,密西西比州来近距离观察:
ms = Entity["AdministrativeDivision",
{"Mississippi", "UnitedStates"}];GeoGraphics[{
Blue, Polygon[ms],
Red, Point[data[All, "Location"]]
},
GeoRange -> ms
]
近距离观察,可以清楚地看到这些野火相当分散且孤立:

(图片由作者提供)
我们可以比较密西西比州和俄勒冈州的差异:
or = Entity["AdministrativeDivision", {"Oregon", "UnitedStates"}];GeoGraphics[{
Blue, Polygon[or],
Red, Point[data[All, "Location"]]},
GeoRange -> or
]
俄勒冈州的野火数量要多得多:

(图片由作者提供)
我们可以放大任何区域,例如,洛杉矶中心 40 英里以内的区域:
la = Entity["City", {"LosAngeles", "California", "UnitedStates"}];GeoGraphics[{
Red, Point[data[All, "Location"]]},
GeoRange -> GeoDisk[la, Quantity[40, "Miles"]]
]
圣加布里埃尔山脉有许多野火:

(图片由作者提供)
这些野火被命名为山猫火(Twitter 上的#山猫火):
俄勒冈州塞勒姆东部也有大面积的野火:
area = Entity[“City”, {“Salem”, “Oregon”, “UnitedStates”}]GeoGraphics[{
Red, Point[data[All, "Location"]]},
GeoRange -> GeoDisk[area, Quantity[60, "Miles"]]
]
这显示了一个非常大的野火群:

(图片由作者提供)
不幸的是,西部的野火季节预计要到 11 月份才会结束。到目前为止,仅在加利福尼亚,超过 3,000,000 英亩的土地被烧毁,估计损失达 8 亿美元。俄勒冈州损失了 60 多万英亩,华盛顿州损失了 50 多万英亩。
WildfireData 函数的代码:
使用 Google Places API 和 leav 绘制您在菲律宾最喜欢的咖啡店地图
实践教程
使用 Google Places API 和 leav 绘制菲律宾的咖啡馆地图

为什么是咖啡?
对我们大多数人来说,咖啡已经成为我们早晨日常生活中不可或缺的一部分。
但在很多城市规划研究中,咖啡店的数量已经成为一个地方或一个城市发展水平的标志。这并不奇怪,因为咖啡店是商业和客户会议的场所,而且位于商业区,忙碌的员工需要快速获得咖啡。
因此,仅仅通过知道一个地方咖啡店的数量,就能告诉我们一些有价值的东西。但是我们如何进行呢?
数据科学如何改善这一过程
既然我们知道了这些数据的重要性,那么我们应该如何收集这些数据呢?
一些咖啡连锁店有一个位置列表,可以在他们的网站上找到,我们可以通过复制信息并自己对数据进行地理编码来手动获取。
但是这将导致冗长的过程,容易出错,并且可能需要更长的时间来清理。
这就是数据科学的魔力所在。对于本教程,让我们使用 Google API 收集数据,并使用 follow 以 HTML 格式可视化我们的数据。
演职员表:我们从 artemrys 借用了一些代码,并对其进行了修改,以满足菲律宾城市的需要,并返回比 count 更多的代码。
分析项目设计

我们这个项目的设计
上面的图片总结了我们处理这个项目的过程。注意,这仅用于数据采集。我没有把清理和数据可视化放在这里,因为它们通常是通常分析项目的一部分。
准备工作
#Preliminaries
from collections import namedtuple
import requests
import csv
import time
import json
import os
import pandas as pd#For Interactive GeoVisualization
import folium
from folium import Map
from folium.map import Layer, FeatureGroup, LayerControl, Marker
from folium.plugins import MarkerCluster, FeatureGroupSubGroup, Fullscreen#To turn our DataFrame to a GeoDataFrame
import geopandas as gpd
from shapely.geometry import Point, Polygon
为什么选择 Google API?
在谷歌地图 API 和 OpenStreetMap 之间,谷歌地图 API 返回更多更新的数据。这可能是因为谷歌使用了更多的资源,拥有了更多的用户。不过需要注意的是,在多次调用后,谷歌开始收费,所以我建议开发者阅读成本矩阵,并在使用 API 时保持警惕。
出于本教程的目的,假设您本月没有使用 Google API(免费层每月刷新),这不会花费您什么。
测试代码时,将 API 调用限制在几行内,这样就不会出现耗尽自由层的错误。
不言而喻,为了继续,你应该注册一个 Google API 密钥。
#the namedtuple method returns a new subclass of tuple with named fields
#this is a convenient way of assigning names to tuples so you can later access them by name
CityCoords = namedtuple("CityCoords", ["city_name", "lat", "lng", "region"])# Google Maps Key
# GMAPS_KEY = {Place your GMAPS Key here}#Google Place API Request
#Note that we {lat}, {long}, {radius}, {keywords} and {key} will be arguments that we need to supply in later
G_PLACES_API = "[https://maps.googleapis.com/maps/api/place/nearbysearch/json?location={lat},{lng}&radius={radius}&keyword={keyword}&key={key](https://maps.googleapis.com/maps/api/place/nearbysearch/json?location={lat},{lng}&radius={radius}&keyword={keyword}&key={key)}"#Token to skip to next page
G_PLACES_NEXT_PAGE_TOKEN = "[https://maps.googleapis.com/maps/api/place/nearbysearch/json?pagetoken={page_token}&key={key](https://maps.googleapis.com/maps/api/place/nearbysearch/json?pagetoken={page_token}&key={key)}"
您现在就可以指出您希望形象化的品牌。我最喜欢的四个咖啡品牌是星巴克、咖啡豆和茶叶、蒂姆·霍顿和咖啡计划。
#Indicate brands you wish to collect
coffee_brands = ["Coffee Bean and Tea Leaf", "Starbucks", "Tim Hortons", "Coffee Project"]
定义功能
让我们定义我们稍后将调用的函数。回想一下,我们有一个分析设计要遵循,我们将编写与过程的每一步相对应的函数。
这一步相当长,所以我们不把它们放在这里。相反,请访问我的 Github 页面获取完整代码。
我的页面将包含地理编码的菲律宾城市供所有人使用。
清理数据集
运行代码收集数据后,现在是清理数据的时候了。
我们从 API 请求中获得的数据可能不完全干净。当你使用的关键词与其他品牌的关键词匹配时,这种情况尤其会发生。以咖啡豆和茶叶为例,那里的咖啡也可能与其他咖啡店的相匹配。
截至 2020 年 10 月,我们最喜爱的咖啡店的最终统计结果如下:

通过树叶进行地理可视化
首先,要使用 our,我们必须将数据框转换为地理数据框:
geometry = [Point(xy) for xy in zip(df['lng'], df['lat'])]#Let us create GeoDataFrame with df data and list of Point Geometries
gdf = gpd.GeoDataFrame(df, geometry=geometry)
接下来,我们实例化叶子地图:
#The folium.Map instantiates a folium map object with given parameters
coffee_map = folium.Map(location = [14.5540,120.9752],
zoom_start=5, #from experience, this zoom level captures the whole PH
tiles='CartoDB dark_matter',
control_scale=True,
prefer_canvas=True)
#Add Fullscreen Control
Fullscreen(
title="Full Screen",
title_cancel = "Exit fullscreen",
force_separate_button=True).add_to(coffee_map)

这就是我们的树叶地图的样子
在我们继续之前,我们需要为每个咖啡品牌分配不同的颜色,以便它在地图上看起来更好:
#Let's Create a Color Dictionary for the Markers
color_dict = {
"Starbucks": ' #00704A',
"Coffee Bean and Tea Leaf": '#362d26',
"Coffee Project": '#654321',
"Tim Hortons": '#dd0f2d'
}
之后,让我们添加标记和聚类工具。
#Since we need to add a filter for this, we need to add them by brand:for brand in coffee_brands:
df_i = gdf[gdf['brand']==brand]
df_i.loc[:, "color"] = color_dict[brand]
#Let's add a marker feature - clustering
marker_cluster = MarkerCluster(control=False) #False so it will not appear as a layer
marker_cluster.add_to(coffee_map)
sub_group = FeatureGroupSubGroup(marker_cluster, name=brand, control=True, show=True)
#Popup Contents
for index, row in df_i.iterrows():
html = """
<h3>{title}</h3><br>
<b> {brand}</b><br>
{vicinity}<br>
"""
popup_contents = folium.Html(html.format(title = df_i.loc[index, 'name'],
brand = row.brand,
vicinity = row.vicinity),
script = True)
popup = folium.Popup(popup_contents, max_width=2650)
folium.vector_layers.CircleMarker(radius = 8,
location = (row.geometry.y,
row.geometry.x),
popup = popup,
color = row.color,
fill = True,
fill_color = row.color,
name = brand,
control = True,
overlay = True
).add_to(sub_group)
sub_group.add_to(coffee_map)
当我们完成后,我们的地图将看起来像这样:

活动中的叶子标记
见解

菲律宾的咖啡店集群(星巴克、咖啡豆、茶叶、蒂姆·霍顿和咖啡项目)
从上面这张地图,我们可以清楚地看到,我们最喜欢的咖啡品牌大多都相当集中在菲律宾的老牌商业区。
不过有一点需要注意的是,在菲律宾的其他地方可能没有那么受欢迎的咖啡连锁店,只有我们喜欢的咖啡连锁店才会出现在主要的商业区——大马尼拉、宿务、莱加斯皮、那加和达沃市。
人们可以假设一个集群中的咖啡店越多,商业区就越发达,因此我们可以使用这些信息来跟踪哪些正在快速发展。
让我知道你们的想法!
完整代码可从 GitHub 获得。
三月版:数据可视化

伊万·罗伯森在 Unsplash 上的照片
人类大脑的很大一部分专门用于视觉;一些研究声称高达 80%的感觉输入是由视觉通路处理的[1]。视觉的重要性通过动词“看见”的使用来证明。我们看到梦;我们看到了解决方案等等。因此,数据可视化成为数据科学的重要组成部分也就不足为奇了。在其最重要的时刻,数据可视化可以在几秒钟内总结几天的数据分析结果。另一方面,如果做错了,它可能会导致演示文稿甚至整个项目的结束。
一个好的可视化不仅仅是一张图片;这是一个故事。数据中的一个人的旅途故事。以下文章是我们关于数据可视化的最佳案例精选。我们希望它们能在你创作的时候启发你。
迪米特里斯·帕纳戈普洛斯——编辑助理
我们团队的公告:我们发布了多伦多机器学习峰会的第一个视频。还会有更多。我们希望你喜欢它。🎤
11 个免费工具,轻松开始数据可视化&即刻
按 Parul Pandey — 9 分钟读取
使用这些简单直观的工具,直接进入数据可视化流程。
可视化的力量
马修·斯图尔特博士研究员——18 分钟阅读
一张照片真的胜过千言万语。
数据搜集、清理和可视化的终极初学者指南
安妮·邦纳 — 11 分钟阅读
如何简单地通过清理和预处理数据,让您的模型从不起眼变得令人惊叹
Python 中数据可视化的下一个层次
由威尔·科尔森 — 8 分钟阅读
如何用一行 Python 代码制作出好看的、完全交互式的情节
Matplotlib——让数据可视化变得有趣
到 Karan Bhanot — 9 分钟读取
数据可视化是理解数据集并从中进行推断的关键步骤。
现在是 2019 年,让您的数据可视化与 Plotly 互动
由杰夫·黑尔 — 12 分钟读完
使用 Express 和袖扣快速找到制作令人惊叹的数字的方法
辛普森一家遭遇数据可视化
由亚当·里夫斯曼——9 分钟阅读
没有什么比辛普森一家更让我喜欢的了
【Matplotlib 动画
按 Parul Pandey — 6 分钟读取
使用 matplotlib 库创建一些有趣的动画。
针对每个数据集的 3 种出色的可视化技术
Rahul Agarwal — 8 分钟阅读
同时学习一些关于足球的知识
我们也感谢最近加入我们的所有伟大的新作家伊哈布、钱(咏叹调)李、库尔提斯·派克斯、多纳特·沙赫尔、多里安·耶戈、伊恩·罗文、安东·穆勒曼、埃莉·哈里斯、苏吉瓦·库马拉通加博士、托马斯·迪 瑞安·a·马尔达尼、施鲁蒂·特纳、伊利亚斯·米拉维、戴夫·罗、伊恩·鲍德温、凯瑟琳·韦列斯顿、塞霍·李、 YoonWooJeong 以及其他许多人。 我们邀请你看看他们的简介,看看他们的工作。
参考资料:
[1] C. Haupt,A. B. Huber,“轴突如何看到它们的方向——视觉系统中的轴突导向”,生物科学前沿 13,3136–3149,2008 年 1 月 1 日
建立一个胜利的疯狂三月支架
使用统计数据对三月疯狂进行数据驱动预测的权威指南

https://www . inter basket . net/news/printable-women-March-madness-bracket-2017/21290/
疯狂三月。盛大的舞会。35 年的 64 支球队篮球锦标赛,只有一个孤独的支架在头两轮比赛中保持完美。每年,一个由 10 名成员组成的评选委员会决定哪 64 支球队将参加 NCAA 锦标赛,并根据常规赛和联盟锦标赛的表现对他们进行排名。这种等级排序系统被称为“种子”,种子从 1 到 16 分布在 16 支球队的四个区域,其中 1 支种子被认为有最高的获胜概率,16 支种子被认为获胜的可能性最低。
对于我们的读者来说,首先不太清楚构建支架背后的动机,简单的答案是奖金。沃伦·巴菲特为任何员工提供终身每年循环100 万美元存款,让他们在 16 岁之前选择一个完美的投资组合。
另一个不那么令人信服的原因是吹牛的权利。去年,我根据一个公认的非传统策略填写了我的组别,从而在 60+人组中获得了第一名,在 100+人组中获得了第二名。当然,不能保证我的方法会重复成功,但我还是要分享我的结果。要么接受,要么放弃,但不管你做什么,别忘了练习你的罚球。
1.翻转概率
我要介绍的第一个概念是“翻转概率”的概念提醒一下,当一个较高的种子队击败了一个较低的种子对手时,就会发生冷门。比如在这个具有历史意义的日子。现在 NCAA 锦标赛有 6 轮,在任何一轮中发生爆冷的平均概率是 31%。但是请注意,精英八人组相对于其他人来说是一个极端的异数。这篇文章的全部内容依赖于 2004 年至 2018 年的 NCAA 锦标赛数据(我选择了最近 15 年的时间,希望能够提取大学篮球的最新趋势,而不会引入 90 年代锦标赛的不必要的噪音)。

事实上,从历史上看,我们已经看到 4 场精英八强赛中有 2.1 场以冷门告终——对我来说,这是一个非常令人惊讶的见解,并促使我将奥本(5 号种子)推进到四强。

在继续之前,应该注意的是,一种观点认为,当两个队之间的种子差距大于 1 时,爆冷应该被保守地定义为爆冷(这意味着 2 号种子击败 1 号种子不被认为是爆冷)。然而,这种分析允许 1 的种子差异有资格成为扰乱,这可能会在我的结果中引入一些偏差。使用更保守的定义来比较任何差异,写一篇后续文章会很有趣。
在这一点上,一个敏锐的读者可能会问自己,“但是我应该挑选多少个冷门呢?”答案是 17.5(平均)。绘制每场比赛的总冷门数分布图,我们可以看到 15 到 20 似乎是个神奇的数字。让我们明智地选择。

2.复仇者联盟。
希望现在我们都相信冷门是重要的,在正确的时间调用正确数量的冷门是设计成功的关键。接下来我想鼓励大家仔细检查的是哪些种子会带来哪些挫折?也就是说,我们知道 16 比 1 是最不可能的赌注,但历史上哪些热门球队最容易受到冷门的影响?为了回答这个问题,我们可以检查一下锦标赛第一轮比赛的热图。

不出所料,8s 在 45%的情况下推翻 9s(使用 2003 年以来的数据)。然而,不太明显的是,11 推翻 6 的频率几乎一样高(44%的时间),12 推翻 5 的频率高于 10 推翻 7 的频率。这有什么奇怪的?种子之间的差异旨在作为技能差异的代表。理论上,种子的更大差异应该与技能的更大差异相关,这意味着 5s 应该比 7s 更经常击败 12s。不过,这些数据讲述的是一个不同的故事,这可能表明要么是糟糕的种子分配,要么是存在一些单靠播种无法捕捉到的获胜可能性的信号。同样值得注意的是,13 粒种子推翻 4 粒种子的几率约为 20%。可惜我错过了 2019 年锦标赛的这个机会:

3.精英八识
这里有一个类似的热图,显示了在精英八强的比赛中,失败者推翻了热门对手的百分比。当种子比对手低时,2 号种子在 8 场比赛中输掉了 7 场,这不值得。然而,他们在对阵 1 号种子时赢得了 20 场比赛中的 12 场。这是一个非常奇怪的统计数据,但我相信你可以猜到我的选择,如果我在精英八强中有 2 比 1(咳,2)。

希望这个演练能帮助你了解一些关于 NCAA 锦标赛种子赛的新东西。如果没有,我很高兴你能走到这一步,我也很感谢你在百忙之中通读我的作品。作为数据科学博客帖子的长期消费者,我不得不说我对那些花时间定期发布这样的教程的人重新产生了敬意。如果您有任何问题/请求/或想要联系,请随时发送评论!
对任何仍然怀疑这种方法有效性的人,我只能说,证据就在布丁里:

数据科学家解释边际、联合和条件概率
以数据科学的方式学习概率

P 概率在数据科学中扮演着非常重要的角色,因为数据科学家经常试图得出可以用来预测数据或更好地分析数据的统计推断。
统计推断是使用数据分析来推断潜在概率分布的属性的过程(来源:维基百科),因此理解随机变量及其概率分布是解决许多数据科学问题所需的技能。
我将通过提供一个场景来开始这个讨论,因为我们将从这个场景中学习概率分布。
方案
在伦敦西区对 500 名陌生人进行了一项调查,以确定人们最喜欢的运动。选项是足球、橄榄球,其余的归类在其他选项中;测试结果显示在图 1 的中。

图 1:测试的结果
图 1 并不完全是一个概率分布,但是如果我们想要得到概率分布,我们可以简单地将图 1 中的每个数字除以 500(观察数字),结果将是图 2 中的图像。

图 2:概率分布
联合概率
联合概率是一种统计度量,用于计算两个事件同时发生的概率,即 P(A 和 B)或 P(A,B)。比如用图 2 我们可以看到,某人是男性并且喜欢足球的联合概率是 0.24。

图 3:联合概率分布。
注意:图 3 中高亮显示的单元格(联合概率分布)的总和必须为 1,因为分布中的每个人都必须在其中一个单元格中。
联合概率是对称的,这意味着 P(男性和足球)= P(足球和男性),我们还可以用它来寻找其他类型的分布,边际分布和条件分布。
边际分布
在概率论和统计学中,随机变量集合的子集的边际分布是该子集中包含的变量的概率分布。它给出了子集中变量的各种值的概率,而没有参考其他变量的值(来源 : 维基百科)——如果这太过行话,简单地说,边际概率是一个事件的概率,而不考虑另一个变量的结果——P(A)或 P(B)。

图 4:边际分布
注意:不管我们忽略性别还是运动,我们的边际分布总和一定是 1。
边际概率的一个有趣的事实是,所有的边际概率都出现在页边空白处——这多酷啊。因此,P(女性)= 0.46 完全忽略了女性喜欢的运动,而 P(橄榄球)= 0.25 完全忽略了性别。
条件概率
条件概率概念是概率论中最基本的概念之一,在我看来是一种更复杂的概率类型。它定义了在一个事件已经发生的情况下,另一个事件发生的概率(通过假设、推测、断言或证据)。

图 5:条件概率的表达式
为了理解这一点,让我们再次使用图 2;如果我们想计算一个人喜欢橄榄球的概率,假设他们是女性,我们必须得到这个人是女性并且喜欢橄榄球的联合概率( P(女性和橄榄球))并除以条件概率。在这种情况下,概率是这个人是一个女性( P(女性)),我们可以从边缘算出是 0.46,因此我们得到 0.11(两位小数)。
让我们把它写得更整洁些:
p(女性,橄榄球)= 0.05
p(女性)= 0.46
p(橄榄球|女性)= 0.05 / 0.46 = 0.11(精确到小数点后 2 位)。
如果我们继续填写偏好某项运动的概率,假设观察对象是女性,那么我们将得到一个条件概率分布。
包裹
这是指南是一个非常简单的介绍联合,边际和条件概率。作为一名数据科学家,了解这些分布可能仍然会让你遭到嫉妒的统计学家的死亡凝视,但至少这次是因为他们只是愤怒的人,而不是你错了— 我在开玩笑!
让我们继续 LinkedIn 上的对话…
[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn
在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有两个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)




浙公网安备 33010602011771号