介绍谷歌番石榴
Guava 是一个开源的 Java“收藏库”库,由 Google 开发。
它提供了使用 Java 集合的实用程序。当您深入研究 Guava 时,您会注意到它是如何通过使代码简洁易读来减少编码错误、促进标准编码实践和提高生产率的。
我决定把番石榴教程分解成一系列的帖子。我们将涵盖许多 Guava 概念——Guava 实用程序类,函数式编程,使用集合,以及事件总线。
在这篇文章中,你将了解到:
1。 给你的 Java 项目添加番石榴。
2。Guava 中的基本实用程序—拆分器、地图拆分器、连接程序、地图连接程序和预处理类
1.将番石榴添加到项目中
番石榴有两种口味
- 一个用于 Java 8+ JavaRuntimeEnvironment。
- 另一个用于 Java 7 或 Android 平台。
如果您使用的是 Maven,将下面的代码片段添加到 <依赖关系>…</依赖关系> 部分
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>**version**</version>
</dependency>
如果你正在使用 Gradle,添加***maven central()***到资源库
*repositories {
mavenCentral()
}*
然后将下面的代码片段添加到 build.gradle 文件的依赖项部分。
*dependencies {
compile group:'com.google.guava’, name:'guava', version:**version**
}*
查看链接了解更多版本信息。
对于不使用任何项目管理工具(如 Maven 或 Gradle)的人来说—
- 从 这里 下载一罐谷歌番石榴。
- 如果使用 IDE,将 JAR 文件作为外部库添加。
- 如果您使用文本编辑器,将 JAR 文件添加到您的类路径中。
2.基本的番石榴公用事业
2.1 Joiner 类
它接受任意字符串,并用一些定界符将它们连接在一起。通过为每个元素调用 Object.toString() 来构建结果。
通常你会这样做
*public String concatenateStringsWithDelimiter(List<String> strList, String delimiter) {
StringBuilder builder = new StringBuilder();
for (String str: strList)
if (str != null)
builder.append(str).append(delimiter);
// To remove the delimiter from the end
builder.setLength(builder.length() - delimiter.length());
return builder.toString();
}*
但是在 Joiner 类的帮助下,等价于上面的代码可以写成
*Joiner.on(delimiter).skipNulls().join(strList);*
如你所见,代码变得简洁且易于维护。同样,用番石榴找虫子也相对容易。现在,如果你想添加一个空字符串的替换,该怎么办呢?嗯,Joiner 类也处理这种情况。
*Joiner.on(delimiter).useForNull(replacement).join(strList);*
你可能会想,也许 Joiner 类仅限于处理字符串,但事实并非如此。因为它是作为泛型类实现的,所以也可以传递任何对象的数组、iterable 或 varargs。
Joiner 类一旦创建就不可改变。因此,它是线程安全的,可以用作静态最终变量。
*public static final Joiner jnr = Joiner.on(delimiter).skipNulls();
String result = jnr.append(strList);*
2.2 接合工。MapJoiner 类
它与 Joiner 类的工作方式相同,唯一的区别是它用指定的键-值分隔符将给定的字符串连接成键-值对。
*public void DemoMapJoiner() {
// Initialising Guava LinkedHashMap Collection
Map<String, String> myMap = Maps.newLinkedHashMap();
myMap.put(“India”, “Hockey”);
myMap.put(“England”, “Cricket”);
String delimiter = “#”;
String separator = “=”;
String result = Joiner.on(delimiter).withKeyValueSeperator(separator).join(myMap);
String expected = “India=Hocket#England=Cricket”;
assertThat(result, expected);
}*
2.3 Splitter 类
Splitter 类的作用与 Joiner 类相反。它接受一个带分隔符的字符串(一个字符、一个字符串或者甚至是一个正则表达式模式),并在分隔符上分割该字符串,然后获得一个部分数组。
通常你会这样做
*String test = “alpha,beta,gamma,,delta,,”;
String[] parts = test.split(“,”);
// parts = {“alpha”, “beta”, “gamma”, “”, “delta”, “”};*
你能注意到这个问题吗?你不希望空字符串成为我的结果的一部分。所以,split()方法还有待改进。
但是在 Splitter 类的帮助下,与上面等价的代码可以写成
*Splitter splitter = Splitter.on(“,”);
String[] parts = splitter.split(test);*
split() 方法返回一个 iterable 对象,该对象包含测试字符串中的各个字符串部分。 trimResults() 方法可用于删除结果中的前导和尾随空格。
就像 Joiner 类一样,Splitter 类一旦创建也是不可变的。因此,它是线程安全的,可以用作静态最终变量。
2.4 MapSplitter 类
Splitter 类伴随着 MapSplitter。它接受一个字符串,该字符串中的键值对由某种分隔符(一个字符、一个字符串甚至是一个正则表达式模式)分隔,并以与原始字符串相同的顺序返回带有键值对的 Map 实例。
*public void DemoMapSplitter() {
String test = “India=Hocket#England=Cricket”;
// Initialising Guava LinkedHashMap Collection
Map<String, String> myTestMap = Maps.newLinkedHashMap();
myMap.put(“India”, “Hockey”);
myMap.put(“England”, “Cricket”);
String delimiter = “#”;
String seperator = “=”;
Splitter.MapSplitter mapSplitter = Splitter.on(delimiter).withKeyValueSeperator(seperator);
Map<String, String> myExpectedMap = mapSplitter.split(test);
assertThat(myTestMap, myExpectedMap);
}*
2.5 前置条件类
前置条件类提供了静态方法的集合来检查我们代码的状态。前提条件很重要,因为它们保证成功代码的期望得到满足。
比如:
1。检查空条件。你可以一直写
*if (testObj == null)
throw new IllegalArgumentException(“testObj is null”);*
使用前置条件类使它更加简洁易用
*checkNotNull(testObj, “testObj is null”);*
2.检查有效参数。
*public void demoPrecondition {
private int age;
public demoPrecondition(int age) {
checkArgument(age > 0, “Invalid Age”);
this.age = age;
}
}*
checkArgument(exp,msg)计算作为参数传递给方法的变量的状态。它计算一个布尔表达式 exp,如果表达式计算结果为 false,则抛出 IllegalArgumentException。
3.检查对象的状态
*public void demoPrecondition {
private String name;
public demoPrecondition(String name) {
this.name = checkNotNull(name, “Anonamous”);
}
public void Capitalize() {
checkState(validate(), “Empty Name”);
}
private bool validate() { this.name.length() > 0; }
}*
checkState(exp,msg)计算对象的状态,而不是传递给方法的参数。它计算一个布尔表达式 exp,如果表达式计算结果为 false,则抛出 IllegalArgumentException。
4.检查有效的元素索引
*public void demoPrecondition {
int size;
private int [] price;
public demoPrecondition(int size) {
this.size = checkArgument(size > 0, “size must be greater than 0”);
this.price = new int[this.size];
}
public void updateItem(int index, int value) {
int indexToBeUpdated = checkElementIndex(index, this.size, “Illegal Index Access”);
}
}*
谢谢你的阅读。在下一篇文章中,我们将讨论 Guava 中的函数式编程。
引入 Hoeffding 不等式生成无存储决策树
探索 Hoeffding 不等式陈述了什么,以及如何使用它来创建一类特殊的不使用存储的决策树:Hoeffding 树。
© by my lovely wife Tinati Kübler
任务
我想象你有一个巨大的带标签的数据集,你想为一个预测任务建立一个模型。例如,这可以是 Twitter,在那里你有比你可以计算的包括相应的喜欢(标签)数量更多的推文(功能)。现在你想要建立一个模型,可以预测一条推文是否会被喜欢超过 100 次,对去年写的所有推文进行训练,也就是说,我们想要解决一个分类任务。标签为 1 意味着该推文有超过 100 个赞,否则为 0。
Photo by Sara Kurfeß on Unsplash
你决定使用决策树,甚至是从它衍生出来的智能工具,比如随机森林或梯度推进。但是决策树、基于决策树的模型、甚至其他模型都有以下缺点:
您需要在内存中随时可用的训练数据。
问题是
在最好的情况下,完整的训练数据可以放入本地机器的内存中。但是,您意识到 tweets 数据集大于 8–32GB,所以您运气不好。也许您可以访问具有 512 GB RAM 的集群,但这也不够大。
数据集实际上有多大?让我们做一个粗略的估计。推特本身和其他几个来源(这里是这里是和这里是)报告称,每秒大约有 6000 条推文。这意味着每年大约有 6000 * 60 * 24 * 365 =189,216,000,000推文。让我们假设每条 tweet 的大小为 140 字节,每个字节对应于单词包编码中的一个字符。*我们忽略了每条 tweet 可能附带了一些元数据,我们也可以使用二元模型、三元模型等。*这是一个巨大的 140 *189,216,000,000/10⁹=26,490 GB 的推文数据!
因此,使用 RAM 不是一个选项。即使你碰巧拥有一个足够容纳整个数据集的硬盘,从其中读取数据也会使训练非常缓慢,正如你在这里看到的(图 3) 。
嗯,怎么办呢?
解决方案
来自华盛顿大学计算机科学与工程系的 Pedro Domingos 和 Geoff Hulten 介绍了决策树的一种变体,称为Hoeffding Trees【1】,可以用于流方式。这意味着我们只需解析一次大的训练数据集,并在此过程中构建树。
我们甚至不必存储所使用的样本:我们可以直接从 Twitter(或任何大型数据库)中获取它们,通过增加一些计数器来处理它们,然后再次忘记它们。为什么这是可能的可以用赫夫丁不等式来解释,这就是赫夫丁树的名字。
高层次的想法是,我们不必查看所有的样本,而只需查看决策树算法中每个分裂点的足够大的随机子集。这个子集有多大是下一节的主题。
我写这篇文章是因为 Domingos 和 Hulten 的论文非常专业(因此也非常精确),我想提出一个高级的、易于理解的观点来解释作者的方法为什么有效。
此外,如果您不想在接下来的部分中处理数学问题,至少可以看看最后一部分的一些代码!在那里,我使用 scikit-multiflow 软件包来使用 Hoeffding 树。
赫夫丁不等式
让我们研究一下霍夫丁不等式的内容,以及如何利用它来解决存储问题。
介绍
芬兰统计学家、非参数统计的创始人之一瓦西里·赫夫丁(基于赫尔曼·切诺夫的思想)发现了一个不等式[2],量化了以下陈述:
有界随机变量的和(也是均值)紧紧围绕其期望值。
以一枚公平的硬币(看到正面的概率= 0.5)为例,我们掷 1000 次。定义随机变量 X₁,…,X₁₀₀₀ 用
那么人头的数量——让我们称之为x——正好是 Xᵢ 的总和。我们已经知道,从那以后我们可以预期 500 次人头
The expectation of the Xᵢ’s is the probability of them being equal to 1, which is 0.5 in our case. Furthermore, the expected value is linear, justifying the first equation.
现在赫夫丁不等式把我们覆盖了:我们也知道 X 大概率不会偏离500太多*,见下图。*我们一会儿就知道“多”和“概率大”是什么意思了。
You can see how concentrated the probability mass is around 500. The probability of seeing exactly 500 times heads is about 0.025.
简化的定理
设 X₁,…,Xₙ是独立的伯努利随机变量,即它们中的每一个都取值 0 或 1。设 X = X₁ + … + Xₙ是他们的和。然后
Hoeffding’s Inequality for sums.
**注意:**一个更一般的公式成立,其中 Xᵢ 可以在任意实数 a 和 b 之间有界,甚至不必随机独立。但是我们使用这里给出的版本。
直觉上,这个不等式是有意义的:t变得越大,也就是说,我们允许误差变得越大,落在区间或长度 2 t 内的概率就越大。
但是真正有趣的事情是这样的:等式的右边只包括随机变量的数量 n 和允许误差 t. **最重要的事情,Xᵢ等于 1 的概率,在不等式的右边是找不到的。概率对我们来说可以是已知的,也可以是未知的,对所有人来说都是一样的,这并不重要。**这就是为什么这种不平等如此多才多艺,如此适合研究。
具有这种性质的其他不等式是更容易的马尔科夫不等式和切比雪夫不等式,但是它们给我们的右边的下界要差得多。平心而论,这两个不等式不需要我们的随机变量有界。然而,赫夫丁不等式利用了这样一个事实:Xᵢ在 0 和 1 之间有界。
取该不等式,用 *nt、*代替 t ,并将 P(…)内的不等式除以 n 得到平均值的 Hoeffding 不等式:
Hoeffding’s Inequality for the mean.
在哪里
应用程序
现在让我们来看看不平等在起作用。首先,我们将谈论一个非常基本的硬币例子。然后,我们会去第二个非常重要的例子,估计股份,我们需要了解为什么赫夫丁树工作。
回到硬币的例子(总和)
假设我们要计算得到小于等于 450 或者大于等于 550 人头的概率。由于𝔼( X ) = 500,我们可以设置 t =50,最后得到
这意味着偏离期望值小于 50 的概率非常高。头数极度集中在 500 左右。
估计份额(平均值)
假设有一大池 N 个球,其中未知份额 p 为白色,其余为黑色。一个自然的问题可能是:白球的份额 p 有多大?如果池大小 N 足够大(想想几十亿),捡起每个球并检查它不是一个选项。
当然,自然要做的事情是均匀地抽取几个样本——比如说有替换的 n — 球,然后检查它们。如果其中的 w 是白色的,我们就可以断定 p ≈ w/n 。但是我们的子样本应该有多大呢?什么尺寸适合 n ?10 可以吗?100?1000?
嗯,这取决于与 p 的偏差有多大,以及在这个偏差范围内,你需要多大的信心。您可以设置两个参数:
- 误差的上界在 *p,*让我们再把它叫做 t
- 在以长度为 2 的 p 为中心的区间内概率的一个下界姑且称之为 1- ɛ 对于小的 ɛ > 0 。
这意味着 t 和ɛ是固定的,我们想找到 n 个例子,这样至少在概率为 1-ɛ的情况下,分数 w/n 与 p 的差异不超过 t
我们现在要正式确定这件事。让我们定义 n 个随机变量 X₁,…,Xₙ 为
由于我们随机抽取有替换的球, Xᵢ 为 1 的概率正好是 p ,未知份额。这也正是 Xᵢ.的期望值
让 X̅=w/n 再次成为这些伯努利变量的平均值。然后我们还有
赫夫丁不等式给了我们
现在我们希望右手边大于 1- ɛ,,这给我们一个关于 X̅=w/n 偏离 p 不超过 t 的下限,其概率至少为1- *ɛ.*因此,我们必须解决这个不等式
对于 n 。使用一些基本运算,我们得到
如果我们容忍概率至少为 99%的 p 的绝对误差至多为 1%,我们必须将 t =0.01,将 ɛ= 设为 0.01,这样我们得到的所需子样本大小至少为
让我们用 Python 来试试吧。我们考虑 30,000,000 个球的池,其中 10,000,000 个球是白色的(标记为 1),20,000,000 个球是黑色的(标记为 0)。所以白球的真实份额是 0.3333……我们假装不知道。
import numpy as npnp.random.seed(0)# Create a pool with 30 million entries, 10 million being a one (white ball) and 20 million being a zero (black ball).
# This means that we have a share of 1/3=0.3333... white balls.
pool = 200000000 * [0] + 100000000 * [1]# Set Hoeffding parameters.
t = 0.01
eps = 0.01
hoeffding_amount = int(np.ceil(np.log(2 / eps) / (2 * t ** 2)))subsample = np.random.choice(pool, size=hoeffding_amount, replace=True)
print(subsample.mean())
# Result: 0.32975992752529065
看起来不错!误差只有 0.0035 < 0.01 = t 左右。但是这种情况发生的概率至少是 99%,所以我们为什么要庆祝呢?;)
注意,不是采样、保存,然后取 26,492 个样本的平均值,我们可以仅仅采样,每当我们画出一个白球(1)时增加一个计数器,然后再次忘记该样本。通过这种方式,我们只需要跟踪计数器和我们查看的球的总数,这使得这成为一种非常高效的内存算法(在我们的子样本大小中为对数 n )。
总的来说,我们可以说一个 26500 左右大小的子样本就足以高置信度地确定白球的份额。
回到机器学习
在最后一个例子中,我们已经看到了如何在一个巨大的黑白球池中计算白球的份额,而无需检查整个池,也不会有很大的误差。
我们将使用这些知识来训练决策树,而不需要在内存中有大量可用的训练数据,这是我们首先要解决的问题。
但是首先,我们必须重复一遍决策树是如何按照通常的方式构建的。
以传统方式构建决策树
在这里,我不会详细讨论决策树算法是如何工作的。在网上和媒体上有很多很棒的视频和文章。
但是,如果完整的训练数据集适合我们的内存,通常这是算法的第一步:
我们计算完整数据集的标签的杂质 I₁ 的度量,例如用于分类任务的香农熵,我们现在也将使用它。
The formula of the Shannon Entropy. p is the share of samples labeled 1. If p is 0 or 1, meaning that the samples all have the same label, the impurity is 0. The entropy function (=impurity) takes its maximum when exactly half of the samples are labeled 1 and the other half labeled 0, which corresponds to p=0.5. As you can see, the formula is symmetric, i.e. I§=I(1-p), which means that we can also consider the share of black balls instead of white balls.
然后,我们采用特征 f 和切割点 c. 使用这些,我们将整个数据集划分成两个不相交的子集:
- 其中特征 f 的值小于(或等于)c的所有样本
- 另一个包含所有样本,其中特征 f 的值严格大于 c.
再次测量这两组的杂质,并合并成一个加权平均值,给出两组的单个杂质测量值 I₂ 。则信息增益*计算为 G = I₁ — I₂.*
考虑以下一个拆分示例:
In this small example, we start with five samples with three features each. We start by measuring the impurity, namely I₁. Then we choose Feature 3 and a cut point of 4 to split the node. Doing this, the original five samples are distributed in the two children nodes. We measure the impurities of both nodes and combine them into a single number I₂. The Information Gain is then computed.
对所有特征和所有可能的切割点进行上述操作,选择具有最大信息增益 G 的切割点作为树中的第一个分割点。我们现在对树中的所有叶子递归地重复这一过程,直到满足某个停止标准(节点的杂质小于阈值,树已经达到最大深度,节点中的样本太少等等)。
消除内存需求
现在,我们必须使用更少的样本来模拟行为。正如我们在普通决策树中看到的:
只有标签为 1 的样品的份额 p 与计算杂质有关!
幸运的是,我们可以使用原始训练集的子样本来近似这个份额 p 和因此杂质,正如在关于赫夫丁不等式的部分中所讨论的。在球示例的语言中,带有标签 1 的标签是白球,带有标签 0 的样本是黑球。
考虑到单次分裂,我们仅使用大约 26,500 个样本就可以近似得到 I₁ 。然而,为了估计 I₂ ,我们在每个子节点中需要 **26,500。如果幸运的话,样本被平均分配到两个节点上,那么 226,500=53,000 个样本就足够了。否则,我们可能需要更多,但只要我们需要的样本少于几百万,我们就比以前更好了。即使我们需要一百万个:因为我们可以将它们流式传输到树中并跟踪一些计数器,所以我们不会遇到内存问题。***
这样我们可以安全地训练我们的模型,即使是在 Twitter 上的每条推文中。快乐大练兵!
如果你想详细了解这是如何做到的,请阅读论文[1]。作者用伪代码描述了他们的算法以及所有必要的计数器,并且他们还给出通过流式传输数据来构建多少 Hoeffding 树的证明,并且相应的正常决策树将会偏离。
结论
我们已经看到,在极大的训练集上训练决策树是不可行的。克服这个问题需要对正确数量的训练样本进行子采样,并用不完整但相当准确的信息构建树。这种二次抽样是合理的赫夫丁不等式,给这些特殊的决策树也有他们的名字:赫夫丁树。
此外,我们甚至不必存储子样本,我们只需在扫描训练数据时跟踪我们已经看到了多少标签为 1(白色球)的样本,这是一种简单有效的方法,可以进一步降低存储复杂度。
在本文中,我们只看到了用于分类任务的香草胡夫丁树。还存在用于回归的算法,甚至是对抗所谓的概念转移的方法,即当训练分布随时间变化时。**
幸运的是,这些算法都是由 Python 的 scikit-multiflow 的开发者实现的!让我们做一个快速测试。
四处玩耍
首先,做一个禁食
*pip install scikit-multiflow*
然后,让我们比较在完整的训练集上拟合 Hoeffding 树(=足够的可用 RAM)与逐个传递每个样本。更详细的测试也可以在[1]中找到。
*from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from skmultiflow.trees import HoeffdingTree
import matplotlib.pyplot as pltres = []# Create a dataset.
X, y = make_classification(10000, random_state=123)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)# Define a tree for fitting the complete dataset and one for streaming.
ht_complete = HoeffdingTree()
ht_partial = HoeffdingTree()# Fit the complete dataset.
ht_complete.fit(X_train, y_train)
ht_complete_score = ht_complete.score(X_test, y_test)
print(f'Score when fitting at once: {ht_complete_score}')# Streaming samples one after another.
timer = False
j = 0
for i in range(len(X_train)):
ht_partial.partial_fit(X_train[i].reshape(1, -1), np.array([y_train[i]]))
res.append(ht_partial.score(X_test, y_test))
print(f'Score when streaming after {i} samples: {res[-1]}')
if res[-1] >= ht_complete_score - 0.01:
print(f'(Almost) full score reached! Continue for another {20 - j} samples.')
timer = True
if timer:
j += 1
if j == 20:
break# Plot the scores after each sample.
plt.figure(figsize=(12, 6))
plt.plot([0, i], [ht_complete_score, ht_complete_score], '--', label='Hoeffding Tree built at once')
plt.plot(res, label='Incrementally built Hoeffding Tree')
plt.xlabel('Number of Samples', fontsize=15)
plt.ylabel('Accuracy', fontsize=15)
plt.title('Fitting a Hoeffding Tree at once (enough Memory available) vs fitting it via Streaming', fontsize=20)
plt.legend()*
生成的图形可能如下所示:
We can see that building a Hoeffding Tree H directly yields an accuracy of about 91% (on a test set). If we build another Hoeffding Tree by feeding in each sample one after another, we can see that the performance approaches the performance of H. After about 50 samples, our streaming Hoeffding Tree has an accuracy of about 88% already. If we pass in more samples, 91% is reached at some point (for me it was after about 4000 samples out of the 8000 training samples).
参考
[1] P. Domingos 和 G. Hulten,挖掘高速数据流 (2000),第六届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集
[2] W. Hoeffding,有界随机变量和的概率不等式 (1962),美国统计协会杂志。58 (301)
我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!
作为最后一点,如果你
- 想支持我多写点机器学习和
- 无论如何,计划获得一个中等订阅,
说白了,给你的价格不变,但大约一半的订阅费直接归我。
非常感谢,如果你考虑支持我的话!
有问题就在LinkedIn上写我!
引入 k-最近邻
理解这种分类模型的基础
k-最近邻算法基于一个非常简单的前提:距离很近的事物有很多共同点。这个前提全世界都可以看到:
- 大学生最亲密的邻居通常是其他大学生。
- 我们倾向于和我们的浪漫伴侣有更多的共同点,他们和我们共享一个家,而不是和隔壁城镇的人。
- 在杂货店里,每一种产品都储存在一组里,而不是分布在整个商店里。
k-最近邻建模方法使用这一前提来假设我们可以获取关于一个点的知识,并得出关于相邻点的结论。由于相似的事物通常聚集在一起,我们可以利用这种接近性对我们不知道的数据点做出假设。在杂货店里,苹果旁边的商品通常是另一个苹果。更具体地说,节日苹果旁边的物品通常是另一个节日苹果。人们的政治取向相似;随着越来越多的人聚集到政治上两极分化的城镇,如果我们知道一个城市中的一个人是保守派或自由派,我们可以合理地假设他们的邻居也是保守派或自由派。
因为它是基于这样的假设而不是复杂的统计模型,所以 k-最近邻是最简单的预测模型。
k 近邻模型是如何工作的?
为了使用 k-最近邻算法,您需要两样东西:
- 相信附近数据点彼此相似的假设。请记住,这并不总是一个有用的假设,你必须小心应用它。例如,如果你想知道口香糖贩卖机中的一个物品是什么,那么知道它旁边的物品是口香糖是非常有用的。然而,如果你想知道相邻的口香糖球是什么颜色,那么知道一个口香糖球是红色是没有用的;每个容器中通常有大约 5 种颜色的口香糖混合在一起。
- 两个数据点间距离的某种近似方法。在最简单的情况下,以及我们到目前为止讨论的所有例子中,这是两个项目之间的实际距离。然而,使用 k-最近邻算法,这也可以是数据集中两点之间的理论距离。例如,如果你想预测不同家庭的卧室数量,你可以使用平方英尺作为你的数据。那么这个距离就是两个不同住宅之间的平方英尺的差异。
通过结合相似项被分组的假设和距离的度量,您可以创建一个算法,通过在数据集中搜索最近的邻居来预测未知事例的事实。一旦找到这些最近的邻居,您就可以得出结论,您的未知点与这些邻居具有相同的特征。
在 k-最近邻模型中,k 是用于定义如何应用该模型的变量。它说明了执行分析时要检查的相邻要素的数量。使用 k-最近邻算法时,您可以更改 k,这可能会产生显著不同的结果。通过尝试不同的值并测试模型的预测能力来选择 k 的值。这意味着您必须开发、验证和测试几个模型。更多信息可以在如何在多个型号中选择中找到。
我怎样才能更好地了解这个算法?
k-最近邻算法是一种常见的分类工具,在互联网上可以找到关于该主题的大量信息。对于那些想要更多信息和高度可信来源的人,我强烈推荐从头开始的数据科学:Python 的基本原理。
关闭
k-最近邻算法是一种常见的分类模型,它基于这样的假设,即数据集中靠在一起的项目通常是相似的。为了使用它,你必须既相信那个假设,又有两个数据点之间距离的度量。然后,该模型使用距离计算来确定与您尝试预测的位置最近的 k 个数据点,并使用来自这些点的信息来得出结论。
介绍车床:朱莉娅的管道
在 Julia 语言中,我最想念的工具之一是 SKlearn 管道。与 SKlearn 相比,Lathe 本质上是一个非常不同的东西,不仅是基于函数式编程语言构建的,而且还具有像 fit-initialization 这样的初学者友好的属性。我非常想实现的是车床内部 Sklearn 管道的替代方案,随着即将发布的车床 0.0.5,我已经做到了!
数据
为了开始我们的小管道演示,我们需要读入一些数据。由于这不一定是一个项目,我将从我的深海相关项目中回收数据。当然,第一步是使用 CSV 读取我们的数据:
using CSV
df = CSV.read("bottle.csv")
然后我们快速清洗!
using DataFrames
df = DataFrame(:TempC => df.T_degC, :Salinity => df.R_SALINITY, :Depth => df.Depthm)
# We're going to drop the missing values now, if we did that prior, # we would
# have likely dropped a-lot more data.
df = dropmissing(df)
轻松点。
现在我们可以进入主题的实质,从选择我们的特性和目标开始。这对我来说并不重要,因为我们不追求准确性,而只是新模块的演示。对于我的特征,我选择了盐度和我的目标温度。让我们对测试和训练集做一个快速分割,然后我们可以设置我们的 x 和 y…
using Lathe.preprocess: TrainTestSplit
train,test = TrainTestSplit(df)
以及 X 和 Y 设置:
trainX = train.Salinity
trainy = train.TempC
testX = test.Salinity
testy = test.TempC
管道
为了在车床中建立管道,首先要建立一个模型。虽然在 Sklearn 中也可以这样做,但是这里的不同之处在于,管道的其他部分依赖于在模型中构造的 X 和 Y。考虑到这一点,我们仍然可以按照 Sklearn 的方式来做,但拟合模型的方式必须与我们在外部做的方式相同。
using Lathe.preprocess: StandardScalar
using Lathe.models: LinearRegression
using Lathe: pipelines
现在我们可以调用函数,它接受一个构造好的车床模型、一个方法或数组中的方法,然后接受一个类型参数。将来,除了原始的管道之外,可能会有不同类型的管道用于不同类型的特性,并且可能到 0.0.5 发布时,会有一个管道能够与其他 Julia 模型通用地工作。现在我们可以构建我们的管道。
pipl = pipelines.Pipeline(LinearRegression(trainX,
trainy),StandardScalar,:CON)
最后一部分,“:CON”告诉 predict 方法要运行哪个算法,这可能会改变,所以我不会太关注这一部分,因为它基本上不重要。
为了预测,我们使用来自车床的函数 pipe _ predict . pipelines:
[@time](http://twitter.com/time) pipelines.pipe_predict(pipl,testX)
恭喜你!
现在我们已经正式创建了一个 fit 管道来保存我们的训练值、预处理方法和模型类型!一个巨大的好处是即将到来的管道系列化。我不仅计划在 Julia 中序列化这些模型,还计划用 PyPi 包将它们读入 Python,以便在 Flask 和 Django 管道和 web 应用程序中使用,这不是很酷吗?
pipelines.save(pipl,"My-Pipeline")
我真的很兴奋的未来,这部分车床,和车床整体举行!车床 0.0.5 中有很多新的统计数据、模型和更多的东西,之后还会有更多!
介绍 Mercury-ML:一个开源的“机器学习之神的使者”
在古罗马神话中,墨丘利神被称为“众神的使者”。他穿着带翼的鞋子,戴着带翼的帽子,在奥林匹斯山和人类王国之间飞奔,确保众神的意志被知晓。他不是众神中最强壮、最聪明、最受尊敬或最令人畏惧的,但他脚步敏捷、狡猾,可以依靠他来引导事情朝着他们想要的结果发展。没有他,珀尔修斯不可能打败美杜莎;奥德修斯可能会中了喀尔刻的魔咒;而赫拉克勒斯也不可能将冥府之神地狱犬从冥府中拖出来,从而完成他 12 项神话般的劳动中的最后一项…
在这篇文章中,我想介绍一个名为 Mercury-ML 的新项目,以及开源的“机器学习之神的使者”。
机器学习工作流程看似简单,却依赖于多种工具和技术的复杂组合
机器学习和数据处理工具的最新发展导致了无数的开源库,其中每个库都提供了开发良好的透明 API,并且每个库都在构建健壮的机器学习工作流时发挥作用。经常使用的机器学习库,如 TensorFlow、PyTorch、Keras 或 SciKit-Learn,通常会形成这种工作流的主干,但仍然有来自不同库的无数功能,通常需要串在一起才能完成工作流。
例如,考虑一个图像识别工作流,您需要从 HDFS 获取图像;在这些图像上拟合 Keras 模型;使用 SciKit-Learn 评估模型;在 AWS 上将训练好的模型保存到 S3;在 MongoDB 中存储训练运行的元数据;并最终使用 TensorFlow 服务来服务模型。你如何建立这样的工作流程?
此外,如果您的需求在项目中途发生变化,以至于您需要从其他地方获取数据,或者需要使用不同的机器学习引擎,该怎么办?你将如何拔掉这些组件中的一个并用另一个替换它?您需要引入多少新代码(和测试!)才能让这个正常工作?
机器学习工作流程的上帝使者
这些是我们在 Alexander Thamm 为客户开发机器学习解决方案时经常面临的一些非常现实的问题。
最近,我们很清楚,我们需要一个能够将机器学习项目分解成典型组件(如读取数据、转换数据、拟合模型、评估模型、服务模型等)的库。)足够模块化和通用,允许我们根据需要插入不同的技术。
最初是一个帮助我们更好地完成自己工作的内部项目,现在已经发展成为我们认为值得作为开源库提供给更广泛的社区的东西。因此,我们决定让 Mercury-ML——我们内部开发的“机器学习之神的使者”——在 MIT 许可下在 GitHub 上可用。
最新的稳定版本也将始终在 PyPi 上提供,并且可以使用“pip install mercury-ml”进行安装
(注意,尽管这个库已经有了丰富的特性,但它还远远没有达到特性的完备。我们暂时将它标记为“预发布”,这意味着一些大范围的变化仍然可能发生。
工作原理
Mercury-ML 旨在提供对不同抽象层次功能的简化访问。
作为这种工作方式的一个简单例子,让我们看看通常构成机器学习工作流一部分的两个小组件:保存拟合的模型,然后将保存的对象存储在远程位置(以后可以从该位置提供服务)。为此,我们将考察四个抽象层次:
- 不使用 Mercury-ML(即直接使用底层依赖关系)
- 使用提供者 API
- 使用容器 API
- 使用任务 API(结合容器 API)
这些方法中的每一种都是完全有效的,尽管在某些情况下一种可能比另一种更有意义。让我们来看看:
参数化:
对于这个例子,我们将保存一个 Keras 模型,并将其存储到 AWS 上的 S3 存储桶中。假设我们有以下输入:
model = … # assume a fitted Keras model fetched here
filename = “my_model”
local_dir = “./local_models”
extension = “.h5”
remote_dir = “my-bucket/remote-model”
1。通过直接访问底层库(即不使用 Mercury-ML)的示例
当您希望最大限度地灵活配置如何使用这些库时,使用底层库而不是使用 Mercury-ML API 是有意义的。下面是一个典型的脚本,你可以把它放在一起。
import os**# save model**
if not os.path.exists(local_dir):
os.makedirs(local_dir)filename = filename + extension
local_path = os.path.join(local_dir + "/" + filename)
model.save(local_path)**# copy to s3**
import boto3
session = boto3.Session() #assuming connection parameters are implicit
s3 = session.resource("s3")s3_bucket, s3_partial_key = remote_dir.split("/", 1)
s3_key = s3_partial_key + "/" + filename + extension
s3.Object(s3_bucket, s3_key).put(Body=open(local_path, "rb"))
这里没有什么特别复杂的东西,但是有许多小步骤需要正确执行。您需要手动检查您希望在本地保存您的模型的目录是否存在(并且必须注意 Keras 不会为您这样做)。您必须知道,Keras 将其模型对象保存为 HDF5 文件,扩展名为“. h5”。您必须知道如何打开一个 S3 连接,并且知道保存到 S3 位置的函数调用需要“桶”和“键”输入(这两个输入放在一起可以简化为“路径”)。要做到这一点,你必须处理大量连接和分离字符串路径的调用。
(例如,如果您决定将您的模型对象存储在 Google 云存储中,您将需要再次这样做)。
2。供应商示例
Mercury-ML 中的提供者旨在将大部分内容抽象出来,并在公开一个简单的(但也是高度可配置的)API 的同时处理好细节。
from mercury_ml.keras.providers import model_saving
from mercury_ml.common.providers.artifact_copying import from_disk
import os**# save model**
path = model_saving.save_keras_hdf5(
model=model,
filename=filename,
local_dir=local_dir,
extension=extension
)**# copy to s3**
from_disk.copy_from_disk_to_s3(
source_dir=local_dir,
target_dir=remote_dir,
filename=os.path.basename(path)
)
如果您想要硬编码您想要使用的提供者,使用提供者 API(而不是任务 API 的容器)是最有意义的。例如在上面的代码片段中,你只能使用model _ saving . save _ keras _ HD F5和from _ disk . copy _ from _ disk _ to _ S3。
如果您想要以不同的格式保存模型,或者将它复制到不同的存储中,那么您必须更改您的代码来做到这一点。例如,要存储到 Google 云存储中,您可以将from _ disk . copy _ from _ disk _ to _ S3替换为from _ disk . copy _ from _ disk _ to _ GCS。
3。通过容器的示例
当您希望通过配置文件来控制工作流时,使用容器 API 是最有意义的。
容器只是轻量级的类,允许您从一个位置访问各种类似的提供者。例如,上面使用的函数model _ saving . save _ keras _ HD F5也可以通过容器 ModelSavers.save_hdf5 来访问。使用 getattr 函数,这也可以作为 getattr(ModelSavers," save_hdf5") 访问,使我们可以在配置中轻松地对其进行参数化。
from mercury_ml.keras.containers import ModelSavers
from mercury_ml.common.containers import ArtifactCopiers
import osconfig = {
"save_model": "save_hdf5",
"copy_model": "copy_from_disk_to_s3"
}save_model = getattr(ModelSavers, config["save_model"])copy_from_local_to_remote = getattr(
ArtifactCopiers,
config["copy_model"]
)**# save model**
path = save_model(
model=model,
filename=filename,
local_dir=local_dir,
extension=extension
)**# copy to s3**
copy_from_local_to_remote(
source_dir=local_dir,
target_dir=remote_dir,
filename=os.path.basename(path)
)
想要将模型保存为张量流图吗?而想将其存储在谷歌云存储中?只需更改配置:
config = {
"save_model": "save_tensorflow_graph",
"copy_model": "copy_from_disk_to_gcs"
}
4。示例通过任务(与容器一起)
当您想要使用单个函数来定义涉及多个提供者并需要多个步骤的小型工作流时,使用 tasks API 是有意义的。例如,下面的 store_model 任务被注入了一个 save_model 和一个copy _ from _ local _ to _ remote提供程序,并继续使用这些提供程序首先在本地保存模型,然后将其复制到远程位置。
from mercury_ml.keras.containers import ModelSaversfrom mercury_ml.common.containers import ArtifactCopiers
from mercury_ml.common.tasks import store_modelsave_model = getattr(ModelSavers, config["save_model"])
copy_from_local_to_remote = getattr(
ArtifactCopiers,
config["copy_model"]
)**# save model and copy to s3**
store_model(
save_model=save_model,
copy_from_local_to_remote=copy_from_local_to_remote,
model=model,
filename=filename,
local_dir=local_dir,
remote_dir=local_dir,
extension=extension
)
tasks API 比其他任何东西都更方便,但是对于经常一起出现的小块工作流来说非常有用。
了解更多信息
以上只是一个小例子。完全成熟的示例工作流可以在这里找到。
Mercury-ML 能够促进工作流的一个关键因素也与它在机器学习管道的各个阶段处理数据的方式有关。Mercury-ML 将数据包装成通用的 DataWrapper 对象(例如“特征”和“目标”),并将它们排列成数据集(例如“训练”、“有效”和“测试”),并最终排列成数据组。你可以在这里找到更多关于如何做的信息。
成为投稿人!
这也是对任何对使用 Mercury-ML 感兴趣的开发人员的公开邀请。告诉我们您需要什么功能,让我们知道哪些功能不起作用,或者贡献您自己的更改或添加内容!
引入模型偏差和方差
模型拟合平衡法
在之前的一篇文章中,我们讨论了模型欠拟合和过拟合的概念。本质上,这两个概念描述了模型无法匹配数据集的不同方式。拟合不足是指建立的模型不够复杂,无法准确地表示数据,并且错过了数据集中的趋势。过度拟合是指模型对于数据集来说过于复杂,并且认为数据集中有趋势,而实际上没有。
思考这些问题的另一种方式是通过偏差和方差这两个术语。这两个术语是数据科学中的附加基本概念,代表了思考模型拟合挑战的另一种方式。理解这两个概念将有助于您创建有用的模拟模型。
什么是模型偏差和方差?
这两个术语都描述了当您使用给定数据集的不同部分重新训练模型时,模型是如何变化的。通过更改用于定型模型的数据集部分,可以更改描述生成的模型的函数。然而,不同结构的模型将以不同的方式响应新的数据集。偏差和方差描述了模型做出反应的两种不同方式。它们的定义如下:
偏差:偏差描述了模型与训练集的匹配程度。具有高偏差的模型不会紧密匹配数据集,而具有低偏差的模型会非常紧密地匹配数据集。偏差来自过于简单的模型,无法捕捉数据集中呈现的趋势。
方差:方差描述了当你使用数据集的不同部分训练一个模型时,它会发生多大的变化。具有高方差的模型将具有匹配提供给它的任何数据集的灵活性,每次都可能导致显著不同的模型。差异来自高度复杂的模型,使用了大量的特性。
通常,高偏差的模型具有低方差,高方差的模型具有低偏差。这是因为两者来自相反类型的模型。不够灵活以正确匹配数据集(高偏差)的模型也不够灵活以在给定不同数据集(低方差)时发生显著变化。
那些读过我之前关于欠拟合和过拟合的文章的人可能会注意到这些概念之间有很多相似之处。欠拟合模型通常具有高偏差和低方差。过度拟合模型通常具有高方差和低偏差。
偏倚和方差之间的权衡是什么?
偏差-方差权衡是数据科学中经常讨论的术语。这是因为您采取的减少偏差的措施(导致更好地拟合训练数据)将同时增加模型中的方差(导致更高的不良预测风险)。反之亦然;你所采取的减少方差的行动将会固有地增加偏差。
关于偏差方差权衡,我能做些什么?
重要的是要记住,增加方差并不总是一件坏事。欠拟合模型是欠拟合的,因为它没有足够的方差,导致持续的高偏差误差。这意味着,当开发一个模型时,你需要找到合适的方差,或者合适的模型复杂度。关键是增加模型的复杂性,从而减少偏差和增加方差,直到偏差最小化,并且在显著的方差误差变得明显之前。
另一个解决方案是增加用于训练模型的数据集的大小。高方差误差,也称为过度拟合模型,来自于创建对于可用数据集来说过于复杂的模型。如果您能够使用更多的数据来训练模型,那么您可以创建一个更复杂的模型,而不会意外地添加方差误差。
不幸的是,这种技巧无助于降低偏置误差。低偏差模型或欠拟合模型对训练数据不敏感。因此,增加数据集的大小不会显著改善模型;它无法对变化做出反应。高偏差的解决方案是更高的方差,这通常意味着添加更多的数据。
我可以在哪里了解更多信息?
我写过几篇类似主题的文章。一篇,在本文中已经链接了几次,讨论了欠拟合和过拟合模型的细节,并给出了相关的例子。第二个从概念上讨论了模型开发、验证和测试的过程,您可以用它来确定模型何时非常适合数据集。此过程将帮助您确定模型中的方差是否正确,并帮助您确定是否需要添加更多数据。
最后,通过阅读 Joel Grus 的书数据科学从零开始:Python 的基本原则,我学到了很多数据科学的概念。他的书介绍了数据科学的许多基本概念,并提供了示例代码来帮助您用 python 开发一些初始函数。
将这一切结合在一起
偏差和方差是数据科学和模型开发中的两个关键术语。它们一起描述了创建模型时可能出现的两个关键错误。偏差指的是所有点上的恒定误差,代表一个不够复杂的模型来捕获数据集。方差是指对于数据集来说过于复杂的模型,通常表现为好像数据集中存在实际不存在的趋势。
这两种误差导致了著名的偏差-方差权衡。模型中高偏差的解决方案是增加更多的方差。但是加太多方差会导致方差误差。因此,创建具有足够方差的模型以捕获数据集并减少偏差误差,而不是创建具有太多方差以至于增加方差误差的模型,就变成了一种平衡行为。
如果不可能找到一个低偏差和低方差误差的解决方案,你需要找到并添加更多的数据。较大的数据集允许您创建更复杂的模型,而不会增加显著的方差误差。通过这种方式,您可以创建一个足够复杂的模型来最小化偏差误差,同时又不会复杂到增加显著的方差误差。
熊猫介绍-日志
用于调试 pandas 操作的新 Python 包
Photo by billow926 on Unsplash
熊猫生态系统对于数据科学生态系统来说是无价的,因此今天大多数数据科学任务由熊猫将原始数据转换成可理解/可用格式的一系列步骤组成。
这些步骤的准确性至关重要,因此理解意外的结果也变得至关重要。不幸的是,生态系统缺乏理解这些意外结果的工具。
这就是为什么我创建了熊猫日志,它提供了每个操作的元数据,这将允许查明问题。比如说之后。查询它返回被过滤的行数。
和往常一样,我相信用一个例子更容易理解,所以我将使用口袋妖怪数据集来寻找*“谁是最弱的非传奇火口袋妖怪?”。*
Photo by Thimo Pedersen on Unsplash
那么谁是最弱的火口袋妖怪呢?
(笔记本代码的链接可在这里找到)
首先,我们将导入相关的包并读取我们的口袋妖怪数据集。
import pandas as pd
import numpy as np
import pandas_logdf = pd.read_csv("pokemon.csv")
df.head(10)
A sample of our dataset
要回答我们的问题,谁是最弱的非传奇火口袋妖怪,我们需要:
- 用
*.query()*
过滤掉传说中的口袋妖怪。 - 只保留火口袋妖怪使用
*.query()*
。 - 降传奇柱
*.drop()*
。 - 使用
*.nsmallest()*
保留其中最弱的口袋妖怪。
在代码中,它看起来像这样
res = (df.copy()
.query("legendary==0")
.query("type_1=='fire' or type_2=='fire'")
.drop("legendary", axis=1)
.nsmallest(1,"total"))
res
It resulted in empty dataframe
哦,NOO!!!我们的代码不起作用!!我们有一个空的数据框!!如果有一种方法来跟踪这些问题就好了!?幸运的是,这就是熊猫日志的作用!
通过在我们的示例中添加一个小的上下文管理器,我们将获得相关的信息,帮助我们找到打印到 stdout 的问题。
with pandas_log.enable():
res = (df.copy()
.query("legendary==0")
.query("type_1=='fire' or type_2=='fire'")
.drop("legendary", axis=1)
.nsmallest(1,"total"))
在阅读输出后,很明显问题出在第 2 步,因为**我们还剩下 0 行,*所以谓词“type _ 1 = = ’ fire '或 type_2=='fire '”是错误的。*的确口袋妖怪类型是以大写字母开头的,所以让我们运行固定代码。
res = (df.copy()
.query("legendary==0")
.query("type_1=='Fire' or type_2=='Fire'")
.drop("legendary", axis=1)
.nsmallest(1,"total"))
res
最后,我们得到了我们的结果,我们得到了斯拉格马!!!!!!!!
最后几句话要说
该软件包仍处于早期阶段,所以它可能包含一些错误。请看看 Github 库,并建议一些代码的改进或扩展。我将很高兴地欢迎任何建设性的反馈,并随时为熊猫日志做贡献!😉
使用机器学习推荐 P2P 借贷投资
介绍 PeerVest:一个免费的 ML 应用程序,帮助你在风险回报的基础上选择最好的贷款池
问题
像 LendingClub 和 Prosper Marketplace 这样的 P2P 贷款市场是由连接投资者和借款者的经纪人费用驱动的。他们被激励去增加在他们平台上发生的交易的数量。在易用性的驱动下,他们现成的信用风险评估按分组桶对风险进行评分。在逐笔贷款的基础上,考虑到每笔贷款的独特性和从借款人那里收集的大量数据,这是低效的。在更精细、更连续的基础上对风险进行评分不仅是可能的,而且优于离散的分组桶。
信用风险是所有 P2P 贷款投资者和债券投资者在做出明智决策时必须仔细考虑的问题。包括大型银行在内的机构一直在雇佣研究人员和定量分析师来争论和分析这些数据,希望对自己的风险回报评估更有信心。借款人未能支付所需款项导致本金和利息损失的潜在风险是什么?考虑到贷款的条件,投资者能期待什么样的回报?对于希望超越市场上现成顾问的普通投资者来说,应该有一种更简单、更容易使用的工具。
解决方案:PeerVest
PeerVest 帮助个人投资者扩大他们的投资组合,通过使用基于 LendingClub.com 历史贷款数据训练的机器学习来评估风险和预测回报,智能地将资金分配到 P2P 贷款市场。PeerVest 根据用户的可用资金、最大风险承受能力和最低预期年化回报,推荐最佳投资贷款。有很多机构在利用现代的替代数据集评估信用风险和预测投资潜力方面处于思想领先地位,但我将这个问题简化为两个关键模型:(1)通过预测贷款违约的概率来评估风险,以及(2)预测年化回报。
重要术语和概念
- 点对点借贷(又称 P2P,Crowdlending) :通过在线服务撮合借贷者向个人或企业放贷的行为。由于其纯在线性质和低管理费用,一般来说,与银行提供的储蓄和投资产品相比,贷款人可以获得更高的回报,而借款人可以以更低的利率借钱。
- **人工神经网络:**一种计算学习系统,它使用一个函数网络来理解一种形式的数据输入,并将其转换为所需的输出,通常是另一种形式。灵感来自于人类大脑神经元共同运作来理解人类感官输入的方式。在此了解更多信息
- **随机森林模型:**一种用于分类、回归和其他任务的集成学习方法,通过在训练时构建大量决策树并输出作为类的模式或个体树的均值预测的类来进行操作。点击此处了解更多信息
- **违约概率:**对借款人无法履行债务的可能性的估计。在此了解更多信息
- **年化回报率:**按比例缩减至 12 个月的回报率。我使用的公式是:ar =(xTP/xLA)^(365/d)-1,其中 xla 是贷款金额,xtp 是借款人支付的总付款额,d 是贷款资金和最后一次付款日期之间的天数。点击此处了解更多信息
预测违约概率
为了给每笔贷款分配一个数量来衡量其风险水平,或借款人违约的概率,我像处理一个标准的分类问题一样处理这个问题,其中如果每笔历史贷款已全额偿还,则分配 1,如果违约,则分配 0。为了提供比 LendingClub 和类似网站提供的更精细的风险评估,我不是寻找类别(1 或 0),而是寻找每笔贷款预计落入每个类别的概率。我最初的方法是使用逻辑回归,尽管对每笔贷款进行了非常自信的分类,尽管进行了概率校准,但似乎与 sklearn 的没有很好的互动。predict_proba() 函数。此函数返回一笔贷款属于类别 1 的概率,介于 0 和 1 之间。用 1 减去这个数字就可以得到一个可解释的违约概率指标(它越大,违约的可能性就越大)。
给定 1,107 个独特的特征,似乎存在许多非线性关系,并且手动减少维度的努力将是麻烦的。使用主成分分析并没有真正的好处,因为它并没有改善这种情况——它降低了维数,减少了等量的解释方差。我决定保留所有的特性,尽管特性冗余的可能性增加了。知道神经网络能够在许多训练时期处理这种复杂性,我开始使用 Keras 构建一个模型,Keras 是一个基于 TensorFlow 的神经网络库。我通过使用隐藏层大小、丢失正则化、L2 核正则化、早期停止、历元、类权重平衡和 ReLU/Sigmoid 激活函数的不同组合,遍历了许多不同的 Keras 架构。尽管在验证损失方面存在一些停滞,但该模型最终取得了突破,并在几个时期内开始对训练集和测试集进行更显著的改进,同时非常好地校准了预测概率。
表现不佳: 3 个 Scikit-Learn 逻辑回归模型,7 个 Keras 神经网络
表现最佳: Keras 神经网络 v8
最佳神经网络模型架构:
输入层(1107,Sigmoid)>
密集层(1000,Sigmoid,L2)>
密集层(300,Sigmoid)>
密集层(50,Sigmoid,L2)>
密集输出层(1,Sigmoid,L2)
最佳模型参数:
最佳模型评估指标(测试误差):
- 完全支付的精确度:0.943
- 召回全额支付:0.979
- F-1 分数完全支付:0.961
- ROC-AUC 评分:0.86
- 预测概率已校准
预测回报
我根据 LendingClub 的可用数据,使用了一个非常简单的年化回报计算方法。由于可解释性,我决定不使用 LendingClub 复杂的调整后净年化回报计算,尽管随着我继续迭代我的模型,我对利用更传统的财务损失估计的精确计算持开放态度。与贷款条款和付款相关的时间因素包含在这一计算中。像联邦利率、通货膨胀和货币的时间价值这样的宏观信息是借款人所报利率中固有的,尽管当然有深入时间序列和生存分析的空间,以增加金融机构生产这种模型的严谨性。
线性回归在训练集上运行良好,但是过度拟合,不能很好地推广到未来集或同一时期的测试集。岭回归,这是类似的,但应用 L2 正则化修复了我的第二次迭代过度拟合的问题。也就是说,我想知道如果使用一些可以做出不同回归决策的东西,我的评估指标是否会有所改善,以及是否有一个模型不那么依赖于总付款,以便我的预测可以用于 LendingClub 上一个没有付款历史的全新列表。考虑到过度拟合的问题,以及其已被证明的引导特征子样本和聚集许多决策树的能力,Random Forest 是完美的候选。简而言之,一个随机森林将能够构建和组合许多彼此不相关的不太好的模型,以创建一个单一的、体面的模型——同时配备处理我的 1,107 个特征,除了找到最佳参数之外,没有太多额外的准备。鉴于 Google Cloud GPU 的强大功能,我让 GridSearchCV 通过搜索最佳组合来处理这个问题。
表现不佳: 1 个线性回归模型,3 个岭回归模型,1 个 Keras 神经网络,4 个随机森林回归模型(使用 Scikit-Learn)
表现最佳:随机森林回归 v5 与 GridSearch 交叉验证
最佳模型参数:
- n _ 估计值= 100
- 最大深度:15
- 最小 _ 样本 _ 叶:4
- 最小 _ 样本 _ 分割:2
最佳模型评估指标(测试误差—不包括支付历史):
- r 平方值:0.56
- 均方差:0.02
- 均方根误差:0.16
最佳随机森林回归模型在测试集上实现了 0.16 的均方根误差,这意味着预测的年化回报估计与真实的年化回报相差 0.16。虽然这可能会出现很大的第一,该模型可以非常有用的制定贷款选择策略。贷款违约通常发生在贷款融资后不久,违约的机会随着付款的增加而减少。因此,我推荐年化回报预测高于用户设定的合理阈值的贷款。直观上,阈值可以作为投资者可以根据其投资账户规模进行调整的参数:最小年化回报(较高回报)越大,最大违约概率越小(较低风险),整体贷款选择越严格,因此可以投资的总美元数越少。希望由于更有选择性地投资贷款,年化回报会更高。
也就是说,如果我们对借款人的还款历史有所了解,我们会对自己的预测更有信心,尽管在实践中,作为投资者,我们无法将最初的借款还款行为纳入其中。也就是说,有了一些支付历史记录,这个模型有了很大的改进:
评估指标(测试错误—如果包括支付历史):
- r 平方值:0.97
- 均方差:0.001
- 均方根误差:0.04
如何配合 LendingClub.com 使用 PeerVest 应用程序
这个应用程序是免费使用的。如果你决定将我的模型应用到你自己的投资组合中,对我来说没有任何费用或好处。我不是任何形式的注册财务顾问——投资风险自担。
该模型已经作为 Flask 应用程序部署在 web 上,托管在 Amazon Web Services EC2 实例上,使用 HTML、CSS 和 Brython。它可以收集用户的最大风险承受能力和他们相应的最小期望投资组合回报,并根据我的模型的建议,输出目前在 LendingClub.com 生活的贷款的综合列表。
- 访问 peer vest:www . peer vest . online
- 下载推荐 CSV
- 使用下载的 CSV 中的贷款 id 来指导您对 LendingClub.com 的投资!点击路径:点击此处 >登录(或创建账户)>投资>手动投资>更多过滤器>按贷款 ID 过滤>添加美元
关于最优多元化的说明:
- 在任何给定的时间内,LendingClub.com 上的可用投资往往少于 100 项,尽管一个优化的贷款组合应该包含至少 100 项不同的贷款,以充分降低缺乏多样化的风险。实际上,我会在接下来的几周里继续使用这个应用来指导新的投资。尽快找到 100 笔贷款的投资组合,适当分散投资。
- 来自 LendingClub:票据总数少于 100 张的账户更有可能出现负回报
未来的工作——示例用户故事
- 我想知道应用程序的推荐是否一定会比现成的 LendingClub/Prosper 推荐更能让我赚钱
- 我希望所有新上市的产品都出现在推荐集中,这样我的投资决策就可以基于最近的更新
- 我希望能够通过贷款目的进行筛选,这样我就可以策划一个任务驱动的贷款集
- 我想看看 P2P 贷款平台是如何设定利率的
- 我希望看到一个 Python 代码输出,我可以使用它来根据建议集执行我自己的订单,以减少手动分配时间
感谢您的阅读,
亚历克斯
来连线吧!我鼓励你评论、分享或直接给我发消息,告诉我你对这里提出的想法的想法,或者对我今后应该关注的有趣话题的建议。
(http://www.peervest.online)使用神经网络(分类、概率…
github.com](https://github.com/as6140/peervest)
来自《走向数据科学》编辑的注释: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
介绍 SHAP 决策图
更加详细和灵活地可视化机器学习模型的内部工作方式
SHAP(SHapley Additive exPlanations)框架已经被证明是机器学习模型解释领域的一个重要进步。由 Scott Lundberg 和 Su-In Lee 开发的 SHAP 结合了几种现有的方法,创建了一种直观的、理论上合理的方法来解释任何模型的预测。
SHAP 通过对每一个预测和特征提出同样的问题来建立模型解释:“当特征 j 从模型中移除时,预测 i 如何变化?”所谓的 SHAP 值就是答案。它们量化了特征对预测影响的大小和方向(积极或消极)。正如本文将展示的,SHAP 值可以用线性模型的清晰性来产生模型解释。
由 Scott Lundberg 等人开发的 Python 软件包 shap 提供了计算和绘制 shap 值的工具。项目的主页展示了典型的 SHAP 图,并提供了示例笔记本的链接。
最近,称为决策图的一类新图被添加到形状包中。决策图提供了模型内部工作的详细视图;也就是说,它们展示了模型是如何做出决策的。本文简要介绍了决策图的几个用例:
- 清晰展现大量特色效果。
- 可视化多输出预测。
- 显示互动的累积效果。
- 探索一系列特征值的特征效果。
- 比较和对比几个模型的预测。
- 识别典型的预测路径。
**更新:**除了学习 SHAP,我推荐探索 interpretML 包中可解释的助推机器(EBM)(官方文件,视频)。循证医学本身是可以解释的,相关的包包括互动的情节。interpretML 还集成了 SHAP,以及其他方法/模型,便于并行比较。
清晰显示大量特征效果
迄今为止,力图(在自然 BME 中介绍)一直是通过 shap 包可视化单个模型预测的默认方法。考虑以下情节。它显示了根据 UCI 成人收入数据集训练的 LightGBM 模型的预测。预测是个人年收入超过 5 万美元的概率。红色箭头表示提高预测值的要素效果(SHAP 值),而蓝色箭头表示降低预测值的效果。每个箭头的大小代表相应特征的影响程度。“基础值”(见图像左上角的灰色印记)标记了模型对训练集的平均预测。“输出值”是模型的预测:概率 0.64。最大影响的特征值打印在图的底部。总的来说,力图为这个预测提供了一个有效的总结。
将上面的力图与下面的决策图进行比较。决策图的垂直直线标记了模型的基础值。这条彩色的线是预测。特征值打印在预测线旁边,以供参考。从图的底部开始,预测线显示了 SHAP 值(即特征效果)如何从基础值累积到图顶部的模型最终得分。(粗略地说,这类似于统计线性模型,其中效应之和加上截距等于预测。)决策图是 SHAP 值的文字表示,使它们易于解释。
力图和决策图都有效地解释了前述模型的预测。主要影响的大小和方向很容易识别。然而,正如我们接下来将展示的,当涉及许多重要特征时,决策图比力图更有效。
下一个例子使用在 UCI 社区和犯罪数据集上训练的 LightGBM 模型来预测人口中每 10 万人中非暴力犯罪的数量。该模型使用了 101 个特征。使用力图和决策图解释了相同的预测。请注意,力图的水平格式使其无法清晰显示所有重要特征。
相比之下,决策图的垂直格式可以清楚地显示任意数量特征的影响。该图被配置为显示总共 101 个特征中的 30 个最重要的特征。
前面的例子表明,决策图在解释上类似于力图,但是决策图的线性、垂直格式允许描述更多的效果。
可视化多输出预测
决策图可以有效地解释多产出模型。这个例子解释了在 UCI 心脏病数据集上训练的一个分类模型 Catboost 。对于每个观察,有五个等级指示疾病的程度:等级 1 指示没有疾病;5 级表示晚期疾病。
下面的决策图显示了单次观察的模型的多个输出。在这种情况下,x 轴代表原始分数,而不是概率。分数包含在图的图例中,以便于识别。该模型预测类别 4(虚线)。该图显示,该模型自信地预测疾病存在(类别 1 具有非常低的分数),但是该模型不能轻易地区分类别 3、4 和 5。
熟悉 shap 包的人都知道,它为每个模型输出产生一个单独的基值。决策图显示模型基础值的平均值,并相应地移动 SHAP 值,以准确再现模型的得分。这种方法简化了可视化,并允许在相同的比例下绘制和比较任意数量的输出。
显示互动的累积效果
决策图支持 SHAP 相互作用值:从基于树的模型估计的一阶相互作用。与显示许多预测的单个相互作用的依赖图相反,决策图显示所有主要影响和相互作用。
这个决策图使用主效应和交互作用解释了来自 UCI 成人收入数据集的单一预测。它被配置为显示 20 个最重要的效果。该图清楚地表明,几个相互作用推动这一预测的得分更高。
探索一系列特征值的特征效果
决策图可以详细展示模型的行为。在此示例中,我们探讨了在给定的特定情况下,模型的预测如何随着特征值的变化而变化。我们从 UCI 成人收入数据集中的以下记录开始。
Age 56
Workclass Local-gov
Education-Num 13
Marital Status Married-civ-spouse
Occupation Tech-support
Relationship Husband
Race White
Sex Male
Capital Gain 0
Capital Loss 0
Hours per week 40
Country United-States
我们通过多次复制参考记录来创建一个合成数据集,但是以 100 美元为增量从 0 美元到 10,000 美元改变资本增值。这种方法允许我们评估和调试模型。分析师也可能会发现这种方法对提出假设情景很有用。请记住,本例中显示的资本收益的影响是特定于参考记录的,因此不能一概而论。
依赖图可以显示 SHAP 值在特性值范围内的变化。该模型的 SHAP 值代表对数概率的变化。该图显示了 SHAP 值在 5000 美元附近的急剧变化。它还在 0 美元和大约 3,000 美元处显示了一些重要的异常值。
尽管依赖图很有帮助,但在上下文中很难辨别 SHAP 值的实际效果。为此,我们可以用概率标度上的决策图来绘制合成数据集。首先,我们绘制参考记录来建立上下文。这些特征被手动排序以匹配随后的合成数据的绘图。预测是概率 0.76。资本收益为零,这种模式对资本收益的负面影响很小。
现在,我们绘制合成数据。参考记录用虚线突出显示。通过分层聚类对特征进行排序,以对相似的预测路径进行分组。我们看到,在实践中,资本收益的影响在很大程度上是两极化的;只有少数预测介于 0.2 和 0.8 之间。
在进一步检查预测后,我们发现阈值约为 4300 美元,但也有异常情况。0 美元、3,000 美元和 3,100 美元的资本收益有助于出乎意料的高预测;5000 美元的资本利得导致了出乎意料的低预测。这些异常在这里用图例标出,以帮助识别每个预测。3000 美元和 3100 美元的预测路径是相同的。
总的来说,使用决策图很容易解释模型行为,因为可以并排绘制几个预测的全部细节。本文中的其余示例也利用了这一特性。
比较和对比几个模型的预测
决策图对于比较不同模型的预测或解释模型集合的预测非常有用。
五个 LightGBM 模型的预测结果绘制如下,这些模型是在 T2 UCI 成人收入数据集中训练出来的。如果概率 0.5 是这个二元分类任务的阈值,我们看到这个观察值很难分类。然而,Model 2 确信个人年收入低于 5 万美元。如果这是一个典型的观察,那就值得研究一下为什么这个模型是不同的。
识别典型的预测路径
决策图可以展示模型的典型预测路径。在这里,我们将来自 UCI 成人收入数据集的所有预测绘制在概率区间【0.98,1.0】中,以查看高分预测的共同点。使用分层聚类对特征进行排序,以对相似的预测路径进行分组。该图显示了两条不同的路径:一条是由资本收益主导的,另一条是由资本损失主导的。与关系、年龄和教育相关的影响也是显著的。Alpha 混合(部分透明)用于指示高密度和低密度区域。
为了比较,这里显示了多预测力图。它是许多旋转 90 度并水平堆叠的单个力图的组合。这些情节之间有几个不同之处;我们将指出几个。力图显示,大约四分之三的预测遵循资本收益主导的预测路径。决策情节无法传达这种比例感。在力图中,左侧的预测并不明显是由资本损失主导的,除非在交互模式下查看,在这种模式下,鼠标悬停时会显示功能标签。此外,年龄和关系的一般模式并不突出。决策图更有效地揭示了这些方面。
结论
决策图是对形状包的自然补充。它们通过 SHAP 框架提供的简单性和清晰性有效地交流模型决策。它们也很灵活,允许从单一预测解释到模型诊断的各种用例。如果您发现了使用决策图的新方法,请发表评论。
向学生介绍自动化和机器人
Photo by Andy Kelly on Unsplash
这个领域没必要那么可怕
自动化很快就成了人们谈论的话题。政客们现在正围绕它展开竞选活动。整个公司都是建立在人工智能(AI)和机器人算法之上的。相关技术甚至已经开始渗入国内领域。一二十年后,我们与机器人和人工智能互动的频率可能会与我们与人类的互动相当。
然而,随着教育的发展,高中生所学的内容和工程领域的实用知识之间存在着差距。虽然有专门的学校致力于在计算机科学原理方面教育学生,早熟的学生组成了涉及现代领域的俱乐部,但大多数年轻人直到大学晚期才接触到高级课题。这是基于他们的大学有如此先进的领域的假设,而许多并没有。
令人担忧的是,就读 STEM 学院的学生对技术领域了解不足。他们可能会进入一个就业增长有限的领域。此外,未知的领域或主题可能会让人望而生畏。如果没有中学的初步介绍,学生可能会被阻止进入一个令人生畏的领域。老师也没有错。没有人能指望数学老师会熟悉机器人学中的数学。
为了向年轻人介绍这个领域,机器人技术可以大大简化。在大学里,我们学习开发机器人系统数学模型的最正规的方法。这样做主要是为了使分析策略能够被推广并应用到各种系统中。这样做,该领域需要彻底的线性代数和微分方程的先决知识。然而,许多基本的机器人系统可以简化成三角原理。
我想用一个简单的例子来证明这一点(如果数学很可怕,可以跳过图像)。也许一个雄心勃勃的数学老师可以找到在教案中实现这个概念的方法。在机械臂建模中,有正向和反向运动学的概念。当我们知道机器人关节之间的角度时,就可以使用正向运动学。知道了这些角度,我们就可以计算出手臂末端,也就是末端执行器,在三维坐标空间中的位置。这有助于检查机械臂是否处于预期位置。反向运动学可能更有用。反向运动学是指我们知道末端效应器在三维坐标空间中的位置。基于这个位置,我们想要计算手臂必须配置的关节角度,以实现这样的坐标。
一个典型的机械臂,一个具有三个旋转关节的三自由度机械臂,将是我们的测试示例。这个机器人有三个关节,每个关节都沿着一个轴旋转。我们通常将这个机器人简化为三个圆柱体,代表旋转关节,两个杆,代表实际的手臂。如果我们知道末端效应器需要的位置,那么我们可以很容易地使用三角形的切线属性(记住,SOH-CAH-TOA)找到第一个关节的角度(俯视图)。其他两个关节角度的值是使用机器人手臂的已知尺寸和末端执行器的位置的三角关系来求解的。
It’s just a bunch of triangles!
对于长期放弃数学的读者来说,上述内容可能令人望而生畏。然而,在一个上三角函数课的高中生的头脑中,上述内容并不陌生。除了向学生介绍机器人技术,上面的例子还回答了老生常谈的课堂问题:“我们什么时候会在现实生活中使用它?”。给学生一个任意科目的实际应用。
我的意思不是用上面的例子来概括机器人和自动化的整个领域。理解上述概念并不能使一个人成为机器人专家。然而,它可以激发学生的好奇心。
随着社会走向一个更加自动化的世界,预测什么将构成“现实生活”是一件棘手的事情。虽然不是每个学生都会继续从事自动化研究,但可能会需要相当于现代汽车修理工的机器人技术人员。在波士顿的一个机器人展示会上,我有幸听到波士顿动力公司的首席执行官马克·雷伯特博士展示他的机器狗。据雷伯特博士的技术员转述,他的预测之一是,机器人浪潮将创造我们尚未想象的工作岗位。
Would you like ice with that?
spot mini 等机器人被设计为室内家用机器人。也许一个网络工程师找到了一个聪明的方法,将齿轮控制的猎犬连接起来,递送食物和包裹。也许一个电机和嵌入式硬件的修补匠会发现机械狗有一个臭名昭著的小故障。像手机屏幕更换店一样频繁的维修店将会发展起来。这些知识中的大部分需要理解相当复杂的机制是如何运作的。
我们不应该回避复杂,以此作为避免阐述材料的理由。在以大猩猩玻璃产品闻名的陶瓷公司康宁公司实习时,我有幸与康宁创新部门的负责人交谈。该小组负责监控康宁公司哪些技术领域被低估了。
在我们的谈话中,我们谈到了人工智能和机器学习的话题。部门负责人向我解释说,公司已经在使用高中实习生通过张量流库实现机器学习算法。虽然一位资深的机器学习科学家可能会嘲笑张量流绝不是黑盒的概念,但孩子们能够操作工具的事实证明了他们的能力。为什么要浪费一个推动 STEM 感兴趣的学生超越教育部门构建的限制的机会呢?
介绍人工智能项目画布
人工智能项目管理
使用调整后的商业模式画布来推销你的下一个人工智能项目。
创造一个人工智能项目总是涉及到回答同样的问题:你增加的价值是什么?需要什么数据?客户是谁?预期的成本和收入是多少?
2008 年,Alexander Osterwalder 开发了商业模式画布,该画布在解释世界各地的商业模式方面取得了巨大成功。过去需要 30 页的商业计划来详述一个商业想法,现在可以在一页上完成。它与精益启动方法配合得很好,使您能够专注于增值活动,并快速创建 MVP 驱动的产品。
精益启动周期由构建-测量-学习反馈回路组成。作为一名数据科学家,你会接受这种精益方法。建立解决方案的原型并不断迭代直到达到关键指标是任何成功的人工智能项目的核心。因此,调整人工智能项目的商业模型画布是很自然的。
作为一名前管理顾问和数据科学的现任项目负责人,我的背景帮助我设计了 AI 项目画布。人工智能项目画布将帮助您回答关于您的人工智能项目所需的成果和资源的最紧迫的问题。这篇文章解释了人工智能项目画布以及真实世界的例子。在此下载可编辑的或空白画布。
我们开始吧。🖌 ⬜️
人工智能项目画布
想象以下场景:你对一个新的人工智能项目有一个绝妙的想法。要实现它,你需要说服管理层为你的想法提供资金。你需要向利益相关者和管理层推销你的人工智能项目想法。呸。
这是 AI 项目画布发挥作用的第一步。虽然 Louis Dorard 已经创建了 ML Canvas ,但 AI 项目 Canvas 的重点是解释你的 AI 项目的商业价值。人工智能项目画布帮助你构建并向他人传达你的人工智能项目的整体思想。
人工智能项目画布由四个不同的部分组成:作为项目中心部分的价值主张,左侧的成分,右侧的客户集成,以及底部的融资。所有这些部分都是任何人工智能项目的重要方面。让我们看一下每一部分,从价值主张开始。
人工智能项目画布的核心是价值主张。它解释了项目将为您的组织增加的价值。增值可以是一种新的人工智能产品,以产生收入,或改善现有流程以降低成本。AI 项目在解决什么客户痛点?您添加了哪些维生素来改善顾客的生活?理想情况下,您可以用一个简洁的要点来描述价值主张。列出许多价值主张可能会淡化影响,或者未能关注最重要的价值主张。
旁注:尝试一种听起来很酷的新论文不会让你走得很远。你的 AI 项目的附加值是什么?充分回答这个问题有助于你专注于手头的任务,并让你为你的人工智能项目获得一半的资金。接下来让我们看看配料块。
成分部分由数据、技能和输出块组成。
数据是每个人工智能项目所依赖的主要元素。你越能解释你需要什么数据来创造价值主张,对你的人工智能项目就越好。你需要多少数据?您是否已经有一个准备好的数据集,或者您是否需要获取它?一定要贴标签吗?你期望什么样的数据格式?
在技能模块中,您将定义您需要的专业技能。是计算机视觉还是自然语言理解任务?需要数据工程师帮你写高效软件吗?甚至可能是一个产品经理和一个 UX 设计师来收集客户需求并设计一个工作流程?
输出块显示了您正在评估的单个关键指标。吴恩达在他的书机器学习的渴望第八章中建议在项目开始前定义一个单一数字的评估指标。这有助于您首先选择一个好的模型,然后根据这个指标比较不同模型的性能。输出指标可以是准确度、f1 分数、精确度或召回率、使用服务的时间等。可以用足够的度量来补充输出度量,例如,精度必须超过 95%(关键度量),而推理时间不超过 1 秒(足够的度量)。
在解释了你的 AI 项目的成分部分之后,接下来我们来谈谈你将如何把你的 AI 项目带给客户。
AI 项目画布的右边部分涵盖了将您的项目集成到当前的基础设施中,供利益相关者和客户使用。
人工智能产品很少生活在一个孤立的世界中,几乎没有在 Jupyter 笔记本中。它们总是需要集成到现有的架构中。解释项目将用于何处以及如何使用。它在后端的什么位置?客户将如何使用您的模型?在流式传输期间,您会使用微服务、整体服务还是动态预测?回答这些问题将使人们清楚这个项目将如何投入生产。
列出关键利益相关者会让你对重要的决策者有一个大致的了解。关键利益相关者可以是法律、UX、管理等内部部门,甚至是承包商、所有者、政治或非盈利组织等外部利益相关者。
最右边的部分是价值主张之后第二重要的部分。你为谁设计项目?很多时候,数据科学家爱上了他们模型的技术细节,但却不知道他们在为谁开发模型。客户真的关心准确性从 99.2%提高到 99.3%吗?还是更快的推断时间更适合他们?详细描述您的不同客户群,以指导您在整个过程中的决策。
在定义了如何将项目带给客户之后,我们最后来探讨一下你的 AI 项目的财务要求。
任何项目都需要有良好的财务基础。回答关于成本和收入的问题将使你处于一个强有力的位置来解释为什么你的人工智能项目应该得到资助。
成本块详细列出了将要发生的成本。需要外包贴标吗?您会产生计算成本吗?不要忘记提及你的团队成员花费的时间或薪水。你不必写下绝对成本,给出成本类别的概述就足够了。
最后,收入块显示你的人工智能项目将如何使公司获得新的收入。该产品将作为一项服务出售,还是作为用户的新功能类别出售?该项目是否会通过自动化流程降低内部成本或支持创新计划?提及收入类型是任何人工智能项目的重要组成部分。
总结一下 AI 项目画布,看看上图中的循环依赖。为了达到目标产量,你需要花费成本来与关键技能争论数据。有了这个模型,你将为组织提出新的价值。然后,在与涉众沟通的同时,将产品整合到现有的架构中。客户将从您的项目中受益,从而为您的公司创造收入。
理论够了。在解释了 AI 项目画布背后的理论之后,接下来让我们看一个真实世界的例子。
人工智能项目画布示例
在之前的帖子中,您了解到了真实世界的数据科学项目,该项目对汽车记录的面部进行匿名处理,以保护个人隐私。让我们为这个项目创建 AI 项目画布。
价值主张很简单:保护个人隐私。这将建立信任,缓解法律担忧,并仍然使该公司能够收集开发自动驾驶汽车所需的数据。
接下来,我们将了解创建价值主张所需的要素。找出数据块是配料管道中最重要的部分。由于我们将使用预先训练的模型,我们至少需要一个现实的验证和测试集来评估不同的模型。比方说,我们需要 10k 张从汽车视角拍摄的带标记人脸的图像。我们决定获取一个特定于我们用例的新数据集。
在技能模块中,我们列出了计算机视觉技能。我们将在 Python 中实现模型,可能需要数据工程技能来生产模型。
输出模块的关键指标已由 OKRs 定义,如本帖子中所定义。我们需要在检测 IoU 为> 0.5 的人脸时达到 95%的准确率。现在不需要足够的度量。
接下来,我们进入价值创造部分。
该项目将通过微服务整合到当前的视频提取服务中。开发者可以调用 API 来匿名化他们的图片。
关键利益相关者是法律部门,因为他们必须决定服务何时提供法律利益。其他利益相关者是一般管理人员,因为他们赞助这个项目。
谁将是这个项目的客户?数据驱动的汽车功能开发人员从匿名化中获益,因为他们可以访问自己的数据集,也可能访问其他人的数据集。工程师是我们最有价值的客户。
最后但同样重要的是,我们将描述我们项目的财务状况。
对于成本模块,我们需要一名数据科学家三个月的时间。我们还需要签约一家标签公司来收集和标记我们的训练数据。此外,我们还会产生云计算成本。
为了获得收入,这种匿名化微服务可以在软件即服务的基础上获得许可。
恭喜你,我们已经创建了我们的第一个人工智能项目画布!你看到这些部分是如何很好地组合在一起来展示这个项目的吗?
如果某些块在您的项目中不如其他块重要,请不要担心。重要的是,你已经考虑了这些块。
因此,我们对我们提出的人工智能项目有了一个全面的了解。我们知道我们试图创造什么价值。我们可以展示我们需要哪些数据和技能来创建一个输出。我们知道最终的模型将如何集成到现有的架构中,以及谁是我们的利益相关者和客户。最后,我们展示了我们预期的成本和收入。
关键要点
就像商业模型画布一样,人工智能项目画布是一个方便的工具,可以快速解释你的人工智能项目的附加值。它旨在用于向管理层、风险承担者和新团队成员解释项目的范围、目的和内容。使用人工智能项目画布来构建人工智能初创公司、人工智能产品和人工智能项目。它有助于你从客户的角度思考问题,设计出真正有影响力的人工智能项目。
- 使用人工智能项目画布向利益相关者和同事解释你的人工智能想法
- 重温人工智能项目画布,以客户为中心关注价值主张
- 确保考虑人工智能项目画布的所有区域
在这里下载 AI 项目画布。当决定接下来支持哪些人工智能项目时,我们将使用人工智能项目画布。你会吗?🖌 ⬜️
这篇文章是正在进行的系列文章的一部分,旨在教育数据科学家以客户为中心的思维和商业敏锐度。我们鼓励数据科学家摆脱“让我们实现这篇论文,看看会发生什么”的态度,转向“我们能产生什么价值”的态度。正如李开复指出的,我们正在进入人工智能实施的十年,需要冠军来生产机器学习模型。
如果你想了解最新消息,请考虑在 Medium 或 LinkedIn 上关注我。你也可能喜欢 这些 帖子。如果您认为应该在 AI 项目画布上添加一些内容,请发表评论。干杯!☮️
为文本分类模型引入“香蕉测试”
结合拼写纠正、术语过滤和“香蕉测试”来构建弹性文本分类模型。
Source: https://pixabay.com/photos/bananas-fruits-food-grocery-store-698608/
介绍
有 数百万 的实例表明,企业已经在他们的系统中收集了自由格式的文本。为了自动化利用这些数据的业务流程,自由格式的文本通常需要被划分到更高级别的类别中。文本分类模型能够快速有效地对这种自由形式的文本进行分类……在很大程度上。
不管报告的验证/测试准确性如何,有许多陷阱会导致即使是训练最良好的文本分类模型也无法进行准确的分类。特别是,文本分类模型在面对从未见过的文本时往往会失败。
如果您的目标是最大化新文本分类模型的准确性,您应该考虑使用香蕉测试。尽管名字很傻,但这是一种非常真实的技术,可以用来提高模型的质量。
什么是香蕉测试?
香蕉检验旨在作为一个决定因素(通常与置信区间相结合)来判断给定的分类是否可信。由于机器学习模型在默认情况下总是会对数据进行分类,并且它提供的置信区间只不过是对概率(而不是准确性)的一种度量,因此香蕉测试有助于确保模型只在有足够的训练数据来做出自信的决策时才对新数据进行分类。它是如何工作的以及它为什么重要都是非常简单的概念。
解释一下测试的名字,“香蕉”这个词从来没有和我工作过的任何公司有过关联。由于我在进入数据科学之前曾是一名产品负责人,我开始相信定义适当的验收标准对于开发一个好的产品至关重要。因此,作为正在构建的任何新文本分类模型的一种接受标准,我强制要求我的模型应该 从不 自信地对包含单词“banana”的文本字符串进行分类。
为什么不呢?嗯…
- 一个理想的文本分类模型应该在一个巨大的文本语料库上进行训练,这个语料库包含了在生产中出现的几乎每一个术语。
- 如果一个模型已经在一个非常大的数据堆上训练过,那么文本语料库中不存在的任何术语几乎肯定是奇怪或不寻常的。这表示术语可能与未经训练的类别、拼写错误或完全不符/错误的数据(例如,文本输入到错误的字段)相关联。
- 为了避免错误,模型应该只在它对正在查看的数据训练有素并且对答案非常有信心时才对文本进行分类。
- 如果一个模型从未在一个提供的文本字符串中看到一个或多个术语,那么就没有办法保证它有信心进行分类。在许多情况下,它仍然会得到正确的答案,但也有很大的机会,未经训练的术语可能会改变答案。为了追求完美,当面对从未见过的文本数据时,模型应该自我报告它不知道答案。理想情况下,模型还会对它未能识别的术语进行自我报告。
因此,香蕉测试就是将输入数据中要分类的术语列表与模型已训练的术语列表进行比较,并确定是否完全覆盖。如果有些术语不包含在定型数据中,则输入数据无法通过香蕉测试,可能不应该由模型进行分类。在 Python 中,使用集合交集(或许多其他解决方案)可以非常容易地做到这一点;具体实现看你了。
这种策略导致了精确和可靠的文本分类模型,代价是被分类记录的百分比略有降低。
实际例子
假设您正在训练一个 tensorflow 模型来区分啤酒和葡萄酒,输入数据以自由格式文本的形式提供。我们还假设您的模型接受最多五个术语(单词)作为基于记号化器和单词索引的填充数组。
在对一些训练数据进行预处理和标记后,您的单词索引可能看起来像这样:
{
"beer": 1,
"wine": 2,
"pinot": 3,
"noir": 4,
"chardonnay": 5
"lager": 6,
"cabernet": 7,
"cab": 8,
"rose": 9,
"ipa": 10,
"pilsner": 11,
"zinfandel": 12,
"chianti": 13,
"porter": 14,
"stout": 15,
"sauvignon": 16,
"red": 17,
"blend": 18,
"merlot": 19,
"ale": 20,
"mead": 21
}
根据上面的单词索引…
- 如果您向模型提供文本
"pinot noir"
,那么得到的数组将是[3, 4, 0, 0, 0]
。 - 如果您提供文本
"red blend"
,得到的数组将是[17, 18, 0, 0, 0]
。 - 如果您提供文本
"ipa"
,得到的数组将是[10, 0, 0, 0, 0]
。
这听起来不错。但是,您可以向这样的模型提供许多值,这会导致错误分类。例如…
- 如果您提供了文本
"banana"
,那么得到的数组将是[0, 0, 0, 0, 0]
。这个术语根本没有出现在单词 index 中,但是数组仍然是基于用来填充输入序列的函数创建的。对于在训练数据中出现频率最高的两个类别(啤酒或葡萄酒),生成的分类将显示较高的置信区间。解决这个问题的一个办法是在分类之前把所有的空数组都踢出去,然后就到此为止,但是… - 如果您提供了文本
"neither wine nor beer"
,那么得到的数组将是[0, 2, 0, 1, 0]
。假设您决定剔除空数组,模型仍然会有把握地错误分类这个记录。分类的置信区间也可能出人意料地高,这取决于两个类中的每一个有多少训练数据(即,如果有 300 条关于葡萄酒的训练数据记录,而只有 20 条关于啤酒的训练数据记录,则模型可能非常确信该输入属于葡萄酒类)。 - 如果您提供文本
"this is a beer"
,得到的数组将是[0, 0, 0, 1, 0]
。这个模型仍然可能正确地分类这个记录,但是输入可能会说"definitely not a beer"
,结果得到的数组会是完全相同的。 - 如果您提供了文本
"bourbon"
,那么得到的数组将是[0, 0, 0, 0, 0]
。这大概应该是一个全新的类(白酒)。
根据上面的例子,如果您的模型能够自我报告它看到了从未训练过的新术语,并避免对这些不一致的记录进行分类,这不是最好的吗?
通过在进行预测之前应用香蕉测试,您的模型将能够剔除上面的每一条记录,并提供一组未通过测试的术语,如bourbon
、banana
、definitely
等。这种方法可以让你创建一个非常有意义的反馈循环。这也意味着您可以将您的模型投入生产,并且知道它只会在识别每个术语时对记录进行分类。
香蕉测试的先决条件
应用香蕉测试时会出现一些问题。也就是说,香蕉测试可以标记在训练过程中被过滤掉的术语和/或不能识别拼写错误的术语。
以下步骤是我认为应用香蕉测试的先决条件,这样你就可以避免这样的问题。无论您决定如何对数据进行预处理,在训练过程和分类过程中都应该应用完全相同的步骤。
案例规范化
在训练文本分类模型或向其输入新数据进行分类之前,您几乎应该始终将文本规范化为单个大小写(通常为小写)。我说“几乎总是”是因为我确信有一些例外,其中大小写可能对模型有意义。
术语过滤
术语过滤并不总是必需的,但通常是推荐的。有些术语,甚至是停用词,对于提供长短期记忆(LSTM)层这样的东西的上下文可能仍然很重要。在从文本语料库中过滤太少或太多的术语之间,你需要找到一条微妙的界限。祝你好运。
拼写纠正
拼写纠正有助于规范化术语的变化,以便香蕉测试(以及一般的模型)尽可能有效。我过去使用的一种方法是使用字符串距离函数将文本语料库中最常出现的术语与文本语料库中的每一个其他术语进行比较。通过基于字符串距离分数过滤结果,数据中存在的许多拼写错误将会暴露出来。这种技术需要手动检查,但如果数据中的术语/拼写错误比一般的拼写自动纠正算法能够可靠处理的要复杂一些,通常会产生很好的结果。
香蕉船
香蕉船是对香蕉测试的可选增强(正如你现在所知道的,我喜欢为严肃的事物取愚蠢的名字)。简单地说,香蕉分裂是在执行香蕉测试之前,从文本语料库(基于 TF/IDF)中分离出总术语的前 N %的实践。
香蕉分裂很重要,因为文本语料库中最不常用的术语可能具有最少的与之相关联的训练数据。通过将香蕉分割应用到香蕉测试的实现中,您可以控制模型在对数据进行分类时的保守程度。模型见过(但可能很少见到)的术语可以被踢出去,就好像模型以前从未见过它们一样。
结论
尽管名字很有趣,方法也很简单,但这种技术对于制作能够有效处理新数据且错误最少的文本分类算法来说至关重要。到目前为止,它已经帮助我和我的团队大大提高了几十个模型的准确性和可靠性,并且已经成为我们的标准做法。我希望它也能让你受益,也许有一天我会听说其他人也在使用香蕉测试!
介绍四方模型:为了更精确的线性回归
为数据科学铺平道路是如此迷人。我认为创建一个模型来提高你的准确性,哪怕只是一点点,都是令人惊讶的。对我来说,我发现很少有事情比使用复杂的条件和数学公式来创建一些可以循环用来训练模型的东西更有趣。不仅如此,获得比传统模型更高的精度让它更加令人兴奋。
我觉得好像应该建立一些东西,不管有多好;事情总是要改进的,这在机器学习中尤其普遍。我喜欢数据科学的一点是,我可以在数学上、精神上有创造力和激情,同时还可以玩一些我最大的爱好。所以我向你们介绍:四方模型。在实践中,这是一个非常简单的模型,但在我迄今为止的经验中,这是一个非常有用的模型。
是什么样的?
如果您已经在数据科学领域工作过一段时间,您可能会想到所有的模型都是特定于案例的。为了选择一个模型,你首先需要知道你想要这个模型做什么。这类似于在软件工程的任何夸克中要求机器做某件事;如果你执行一行代码,你期望得到一定的回报。回报可能不总是我们想象的那样,但是,嘿,这就是编程。
所以,当然,我不能为不特别的用例推荐这个模型,我会为你解释这个模型背后的数学和软件。
这个模型,就像我说的,很简单。它使用第一、第二、第三和第四季度以及最小和最大数据将数据分类到不同的范围。然后用简单的线性模型来拟合这些范围。将来,我计划根据所述数据的计算方差来改变模型。该模型的用例正是具有高方差的数据。单价就是一个很好的例子。线性回归模型不太擅长预测单位数据,因为它受到线性度的限制。想象四条独立的线,四个独立的模型,每一个模型对应一个季度的数据。不用说,在某些情况下,对于连续特征,该模型比线性回归更准确。
它是机器学习算法的终极目标吗?不。但这就是数据科学的意义,实验。
当然,我将在本文中排除线性回归的使用。但这个实验是基于相同的数据,如果你想查看文章,这里是。一如既往,笔记本可以在这里买到。此外,我应该注意,如果您想使用该型号,它仅在不稳定的 0.0.2 版本中可用。优势当然是存在的,增加了更多的统计数据,标量,更多的验证,更多的模型。您可以通过以下方式添加它:
using Pkg
Pkg.add(url="[https://github.com/emmettgb/Lathe.jl](https://github.com/emmettgb/Lathe.jl)#Unstable")
要获得最新的稳定版本,只需移除#Unstable,或者放入#master
using Pkg
Pkg.add(url="[https://github.com/emmettgb/Lathe.jl](https://github.com/emmettgb/Lathe.jl)")
在不久的将来(未来几天),您将能够:
using Pkg
Pkg.add("Lathe")
安装和使用
那么这种模式有实际的需求吗?与传统的线性或逻辑模型相比,它有什么样的改进?嗯,我继续进行测试,当然是在我之前的努力中使用的相同的纽约市数据上,拟合线性回归。
我们可以像拟合线性回归一样拟合模型。
model = models.FourSquare(df.LotArea,df.SalePrice)
这将返回以下输出:
Lathe.models.FourSquare(Int64[8450, 9600, 11250, 9550, 14260, 14115, 10084, 10382, 6120, 7420 … 9000, 9262, 3675, 17217, 7500, 7917, 13175, 9042, 9717, 9937], Int64[208500, 181500, 223500, 140000, 250000, 143000, 307000, 200000, 129900, 118000 … 136000, 287090, 145000, 84500, 185000, 175000, 210000, 266500, 142125, 147500])
或者类似的东西。当然,我还拟合了一个线性回归模型来比较两者的准确性。
using Lathe: models
model = models.LinearRegression(df.LotArea,df.SalePrice)
太棒了,4 个系列中的 2 个合身款。
在用我的两个模型预测后,
testdf.linearreg = models.predict(model,testdf.LotArea)
testdf.foursqu = models.predict(model,testdf.LotArea)
我们有两个数组,最后可以比较一下,看看分数如何。到目前为止,我们仍然坚持使用 MAE,然而,0.0.2 将承诺 r2 也可以进行验证。这是我们得到的!:
linearacc = validate.mae(testdf.SalePrice,testdf.linearreg)
输出为:
173848.28232265453
173,000 并不是那么糟糕,考虑到这些数据只是被清理了一点点,然后直接扔进了模型。此外,在接下来的文章中,我计划实际上为此建立一个非常棒的模型,并使用车床获得相当高的精度,所以请继续关注。当然,你会想知道四方模型的精确度是多少?
foursqacc = validate.mae(testdf.SalePrice,testdf.foursqu)
我们高兴地迎接:
104892.39723066095
我当然会四舍五入这些数字,174 对 105。总误差在 65 左右。所以:不一定不可思议,但正如数据科学人士会注意到的那样,如此大的跳跃可能意义重大。当然,在我看来,对于这种比较,r 验证会更好。
但是…它是如何工作的?
该模型将从获取数据的长度开始,并比较适合的数组的长度。
x = m.x
y = m.y
# Go ahead and throw an error for the wrong input shape:
xlength = length(x)
ylength = length(y)
if xlength != ylength
throw(ArgumentError("The array shape does not match!"))
end
这只是为了确保数组形状是相同的,因为如果不是这样,模型就不会像我们希望的那样顺利。这是预测方法中最重要的等式:
# x = q1(r(floor:q1)) |x2 = q2(r(q1:μ)) |x3 = q3(r(q2:q3)) |x4 q4(r(q3:cieling))
# y' = q1(x * (a / x)) | μ(x * (a / x2)) | q3(x * (a / x3) | q4(x * (a / x4))
这到底是怎么回事?嗯,由于该模型专用于预测连续数据,所以我们根据数据排序时它所在的四分位数来拆分数据。因此,第一个范围是数据到第一个四分位数的最小值,这是数据的四分之一标记,第二个范围是第一个四分位数到第二个四分位数(中位数),以此类推。有几种方法可以做到这一点,我们可以使用 Lathe.stats.firstq 计算四分位数在哪里,当数据在较低范围内时,使用条件将数据追加到列表中,或者我们可以使用 Lathe.preprocess 中一个名为 SortSplit 的方法。SortSplit 自动对数据进行排序,取指定的最大百分比(默认为 0.25)并将其分成两个新数组。
# Quad Splitting the data ---->
# Split the Y
y2,range1 = Lathe.preprocess.SortSplit(y)
y3,range2 = Lathe.preprocess.SortSplit(y2)
y4,range3 = Lathe.preprocess.SortSplit(y3)
range4 = y4
# Split the x train
x1,xrange1 = Lathe.preprocess.SortSplit(x)
x2,xrange2 = Lathe.preprocess.SortSplit(x1)
x3,xrange3 = Lathe.preprocess.SortSplit(x2)
xrange4 = x3
本质上,我们把 x 和 y 分成下端,中下端,中上端和上端。SortSplit 方法是这样做的:
function SortSplit(data, at = 0.25, rev=false)
n = length(data)
sort!(data, rev=rev) # Sort in-place
train_idx = view(data, 1:floor(Int, at*n))
test_idx = view(data, (floor(Int, at*n)+1):n)
return(test_idx,train_idx)
end
它取数据的长度并将其相乘,然后用百分位倒数返回两个数据。
接下来,我们拟合出线性回归模型,每个季度一个数据。
# Fitting the 4 linear regression models ---->
regone = LinearRegression(xrange1,range1)
regtwo = LinearRegression(xrange2,range2)
regthree = LinearRegression(xrange3,range3)
regfour = LinearRegression(xrange4,range4)
# Split the train Data
xt1,xtrange1 = Lathe.preprocess.SortSplit(xt)
xt2,xtrange2 = Lathe.preprocess.SortSplit(xt1)
xt3,xtrange3 = Lathe.preprocess.SortSplit(xt2)
xtrange4 = xt3
# Get min-max
xtrange1min = minimum(xtrange1)
xtrange1max = maximum(xtrange1)
xtrange2min = minimum(xtrange2)
xtrange2max = maximum(xtrange2)
xtrange3min = minimum(xtrange3)
xtrange3max = maximum(xtrange3)
xtrange4min = minimum(xtrange4)
xtrange4max = maximum(xtrange4)
# Ranges for ifs
condrange1 = (xtrange1min:xtrange1max)
condrange2 = (xtrange2min:xtrange2max)
condrange3 = (xtrange3min:xtrange3max)
condrange4 = (xtrange4min:xtrange4max)
我们还获取了每个四分位数的范围,以便对我们的训练数据中的每个 x 进行分类。此外,我们必须创建一个空数组来追加数据。
e = []
然后,我们可以根据我们的迭代在 X 序列的哪个四分位数上继续使用预测方法:
for i in xt
if i in condrange1
ypred = predict(regone,i)
end
if i in condrange2
ypred = predict(regtwo,i)
end
if i in condrange3
ypred = predict(regthree,i)
end
if i in condrange4
ypred = predict(regfour,i)
end
append!(e,ypred)
end
return(e)
结果呢
当然,我们已经比较了结果,但如果我们将结果与我们的朋友线性回归进行比较,我们会发现,当关系发生变化时,FourSquare 模型能够发生变化。在某些类型的数据中肯定可以看到好处,包括我最初下载到来看看线性回归的随机数据。
以下是这些模型的可视化效果对比:
Linear Regression
Four-Square
这告诉我们什么?
如我们所见,我们有两条不同的线。如果我们使用线性回归,正如我们在上面看到的,方差较高的区域,也就是更接近底部的区域,完全被排除在方程之外,不会被忽略,但会稍微移动最佳拟合线。通过这个模型,我们得到了一条 4 向量自适应线。数据初始部分的斜率要陡得多,与数组其余部分相对平缓的性质相比,y 截距将直线推到了荒谬的水平。当接近下一个季度的数据时,我们看到预测突然转变。看起来前两个回归模型在一开始就出现了,在平方英尺的价格下降之前,斜率在接近结束时有一个相当大的弯曲。这是因为一次购买更多的土地当然总是更便宜。他们都出现在开始的原因很简单;我们的大部分数据都在那里。我们数据的中位数最有可能在 2000 点左右。
你可能会对自己说“哇,这太棒了,但它确实看起来很像逻辑回归。”虽然它是相似的,但这种模型在技术上是线性的,尽管它实际上是多线性的。
最后
虽然模型会有变化,也许会增加更多的划分,超参数来调整它们等等。我有兴趣听听其他数据科学家对这个模型的想法。
最后,我真的很享受扩展 Julia 包注册表的时光。如果你想通过 Github fork 学习更多知识或为车床做贡献,请点击这里的。我真诚地希望像我一样的其他人会觉得这个包有用。我当然很高兴能继续发展到测试版,甚至更高。
介绍 schrute 软件包:办公室的全部记录
文本数据集的集锦
这是一个只有一件事的软件包:办公室所有剧集的完整副本!(美版)。
使用这个数据集来掌握自然语言处理或文本分析。让我们从茱莉亚·西尔格和大卫·罗宾逊所著的优秀的《用 R 进行文本挖掘的 T4》一书中的几个例子来了解一下这个主题。
首先,从 CRAN 安装软件包:
# install.packages("schrute")
library(schrute)
schrute 包只有一个数据集;将它赋给一个变量
mydata <- schrute::theoffice
看一下格式:
dplyr::glimpse(mydata) #> Observations: 55,130 #> Variables: 7
#> $ index <int> 1, 358, 715, 1072, 1429, 1786, 2143, 2500, 2857... #> $ season <chr> "01", "01", "01", "01", "01", "01", "01", "01",... #> $ episode <chr> "01", "01", "01", "01", "01", "01", "01", "01",...
#> $ episode_name <chr> " Pilot", " Pilot", " Pilot", " Pilot", " Pilot...
#> $ character <chr> "Michael", "Jim", "Michael", "Jim", "Michael", ...
#> $ text <chr> " All right Jim. Your quarterlies look very goo... #> $ text_w_direction <chr> " All right Jim. Your quarterlies look very goo...mydata %>%
dplyr::filter(season == '01') %>%
dplyr::filter(episode == '01') %>%
dplyr::slice(1:3) %>%
knitr::kable()
所以我们有的是季节,集数和名字,人物,说的台词和跟舞台方向(cue)说的台词。
我们可以用 tidytext 包中的几行来标记所有的行:
token.mydata <- mydata %>%
tidytext::unnest_tokens(word, text)
这将我们的数据集增加到 575146 条记录,其中每条记录包含脚本中的一个单词。
token.mydata %>%
dplyr::filter(season == '01') %>%
dplyr::filter(episode == '01') %>%
dplyr::slice(1:3) %>%
knitr::kable()
如果我们想分析整个数据集,我们需要先删除一些停用词:
stop_words <- tidytext::stop_words tidy.token.mydata <- token.mydata %>% dplyr::anti_join(stop_words, by = "word")
然后看看最常见的单词是什么:
tidy.token.mydata %>%
dplyr::count(word, sort = TRUE)
#> # A tibble: 19,225 x 2
#> word n
#> <chr> <int>
#> 1 yeah 2895
#> 2 hey 2189
#> 3 michael 2054
#> 4 dwight 1540
#> 5 uh 1433
#> 6 gonna 1365
#> 7 jim 1345
#> 8 pam 1168
#> 9 time 1129
#> 10 guys 933
#> # ... with 19,215 more rowstidy.token.mydata %>%
dplyr::count(word, sort = TRUE) %>%
dplyr::filter(n > 400) %>%
dplyr::mutate(word = stats::reorder(word, n)) %>% ggplot2::ggplot(ggplot2::aes(word, n)) +
ggplot2::geom_col() +
ggplot2::xlab(NULL) +
ggplot2::coord_flip() +
ggplot2::theme_minimal()
你可以继续这样做。现在你已经有了时间线(剧集,季节)和剧中每一行每一个词的角色,你可以进行无限的分析。一些想法:—逐角色感悟—逐角色感悟—逐季节自恋(咳咳…Nard Dog 第 8-9 季)——角色台词——等等。
原载于 2019 年 12 月 15 日https://technistema.com。
介绍
设计和数据科学
地理空间数据探索的工作流自动化
我最近开源了一个 Python 库,名为 Theto,用来自动化我的一些工作流程。这篇文章是关于我设计这个工具的过程。如果你只是想跳到工具本身,你可以在这里看到一个演示笔记本。否则,通读帖子,我会在最后发布笔记本和其他资源的链接。
大约一年半以前,我写了一篇关于的文章,这是一个工具的前身,并解释了我在创建这个工具时试图遵循的一些原则。我想在这里展开讨论:在编写和组织代码的过程中,我需要系统地思考我试图实现什么目标,尤其是哪些事情会阻止我实现这些目标,以及我如何以避免这些陷阱的方式进行构建。换句话说,我需要修改工具的设计,而代码的修改是从这项工作中产生的。
加入设计工作使得代码更容易修复和改进,但更重要的是,它让我可以花更多的时间使用工具,而不是维护它。现在的设计比过去好,但这在很大程度上是更好的设计而不是更好的代码的结果。(要更完整地讨论应用于数据科学的设计,请阅读我在这里写的内容)。
所以我想谈谈我经常做的工作,我觉得我需要一个工具来帮助我。然后我想谈谈好的设计原则是如何帮助我组织创建这个工具的。然后,我将介绍一下机器人能做的一些事情。
我的目标:探索地图上的形状(有背景)
我在 Valassis 的大部分工作都与理解移动定位数据有关。当您在地标(建筑物、道路、行政边界、水体等)的背景下查看位置数据时,会更容易理解。将所有的上下文数据转换到一个位置和格式,以便与移动 GPS 信号等进行有意义的比较,这既困难又昂贵。在一张有许多这些背景信号的图片上绘制这些 GPS 信号,然后使用我的人脑来理解一切,这要容易得多。例如:
数据有效性
A few of the parcel shapes we don’t want
当我们能够将位置信号附加到有意义的空间时,我们的客户通常会觉得很有价值。例如,知道一个位置信号是在一个独户住宅或一个家得宝所在的建筑中通常是有用的。背景帮助我们做出更好的决定。为了获得这种背景,我们购买了从城市和县评估办公室、基于卫星图像的图像识别和其他来源获得的地块数据集。
上图左上角显示了一个细分。白线划定了住宅用地。深蓝色的线划分细分。我们的数据不包含区分这两个界限的元数据;较大的边界完全包含所有较小的边界,并且较大的边界没有被较小的形状完全填充—存在间隙。
左下方的图像显示了商店的边界。数据没问题。如果你仔细观察图像的中间,你会看到一个黑色的正方形。那是个垃圾箱。如果你从垃圾箱的左上看得更近,你会看到一个蓝色的形状。据我所知,那是垃圾箱里的包裹。我不知道它为什么会在那里,但它就是在那里。
中间的图像是河流的包裹。有意思,但对我们的生意没什么价值。我也见过这样的情况,城市里的每条路都有一个巨大的包裹。
最右边的图像是错误的。这些包裹甚至不接触他们的建筑,似乎旋转不当。
我构建了识别上述所有条件以及更多条件的过程。在某些情况下,我们会标记它们以便修复它们。在其他情况下,我们标记它们以便我们可以删除它们。在所有情况下,我们根本不知道我们需要修复或删除任何东西,直到我们把形状放在地图上,并理解我们在看什么。
Mobile location data can be wrong in a lot of different ways
形状不是我们业务中唯一有问题的数据。有时位置数据本身是错误的。
比如看左边上图。你可以看到很多橙色的点。这些小点中的大部分都聚集在图像顶部的房子上。如果你仔细看,你甚至可以看到这些点的大部分都在车道后面的房子上,这意味着那个人在上车或下车时更有可能使用他们的手机。看起来车库旁边有一点活动,大概是厨房,然后在房子的另一头有一点,大概是卧室。所有这些都有道理。
现在看图像的底部。在邻居的前院,你可以看到两个大点,实际上是一个在另一个上面。从上下文来看,这些看起来有点奇怪。点的大小反映了一周内在每个位置报告的设备数量:顶部的每个点是由单个设备报告的,而右侧的两个点是由数百个设备报告的。太奇怪了。
我称右边的图片为麦田怪圈。我不知道这是什么。每个方块大致是两个并排的足球场边上的一块土地,但我只展示这些方块,因为你无法同时看到问题的性质和范围。每个正方形本身包含一个完美的网格,每个网格点之间只有几码远。所以每个方块包含几百个网格点。蓝色方块包含一个完整的网格。沿边缘的黄色方块仅包含部分网格。换句话说,有一个巨大的网格。
每个网格点都来自假定的有机移动定位数据。这些数据形成了一个完美的网格,网格点之间的间隔只有几米,它横跨了一个直径约为 2.5 英里的完美圆形。据我所知,美国只有六家这样的公司。其中大部分发生在市中心附近——在阿拉巴马州伯明翰市中心就有一个——但上图中的这个是在俄勒冈州的一块空地上。
每个人都知道手机定位数据不能只看表面。我们需要在很多很多不同的背景下,实际上观察移动位置,以找出哪些信号我们可以相信,哪些不可以。
A couple post-analysis sanity checks
有时我们需要在分析之后而不是之前检查数据。上面的左图显示了当我们重新设计一个为物理位置分配 IP 地址的算法时发生的变化。蓝色表示重新设计导致分配更多 IP 地址的地方。红色表示分配的 IP 数量减少的地方。
右图显示了类似的分析后健全性检查。我们一直在寻找销售类似产品或服务的商店。黑色曲线的宽度显示了我们认为某些商店有多相似。这让我们可以查看商店名称,看看我们是否得到了正确的相似性分数。
算法开发
What makes sense for a county assessor doesn’t make sense for us.
我不仅仅使用可视化来计算我正在处理的数据或结果。我经常用它来迭代我正在构建的算法的不同设计选项。
上图显示了一些宗地数据。左边的图像显示了我们从县评估员那里收到的数据。白线表示不同地块之间的分界线。很明显,那些对角线并没有划分出真正怪异的公寓。查看分配给该建筑的邮寄地址,我们认为县评估员试图找出如何解释该建筑有三个公寓平面图,但有四层。对于我们来说,不知道移动信号在几楼有点问题,但如果它出现在某人的客厅,那么将它分配给一个公寓,如果它出现在他们的卧室,那么将它分配给另一个公寓,这确实是个问题。
因此,我编写了一个过程,从一个地块开始,爬行到相邻的地块,在每个阶段检查不同的度量——例如,查看爬行的总空间有多大。这里没有正确的答案——在某些情况下,很难准确说出正确的组合是什么,即使直视它。我甚至使用可视化来尝试不同的指标:
Screen shot of me trying to undo a county assessor’s good intentions
鉴于我几乎总是处理没有可获得的基本事实来验证模型的问题,我很少开发一种算法而不开发一种方法来可视化该算法的结果。这是另一个例子:
红点是一个企业的位置。我们没有为那家商店(和许多其他喜欢它的商店)留下建筑足迹。因此,我们查看了商店附近的移动设备,并计算出它们还去了附近的其他地方。我们能够利用这一点来对地块进行评分,确定出现在给定地块上的人出现在离商店质心更近的地方的概率。我们能够利用这种概率云来构建一个建筑足迹,不仅捕捉到了商店,还捕捉到了商店前门外的专用停车场。
好的设计产生好的代码
以上所有的例子实际上只是一个简单目的的不同版本:我需要在地图上以一种我可以看到上下文的方式放置形状。这就是我需要一个工具来实现的目的。一个好的设计不应该分散我对那些可能妨碍我实现目标的事情的注意力,而且应该尽量减少我在其他事情上花费的精力。我会回到那一点。
设计是一件有趣的事情。许多好的设计原则适用于你正在设计的任何东西,无论是软件、机器还是建筑:
Vitrivius 是一位罗马设计师,他写了“十本关于建筑的书”,现在通常简称为“建筑论”。在那部作品中,维特鲁威提出了优秀设计的三个品质:
- 有用
- 坚定
- 高兴
前两个是不言自明的——尤其是第一个。一个好的设计应该是有用的,因为它首先实现了一个目的。我经常看到数据科学家,尤其是初级数据科学家,设计复杂的工作流和流程来适应他们想要使用的特定方法,而没有首先确认该方法比(通常更简单的)替代方法更好地实现了分析目的。我自己做过的次数比我愿意承认的要多。
无论你是在建造一栋建筑还是一个软件,你都希望它“坚固”到不容易损坏。实际上,这种品质很难达到。在我自己的经验中,我经常发现我写代码是为了在一定条件下适应某种输入,并提供某种输出。然后输入发生变化,或者我需要不同的输出,或者基础条件发生变化,一切都崩溃了。我重新设计了可视化代码,因为我厌倦了保持相同过程的多个版本,或者每当一个旧的需求重新出现时就搜索旧版本的代码。我之前写的代码不牢。这一目标还有一段路要走,但它已经稳固得多了。
最后一个品质——愉悦——是最不直观的,但在我看来,却是最重要的。在设计建筑时,这个概念更加直观:建筑不应该只是挡雨。应该很好看。但这就提出了一个问题,一个算法或一个软件“看起来不错”意味着什么?
弗雷德里克·布鲁克斯(Frederick Brooks)最出名的可能是写了《人月神话》,并监督了 IBM 的 System/360 系列计算机的设计,这是第一个支持小写字母表示的系统。布鲁克斯已经写了很多关于设计的文章。他认为维特鲁威的快乐概念是一种“逻辑美”。如果一个设计减少了脑力劳动,那么它在逻辑上就是美丽的——它让我们很容易注意到需要我们注意的事情,也很容易忽略甚至完全意识不到那些不需要我们注意的事情。Books 将逻辑美的概念分为三个部分:
- **礼义廉耻。**布鲁克斯将此描述为“不要介绍不重要的东西”。我们制造东西是因为我们有任务要完成。任何与完成任务直接相关的事情都适合于该任务。任何不直接相关的东西——如果有必要的话——都是不合适的。一个好的设计应该让适当的任务变得容易,让不适当的任务变得不可见。
- **正交性。**布鲁克斯将此描述为“不要链接独立的东西”。我们也可以将其描述为模块化。一个好的设计不应该让设计的不同方面互相依赖,除非它们真的总是需要一起发生。如果他们可以分别快乐,他们应该被建造成彼此独立。
- 共性。布鲁克斯将此描述为“不要限制固有的东西”。一个好的设计不应该为了使用这个设计而一遍又一遍地让人们去做同样的事情。设计应该只是做那件事。
那么,让我们回到作为一名数据科学家,我真正想要完成的事情上来。我的目标:探索地图上的形状以理解背景。不是我的目标:得到形状,得到地图,把形状放在地图上。这些事情都不适合我的任务,尽管它们显然需要发生才能让我完成任务。事实上,当我想得更多的时候,我发现大量的任务是必要的,但并不恰当:
- 存储默认值
- 摄取数据
- 验证数据
- 过程数据
- 追加元数据
- 获取地块大小和边界
- 获取缩放级别
- 检索地图切片
- 项目数据
- 添加形状
- 将数据映射到形状
- 格式化形状
- 连接形状
- 批注形状
- 添加互动
- 设置交互工具
- 添加/格式化图例
- 渲染图
- 重复
一个好的设计应该尽量减少我在上面任何一项任务上花费的脑力。它们应该尽可能高效地发生,尽可能减少我的工作量。这就是得体的原则。
所以现在我们得到了正交性原理。如果我想最大限度地减少我花在上述任务上的注意力,我需要以一种最大限度减少依赖性的方式来组织它们。我需要对任务进行足够的划分,这样,如果一个东西出现故障或未能满足需求,就不会影响到工具的其他部分。有很多方法可以分解这些任务。这是我选择的:
- 设置默认值
- 添加来源
- 添加互动
- 创建绘图
- 添加层
- 渲染图
这些是我与设计的互动点:我不需要对所有那些必要但不恰当的任务做出决定,我只需要做出以上六个决定。这样更省力。
我的最后一个目标是将这六项任务尽可能分开。这就是展示比讲述容易得多的地方。
建筑师可以做的几件事
上面文章中几乎所有的图片都是用这个工具创建的,但是在这里我将介绍所有的主要功能。该工具构建在散景库之上,该库具有一定的内置交互性,例如平移和缩放图形的能力。的其他部分提供了更高级的交互性。Medium 没有提供任何直接嵌入 Javascript 的方法,所以如果你想看到交互式部分,可以向下滚动到文章的底部,点击笔记本的链接。
输入格式
计算器可以自动处理以下类型的输入:
Shapes on maps!
散景能够渲染字形(其中形状的边界映射到实际的地图坐标,因此如果您缩放图像,形状也会放大)和标记(映射到地图上单个点并且无论您如何缩放都保持不变的点或其他形状)。这个工具将接受上面的任何输入,并将它们格式化为一个字形或一个标记——随你怎么想。
这个工具还可以自动追加元数据。您可以将所有想要的数据作为 Pandas dataframe 加载,并指定包含形状的列,或者您可以将形状作为值列表加载,然后通过将元数据作为关键字参数包含在add_source
方法中来追加元数据。您可以加载任意数量的源,并以多种方式渲染单个源。
视觉造型
为形状边框、形状表面或同时为两者指定颜色提供了多种方法:
如果您将单一颜色名称或十六进制颜色代码传递给add_layer
方法,所有形状都将是该颜色。或者传递一个值列表来分别分配给每个形状。如果您在数据源中传递一个列的名称,并且该列包含字符串值,则将自动从分类调色板中分配颜色。(您可以在实例化调色板时指定哪个调色板,但它也有一个缺省值)。如果列包含数值,则将创建一个颜色渐变(包括具有正值和负值的列的中点颜色渐变)。所有的颜色映射都在幕后进行。
还提供了几种地图类型:
只需使用适当的关键字来获得您想要的地图类型。另外,如果在实例化一个 Theto 实例时输入一个 Google API 键,那么可以使用任何 Google Maps 地图类型(“卫星”、“路线图”、“地形”或“混合”)。只是要小心:Bokeh 将 API 键存储在用于渲染图的 Javascript 对象中,因此任何查看您渲染图的页面的源代码的人都可以看到您的 API 键。
这个工具还有一个add_path
方法,可以让你在形状之间添加线条(曲线或直线)。它可以处理一对一的关系来显示从一个位置到另一个位置的旅行,或者处理多对多的关系来显示其他类型的连接。
交互性
正如我之前提到的,由于是建立在散景的基础上的,所以它可以获得一些开箱即用的交互性。除了平移和缩放,你还可以在add_layer
方法中的legend
关键字参数中加入一个标签,这将创建一个图例,点击标签将打开和关闭相关层。
此外,还有一种add_widget
方法,允许更复杂的交互来动态过滤地图上显示的形状:
如何自己使用计算器
如果你只是想开始使用它:
pip install theto
您可以在这里看到所有功能的演示:
Geohashes 是划分地球表面的长度为 1 到 12 的字符串。该工具将转换这些…
nbviewer.jupyter.org](https://nbviewer.jupyter.org/github/Valassis-Digital-Media/theto/blob/master/theto_demo_notebook.ipynb)
您可以在这里查看代码、文件问题和创建拉取请求:
任何可视化都需要大量琐碎的决策,这些决策加起来会对…产生重大影响
github.com](https://github.com/Valassis-Digital-Media/theto)
介绍 tsviz,R Studio 中的交互式时间序列可视化
我们为什么以及如何开发 R Studio 插件
tsviz logo
上下文:R 数据可视化工具
我们都知道。r 非常适合数据可视化。
Hadley Wickham 的 ggplot2 提供了一个简单而优雅的语法来创建非常有效的图表。此外,万一 ggplot2 不支持一些奇特的图表,R 提供了许多有效的替代方法,如点阵。
在这种场景下,2016 年初,发布了新的包。随着 JavaScript 库的开源发布,R 的 Plotly 在 CRAN 上可用。Plotly 允许创建交互式图表,用户可以缩放,平移,选择数据,并通过悬停在数据点上查看附加信息。
交互性可能只是一个花哨的功能。在学术著作中,数据是已知的,真正重要的是为出版物制作清晰和信息丰富的图表。
但是…
对于从业者来说,交互性是一件大事。它有助于接近数据并获得早期洞察力,从而加快数据探索的整个过程。
毫不奇怪,Plotly 立即获得了成功,随着新功能的增加,它越来越受欢迎,比如与 ggplot2 的集成。
然而,即使是 Plotly 和 ggplot2 也是要付出代价的。
Plotly R package daily downloads. Data from rpackages.io.
动机:寻求早期洞察力
Plotly 和 ggplot2 未能提供一个通用的语法:将纯 plotly 中的图表与用 ggplot2 创建的 plotlified 图形混合在一起是很棘手的。即使有了库的帮助,创建有效的可视化仍然需要时间。
大多数数据科学家喜欢创建图表。图表是我们交流的方式,是分享我们从数据中获得的信息的最有效的语言。
但是,创建图表来共享结果不同于创建图表来浏览和调查数据。
在第一种情况下,我们很乐意在一个数字上花很多时间,但在第二种情况下,我们就不乐意了。我们想尽快获得知识,这样我们可以做出更好的决定,避免危险的误解。
幸运的是,R and R 工作室为这种需求提供了答案。2016 年初,R Studio 宣布支持插件。作为 IDE 的有效扩展,外接程序可能有助于与开发相关的任务,但也为数据分析提供支持。例如,一些加载项简化了数据子集设置,而其他加载项则帮助选择图表的颜色。
因此,为什么不创建一个插件来简化交互式图表的使用呢?
在过去的几个月里,在 xtream 中,我们参与了几个涉及时间序列分析的项目。我们多次重复同样的过程:
- 绘制时间序列
- 检查目标系列和特征之间的散点图
- 建立和分析自相关、偏自相关和周期图
当然,我们构建并使用了函数,但是创建一个脚本或一个 R Markdown 文档来一直使用它们是很乏味的。
因此,我们决定将最有用的功能封装在一个插件中。
创造:站在巨人的肩膀上
由于有很多有用的资源,开发 R Studio 插件的过程非常快。以下是清单:
- 使用这个包:一个易于使用的工具,在 R 包的基础上构建框架并添加元素,比如许可证、测试、CI 配置。
- styler 包:实现 tidyverse 风格导轨的棉绒。它可以通过其插件运行。
- hexSticker package :为包创建六边形标志的工具。
- Hadley Wickham 的 R 包:创建 R 包的严谨而易懂的指南。
- R Studio 关于插件的教程:对于从未创建过插件的开发者来说是一个很棒的资源。
- GitLab 和 GitLab CI:起初,插件托管在 xtream 的私有 GitLab 存储库中。本教程帮助我们配置持续集成管道。
- GitHub 和 Travis CI:社区维护的 Travis 的 R 映像提供了与 GitHub 的无缝 CI 集成。
结果:tsviz
tsviz 是一个 R 包,其中包含 tsviz 插件和一个样本数据集。
您可以通过运行以下命令从曲柄安装 tsviz:
或者可以从 GitHub 下载开发版。确保安装并运行 devtools 包:
安装后,您可以尝试加载项:
您应该能够做这样的事情:
tsviz usage example
tsviz 也可以随时从 R Studio 中的 add-ins 菜单运行:不需要用library()
加载包。
当然,你可以在自己的数据上尝试 tsviz。
启动时,加载项会自动在全球环境中查找合适的数据框。如果满足以下条件,可以使用 tsviz 分析数据帧:
- 它至少有一个类型为
Date
的列 - 它至少有一个
numeric
类型的列
参考
tsviz 在 GitHub 上:https://github.com/xtreamsrl/tsviz。它仍处于早期开发阶段:欢迎每一个反馈或错误报告!
我的读者,感谢你来到这里!
如果你喜欢这篇文章,你可能会感兴趣:
如果你对 me 或xtream有什么好奇的话,上领英看看吧!
Xverse 介绍!—用于要素选择和变换的 python 包
节省数据科学家 80%的时间
Credits: Pixabay
Xverse 是 X Uni verse 的缩写,是一个用于机器学习的 python 包,用于协助数据科学家进行特征转换和特征选择。在我们谈论这个包的细节之前,让我们理解为什么我们需要一个。
背景
Credits: Geeksta
我看到了这张图片,我觉得没有更好的方式来解释这个项目。虽然听起来很有趣,但它发生在数据科学生命周期的大部分时间里。数据科学家 80%的时间花在处理特性(X)上,因此得名 XuniVerse 又名**“X verse”。**
另外,整个项目是基于我 2018 年在 Medium 上发表的作品。根据我从读者那里得到的反馈,我想改进代码的功能。与其把它作为一个更新的功能发布,我认为把它作为一个 python 包发布会更好。嗯,《xverse》就是这么诞生的。
此包的早期作品
下面显示的文章现在是这个包的一部分。
证据权重(WOE)和信息价值(IV)是简单的,但强大的技术来执行可变…
medium.com](https://medium.com/@sundarstyles89/weight-of-evidence-and-information-value-using-python-6f05072e83eb)
“证据权重(WOE)和信息价值(IV)是执行变量转换和选择的简单而强大的技术。这些概念与逻辑回归建模技术有着巨大的联系。它被广泛用于信用评分,以衡量好客户与坏客户的区分。”
变量选择是预测建模过程中的关键步骤之一。这是一门艺术。简单来说…
medium.com](https://medium.com/@sundarstyles89/variable-selection-using-python-vote-based-approach-faa42da960f0)
“这个想法是应用各种技术来选择变量。当一个算法选择一个变量时,我们给这个变量投票。最后,我们计算每个变量的总投票数,然后根据投票选出最佳变量。这样,我们就能在变量选择过程中以最少的努力挑选出最好的变量。”
功能
xverse (XuniVerse)是用于特征工程和特征选择的转换器的集合
github.com](https://github.com/Sundar0989/XuniVerse)
下面显示的所有示例使用的数据集都在“data”文件夹中。此外,您可以参考此链接中的 Jupyter 笔记本代码“Xverse.ipynb”。
1.单调宁滨
单调宁滨是记分卡开发中广泛使用的数据准备技术。它试图通过创建与目标具有单调关系的箱来将数值变量转换为分类变量。下面给出的例子将演示它是如何工作的。
Balance vs Target (Monotonic Relationship)
上面显示的特征“余额”的范围从$3,313.001 到$71,188。我们都同意这是一个非常广泛的范围。如果我们必须基于领域知识绑定这个变量,那么我们就不必担心单调关系。然而,当没有先验知识存在时,则很难确定容器类别。这是一个理想的情况,单调宁滨可以帮助。
它从 20 个箱开始(默认值,可以随时更改),然后减少箱数,直到发现 X 变量和目标 y 之间的单调关系(增加或减少)。如果它没有建立单调关系,则使用 force_bins 选项强制在 X 变量上创建箱数。一直以来,它使用 斯皮尔曼相关 来验证 X 和 y 变量之间是否存在单调关系。
单调宁滨的优点:
- 处理异常值
- 在特征和目标变量之间建立单调关系
单调宁滨的缺点:
- 在可变宁滨期间,我们会丢失信息
- 没有处理缺失值的正确方法
如何用“Xverse”演奏单调的宁滨?
from xverse.transformer import MonotonicBinning
clf = MonotonicBinning()
clf.fit(X, y)
print(clf.bins)
output_bins = clf.bins *#will be used later in this exercise*
这里 X 表示特征数据集,它是一个熊猫数据框架,y 是目标列的 numpy 数组。我们还可以使用预计算的单调条柱应用于新数据集,如下所示。
clf = MonotonicBinning(custom_binning=output_bins) *#output_bins was created earlier*
out_X = clf.transform(X)
out_X.head()
2.证据权重和信息价值
WOE 包在 transformer 函数中可用。WOE 转换的优点是
- 处理缺失值
- 处理异常值
- 该变换基于分布的对数值。这与逻辑回归输出函数一致
- 不需要虚拟变量
- 通过使用适当的宁滨技术,可以在自变量和因变量之间建立单调关系(增加或减少)
- IV 值可用于快速选择变量。
计算 WOE 和 IV 的公式如下。
或者简单地说,
如何使用“Xverse”执行 WOE?
from xverse.transformer import WOEclf = WOE()
clf.fit(X, y)**clf.woe_df # weight of evidence transformation dataset. This dataset will be used in making bivariate charts as well.** clf.iv_df #information value dataset
要选择功能,请使用下面的规则
+-------------------+-----------------------------+
| Information Value | Variable Predictiveness |
+-------------------+-----------------------------+
| Less than 0.02 | Not useful for prediction |
+-------------------+-----------------------------+
| 0.02 to 0.1 | Weak predictive Power |
+-------------------+-----------------------------+
| 0.1 to 0.3 | Medium predictive Power |
+-------------------+-----------------------------+
| 0.3 to 0.5 | Strong predictive Power |
+-------------------+-----------------------------+
| >0.5 | Suspicious Predictive Power |
+-------------------+-----------------------------+
要基于之前计算的 WOE bins 转换变量 X,请使用下面的代码。
clf.transform(X) #apply WOE transformation on the dataset
如何在未来数据集上应用 WOE 转换?
output_woe_bins = clf.woe_bins #future transformation
output_mono_bins = clf.mono_custom_binning #future transformationclf = WOE(woe_bins=output_woe_bins, mono_custom_binning=output_mono_bins) #output_bins was created earlierout_X = clf.transform(X)
WOE 包中可探索的其他功能:
*treat_missing: {‘separate’, ‘mode’, ‘least_frequent’} (default=’separate’)**This parameter setting is used to handle missing values in the dataset.
‘separate’ — Missing values are treated as a own group (category)
‘mode’ — Missing values are combined with the highest frequent item in the dataset
‘least_frequent’ — Missing values are combined with the least frequent item in the dataset*
3.二元分布的条形图
二元分布帮助我们探索 X 和 y 变量之间的关系。这个选项在“xverse”中也是可用的。
如何使用“Xverse”制作图表?
为了制作二元图表,我们需要从上面显示的 woe 选项生成的**“WOE _ df”**数据集。
woe_df = clf.woe_dffrom xverse.graph import BarCharts
clf = BarCharts(bar_type='v')
clf.plot(woe_df)
要在条形图中探索的其他功能:
*plot_metric: 'count' or 'mean' (default='mean')
Metric to be used while plotting the bivariate chart.
'count' - Event counts in the particular bin
'mean' - Mean event rate in the particular bin**bar_type: 'horizontal' or 'vertical' (default='vertical')
Type of bar chart.**fig_size: figure size for each of the individual plots (default=(8,6))**bar_color: CSS color style picker. Use it with the hashtag in the front. (default='#058caa')
Bar color
num_color: CSS color style picker. Use it with the hashtag in the front (default='#ed8549')
Numbers color. It represents the numbers written on top of the bar.*
4.变量选择的投票选择器
变量选择是预测建模过程中的关键过程之一。这是一门艺术。简单地说,变量选择就像挑选一支足球队赢得世界杯。你需要在每个位置都有最好的球员,你不希望两个或多个球员踢同一个位置。
在 python 中,我们有不同的技术来选择变量。其中一些包括递归特征消除、基于树的选择和基于 L1 的特征选择。
这里的想法是应用各种技术来选择变量。当一个算法选择一个变量时,我们给这个变量投票。最后,我们计算每个变量的总票数,然后根据投票选出最好的变量。这样,我们就可以在变量选择过程中以最小的努力挑选出最好的变量。
from xverse.ensemble import VotingSelectorclf = VotingSelector()
clf.fit(X, y)
现在,让我们用下面的代码来看看特性的重要性。
clf.feature_importances_
clf.feature_votes_
clf.transform(X).head()
投票选择器中可探索的其他功能:
*selection_techniques: 'all', 'quick' or list(default='all')
List of selection techniques to be applied on the data.
Available techniques - Weight of evidence ('WOE'), Random Forest ('RF'), Recursive Feature Elimination ('RFE'), Extra Trees Classifier ('ETC'), Chi Square ('CS'), L1 feature selection ('L_ONE').
'all' - Apply all selection techniques ['WOE', 'RF', 'RFE', 'ETC', 'CS', 'L_ONE']
'quick' - ['WOE','RF','ETC']
list - user provided list of feature selection techniques from available techniques
no_of_featues: 'auto', 'sqrt' or int(default='auto')
Number of features to be selected by each selection technique.
'auto' - len(features)/2
'sqrt' - sqrt(len(features)) rounded to the lowest number
int - user provided number in integer format
handle_category= 'woe' or 'le' (default='woe')
Handle category values transformation using Label encoder or Weight of Evidence option. Takes care of missing values too. It treats missing values as separate level.
'woe' - use weight of evidence transformation
'le' - use label encoder transformation
numerical_missing_values= 'median', 'mean' or 0 (default='median')
Handle numerical variable missing values.
'median' - use median of the column
'mean' - use mean of the column
0 - use 0 to impute the missing values
minimum_votes = int (default=0)
Minimum number of votes needed to select a variable after feature selection. Only used in the transform process. Default value is set to 0 to select all variables.*
5.管道特征
最后,关于“Xverse”的一件重要事情是管道功能。我们可以将所有步骤作为流水线的一部分,让我们的生活变得更加轻松。
下面的代码展示了管道特性。
from sklearn.pipeline import Pipelineclf = Pipeline(steps=[('split_x_y', SplitXY(['target'])),('feature_votes', VotingSelector())])
clf.fit(df, df['target'])
最后,为了在新的数据集上进行转换,
clf.transform(df)
为 Xverse 做贡献
XuniVerse 正在积极开发中,如果你想参与其中,我们欢迎你的加入。请在这篇文章中留下回应,我们可以谈论下一步。
代码在这里的一个笔记本中给出,供您在自己的数据集上进行实验。
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/Sundar0989/XuniVerse/blob/master/Xverse.ipynb)
玩得开心!
分层聚类简介
揭示 R 州级人口统计数据的结构
聚类试图通过创建具有相似特征的数据分组来发现数据中的结构。最著名的聚类算法可能是 K-means,但是有许多方法可以对观察值进行聚类。分层聚类是一类可生成 1 到 n 个聚类的聚类算法,其中 n 是数据集中的观察值数量。当您从 1 个分类(包含所有数据)到 n 个分类(每个观察值都是自己的分类)时,分类会变得越来越相似(几乎总是如此)。有两种类型的层次聚类:分裂型(自上而下)和聚集型(自下而上)。
分裂的
分裂式层次聚类从包含整个数据集的 1 个聚类开始工作。具有最高平均不相似性的观察值(离聚类最远的某个度量)被重新分配给它自己的聚类。旧聚类中更靠近新聚类的任何观测值都被分配给新聚类。对最大的聚类重复这个过程,直到每个观察值都是它自己的聚类。
结块的
凝聚聚类从每个观察值作为自己的聚类开始。两个最接近的集群被结合成一个集群。下一个最接近的聚类被分组在一起,并且该过程继续,直到只有一个聚类包含整个数据集。
亲近是什么意思?
在上一节中,我忽略了定义“接近”是什么意思。有各种可能的度量标准,但我将列出 4 个最受欢迎的:单连接、完全连接、平均连接和质心连接。
单连杆机构
单链(最近邻)是两个聚类中一对观测值之间的最短距离。它有时可以生成这样的聚类,其中不同聚类中的观测值比它们自己的聚类中的观测值更接近。这些集群可能看起来很分散。
完全连锁
完全关联(最远邻居)是两个聚类中最远的一对观察值之间的距离。这种方法通常会产生比单一链接更紧密的集群,但是这些紧密的集群最终可能会非常紧密。与平均链接一起,它是更受欢迎的距离度量之一。
平均连锁
平均关联是指将每个聚类中每对观察值之间的距离相加,然后除以对的数量,以获得平均聚类间距离。平均连接和完全连接是层次聚类中两种最流行的距离度量。
质心连杆
质心连接是两个簇的质心之间的距离。当质心随着新的观测值移动时,较小的星团可能更类似于新的较大的星团,而不是它们各自的星团,这导致了树状图中的反转。这个问题在其他链接方法中不会出现,因为被合并的聚类总是更类似于它们自己,而不是新的更大的聚类。
在 R 州级人口统计数据上使用层次聚类
在我们对美国各州进行分类时,地区的概念非常重要。区域是由地理定义的州的集群,但是地理导致了州之间额外的经济、人口和文化相似性。例如,佛罗里达州南部非常靠近古巴,这使得它成为古巴难民通过海路前往美国的主要目的地。因此,南佛罗里达是古巴裔美国人最集中的地方。
为了研究今天(实际上是在 2017 年)各州之间的相似程度,我下载了包含 2017 年美国社区调查信息的数据,并使用分层聚类对它们进行分组。数据集有许多变量,所以我使用了“特征向量分解,这是一个来自量子力学的概念,以梳理“人口统计数据”中重叠的“笔记”(我知道我迟到了,但我必须告诉大家,我也上过线性代数课)。生成的树状图(带有 R 代码)如下。
完全链接的凝聚层次聚类
HC . complete = hclust(dist(PC . state . full $ x[,1:5]),method='complete ')
plot(hc.complete,labels = X_state$State,main= ‘使用 2017 年 ACS 数据的区域聚类的树状图(聚合)’,xlab= ’ ',sub= ’ ',cex=0.7)
Dendrogram created using Agglomerative Hierarchical Clustering with Complete Linkage on 2017 ACS data’s first 5 principal components
分裂层次聚类
库(集群)
div.hc = diana(pc.state.full x [ , 1 : 5 ] , d i s s = i n h e r i t s ( p c . s t a t e . f u l l x[,1:5],diss = inherits(pc.state.full x[,1:5],diss=inherits(pc.state.fullx[,1:5]," dist "),metric = "euclidean ")
plot(div.hc,labels = X_state$State,,main= ‘使用 2017 年 ACS 数据的区域聚类的树状图(divide)’,xlab= ’ ')
Dendrogram created using Divisive Hierarchical Clustering on 2017 ACS data’s first 5 principal components
聚集和分裂方法产生的集群之间存在一些差异。聚集法将乔治亚州和北卡罗来纳州与伊利诺伊州、特拉华州、宾夕法尼亚州和罗德岛州归为一组,而分裂法将它们与南俄亥俄州、密歇根州、密苏里州和印第安纳州归为一组。大体上,它们是相同的,这是我们所期望的。
从这些树状图中有一些发现:
弗吉尼亚离大西洋中部比离南部更近
-阿拉斯加最靠近上平原州(农村、白人、土著人口相对较多)
-俄亥俄州、密歇根州、密苏里州和印第安纳州比其他中西部州更靠近南方
-夏威夷州和 DC 与其他州非常不同
我希望您学到了一些新东西,并看到了在 R 中实现这些技术是多么容易。 hclust() 在 base R 中可用,而 diana() 在集群库中。
我的数据和代码可以在这里找到。