塔夫拉:一个极简的数据框架
一个小的纯 Python 包,对类型的支持一流,对可用性和性能的依赖性最小。
大卫·s·富尔福德和德里克·w·特克。2020 年 6 月 17 日
图片来源: Pixabay
介绍
很明显,数据科学需要数据。当我们处理数据时,我们必须首先从数据源加载数据,并存入内存。我们的数据可能有不同的类型:文本、整数、小数、日期、时间戳等等。数据框架是我们在执行数据科学时存储这种异构数据的实际机制。
tafra
作为一个思想实验开始了它的生命:我们怎样才能把阿达 塔夫拉 我的想法(用像pandas
这样的库或者像R
这样的语言表达)减少到它有用的本质,同时切掉脚?
原始概念验证在group_by()
处停止。从那以后,我们扩展了这个想法,构建了一个完整的库,产生了一个实用的 T4,我们希望你会发现它是一个有用的轻量级替代品,可以替代 T5 的某些用途。
一个tafra
或多或少是一组命名的列或尺寸。每一个都是长度一致的类型化numpy.ndarray
,用行表示每一列的值。该库提供了用于操作行和列的轻量级语法、对管理数据类型的支持、对行和子帧的迭代器、pandas
式的支持和从 pandas 数据帧的转换,以及 SQL 风格的GROUP BY
和JOIN
操作。
一个简短的例子
from tafra import Tafrat = Tafra({
'x': np.array([1, 2, 3, 4]),
'y': np.array(['one', 'two', 'one', 'two'], dtype='object'),
})t.pformat()
> Tafra(data = {
> 'x': array([1, 2, 3, 4]),
> 'y': array(['one', 'two', 'one', 'two'])},
> dtypes = {
> 'x': 'int', 'y': 'object'},
> rows = 4)
如果我们在一个 Jupyter 笔记本中,我们得到一个第一行带有dtypes
的 HTML 表格:
tafra 的 HTML 表格渲染
编写高性能代码(比如通过使用[numba](https://numba.pydata.org/)
)需要严格执行您的数据类型。奇怪的是,Windows 将int32
作为默认long
,而 Linux 和 MacOS 则是默认int64
。需要改吗?Tafra.update_dtypes()
可以接受numpy.dtype()
接受的任何输入。
# these are all equivalent
t.update_dtypes({'x': 'int64', 'y': 'str'})
t.update_dtypes({'x': np.int64, 'y': str})
t.update_dtypes({'x': np.dtype('int64'), 'y': '<U3'})
铸造类型是灵活和直接的
除了从其他数据结构中读取数据(例如 CSV 、 SQL 游标,或者行记录,以及许多其他数据结构),能够将tafra
转换为其他数据结构也很有用:
print('List:', '\n', t.to_list())
> List:
> [array([1, 2, 3, 4], dtype=int64),
> array(['one', 'two', 'one', 'two'], dtype='<U3')]print('Records:', '\n', tuple(t.to_records()))
> Records:
> ((1, 'one'), (2, 'two'), (3, 'one'), (4, 'two'))print('NamedTuple:', '\n', t.to_tuple())
> NamedTuple:
> Tafra(x=array([1, 2, 3, 4], dtype=int64), y=array(['one', 'two', 'one', 'two'], dtype='<U3'))print('NamedTuple:', '\n', t.to_tuple(inner=True))
> NamedTuple:
> Tafra(x=(1, 2, 3, 4), y=('one', 'two', 'one', 'two'))
要将聚合函数映射到列:
t.group_by(
['y'], {'x': sum}
)
group_by()运算
并将函数映射到行:
Tafra(t.row_map(lambda tf: (
tf['x'],
np.linspace(0, tf['x'].item(), 5)
)))
row_map 示例
iterate_by
方法提供了很大的灵活性。Iterable
是唯一分组的Tuple
,匹配唯一分组的行的索引,以及这些行的Tafra
。例如:我们还没有构建 pivot 方法,但是执行您自己的方法非常简单:
pivot = []
not_null = np.full(len(t), False)
for y, idx, tf in t.iterate_by(['y']):
not_null |= idx
pivot.append([y, np.full(len(t), None)])
pivot[-1][1][idx] = t['x'][idx]Tafra(pivot)[not_null]
有枢轴的塔夫绸
有一些适合熊猫的代码,或者只是一种你喜欢的做事方式?tafra
灵活:
df = pd.DataFrame(np.c_[
np.array([1, 2, 3, 4]),
np.array(['one', 'two', 'one', 'two'])
], columns=['x', 'y'])t = Tafra.from_dataframe(df)
回去也一样简单:
df = pd.DataFrame(t.data)
或
df = t.to_pandas()
请注意,大多数函数的默认设置是将数据视为不可变的。存在许多函数的就地版本,这样做是为了明确每个函数的返回类型。也就是说,一个函数最多返回一个类型或者一个None
,而不是调用代码必须检查的另外两个类型的一个Union
。
不同返回类型的另一个例子在Tafra.read_sql
和Tafra_read_sql_chunks
中。前者将在调用时在一个Tafra
中返回所有记录,而后者将根据需要返回一个Iterator[Tafra]
来消费。
计时
在这种情况下,轻量级也意味着高性能。除了添加到库中的任何附加特性,tafra
应该为组织数据结构进行数值处理提供必要的基础。最重要的方面之一是快速访问数据本身。通过最小化访问底层numpy.ndarray
,tafra
提供了数量级的性能提升。
# Read Operations%timemit x = t['x']
> 219 ns ± 71.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)%timemit x = df['x']
> 1.55 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)# Assignment Operations%timeit tf['x'] = x
> 7.39 µs ± 950 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)%timeit df['x'] = x
> 47.8 µs ± 3.53 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
对于那些需要更快性能的人来说,可以通过直接读写_data
属性来进行绕过数据验证检查的“不安全”操作。这些分别是熊猫的 10 倍和 100 倍。
%timemit x = t._data['x']
> 55.3 ns ± 5.64 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)%timeit tf._data['x'] = x
> 65 ns ± 5.55 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
聚合函数
dataframe 式结构的主要用途之一是能够模拟 SQL 风格的GROUP BY
和JOIN
操作。tafra
在这些方面也很出色,即使是基本功能的性能也提高了10 倍。此外,我们提供了将任何函数映射到任何列的能力。
# Group By%timeit tf.group_by(['y', 'z'], {'x': sum})
> 138 µs ± 4.03 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)%timeit df.groupby(['y','z']).agg({'x': 'sum'}).reset_index()
> 2.5 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) # Transform, e.g. a GROUP BY followed by a LEFT JOIN back to the original table%timeit tf.transform(['y', 'z'], {'sum_x': (sum, 'x')})
> 161 µs ± 2.31 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)%%timeit
tdf = df.copy()
tdf['x'] = df.groupby(['y', 'z'])[['x']].transform(sum)
> 2.81 ms ± 143 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
摘要
对于这些基本操作,tafra
至少快了一个数量级。而“不安全”赋值(直接赋值给_data
属性)是 3 个数量级如果你想自己提供dtypes
,或者在一组操作后调用[Tafra._coalesce_dtypes()](https://tafra.readthedocs.io/en/latest/api.html#tafra.base.Tafra._coalesce_dtypes)
。
操作时间的比较
你想知道更多吗?
这只是对tafra
的介绍。我们相信它非常适合许多工作流,这些工作流需要一个以类型为中心的数据帧类型的结构,而不需要所有的花里胡哨…或者如果您只是想要一个替代方案,不会妨碍您将numpy.ndarray
传递到您想要它们去的地方。
用 BioBERT 标记基因和蛋白质
BioBERT 背后的直觉以及在 Colab 中的实现
在 Unsplash 上由 Ani Kolleshi 拍照
一、简介
临床领域的文本挖掘变得越来越重要,目前有大量的生物医学文档包含有价值的信息,等待通过 NLP 技术进行解码和优化。随着自然语言处理的加速发展,预先训练的语言模型现在可以携带数百万(甚至数十亿)的参数,并可以利用大量的文本知识来完成下游任务,如问答,自然语言推理,以及在我们将要完成的情况下,通过命名实体识别进行生物医学文本标记。所有代码都可以在我的 GitHub 上找到。
二。背景
作为自然语言处理领域的最新突破,谷歌的研究人员开发了一种被称为 BERT 的语言模型。al,2018),该模型通过在其架构的所有层中联合调节文本的双向上下文来学习深度表示。这些表示对于严重依赖上下文的顺序数据(如文本)很有价值,迁移学习在该领域的出现有助于将编码的知识用于加强个人跨领域的较小任务。在迁移学习中,我们将这一步称为“微调”,这意味着预先训练的模型现在正在针对我们脑海中的特定任务进行微调。最初的英语语言模型在预训练中使用了两个语料库:维基百科和图书语料库。对于像 BERT 这样的变形金刚背后的更深层次的直觉,我会建议一系列关于它们的架构和微调任务的博客。
伯特建筑(德夫林等人,2018 年)
BioBERT (Lee et al .,2019)是来自高丽大学和 Clova AI 的前述模型的变体。研究人员用 PubMed 和 PMC 增加了原始 BERT 的语料库。PubMed 是生物医学引文和摘要的数据库,而 PMC 是全文期刊文章的电子档案。他们的贡献是一种生物医学语言表示模型,可以管理诸如关系提取和药物发现等任务。通过拥有包含通用和生物医学领域语料库的预训练模型,开发人员和从业人员现在可以封装生物医学术语,这些术语对于通用语言模型来说难以理解。
BioBERT 建筑(Lee 等人,2019 年)
在 BERT 和 BioBERT 中,文本被分解为单词片段标记器,该标记器将单词拆分为频繁出现的子单词,这样免疫球蛋白将被标记为 *I ##mm ##uno ##g ##lo ##bul ##in 的组成片段。*这些词块可以通过字符组合利用字符的灵活性以及一般的词义。使用 BioBERT 实现最先进结果的微调任务包括命名实体识别、关系提取和问题回答。在这里,我们将看看第一项任务,以及到底完成了什么。
三。工作
命名实体识别(NER)是对大量专有名词(或给定的目标短语)的识别过程,我们将这些专有名词建立为要标记的实体类型。用于评估 NER 的数据集以 BIO(开始、内部、外部)模式构建,这是该任务中最常见的句子标记格式。此外,“S-Protein”中的“S”可用于推断单个标记。这样,我们就可以注意到根据训练数据预测的位置前缀和实体类型。
基于 BioNLP13 语料库的命名实体识别
本例中使用的数据集是由 BioNLP09 语料库、 BioNLP11 语料库和 BioNLP13 语料库组合而成。虽然我们关注基因和蛋白质,但还有其他实体类型,如疾病、化学物质和药物。这些实验中包含了 74 个标签,但为了简洁起见,下面是 BIO 模式中的 BioNLP13 语料库标签:
'B-Anatomical_system',
'B-Cancer',
'B-Cell',
'B-Cellular_component',
'B-Developing_anatomical_structure',
'B-Gene_or_gene_product',
'B-Immaterial_anatomical_entity',
'B-Multi-tissue_structure',
'B-Organ',
'B-Organism',
'B-Organism_subdivision',
'B-Organism_substance',
'B-Pathological_formation',
'B-Simple_chemical',
'B-Tissue',
'I-Amino_acid',
'I-Anatomical_system',
'I-Cancer',
'I-Cell',
'I-Cellular_component',
'I-Developing_anatomical_structure',
'I-Gene_or_gene_product',
'I-Immaterial_anatomical_entity',
'I-Multi-tissue_structure',
'I-Organ',
'I-Organism',
'I-Organism_subdivision',
'I-Organism_substance',
'I-Pathological_formation',
'I-Simple_chemical',
'I-Tissue',
'O'
四。履行
首先,我们要从原来的 GitHub 导入 BioBERT,并将文件转移到我们的 Colab 笔记本中。在这里,我们正在下载主要的 BioBERT 文件,提取 BioBERT 权重,并将其转换为适用于 PyTorch,以便与 HuggingFace API 一起工作。为了简单起见,我们移动了配置文件,现在可以开始了!
你需要 HuggingFace 的变形金刚库。关于安装和导入的完整列表,请查阅我的笔记本。我们将文本的最大长度和批量大小设置为约束条件,我们将在后面使用这些约束条件。我们还将在 Colab 中创建一个利用 GPU 进行计算的设备。BertTokenizer 类将从我们之前设置的 BioBERT 文件中获取 vocab.txt。
SentenceFetch 类将接收我们的数据,读取生物模式文本进入的 TSV 文件,并将句子和标签组织成可用的数据结构。然后我们就有了检索句子和标签的方法。
我们搜索根目录的所有子目录。在 Colab 中,我建议从 Google Drive 或本地硬盘上传数据。我们使用 SentenceFetch 类并创建一个在实验中使用的句子和标签列表。
我们创建一个助手函数来标记文本,而不会丢失每个标记的标签。我们的模型需要完整的标签。
现在,我们可以通过 Keras 中的“pad_sequences”将输入数据规范化。这用于保持固定长度与比我们的最大长度短的序列一致。
现在我们可以完成建模的数据准备工作了。当将序列批处理在一起时,使用注意屏蔽来指示应该观察哪些记号。我们在训练和验证数据之间分割输入和屏蔽。然后,我们将数据转换为张量,以便与 PyTorch 一起正常工作。之后,我们通过 PyTorch 中的数据工具传递这些张量,最终为我们的模型准备好数据。
在建模阶段,我们使用 BertConfig 类来使用模型的配置文件。我们还使用预先训练的权重来帮助建立我们的“状态字典”。“state_dict”是一个字典,它将每一层映射到它的参数张量,这大大增加了 PyTorch 中模型和优化器的模块性。
我们为 NER 模型创建了一个简单的 BioBERT 类。我们的属性是我们网络中的层以及一个向前传递的方法。
创建了主要模型后,我们设置了优化和学习率调度程序。我们还在这里设置了其他超参数。
创建了管理纪元训练的功能。在这里,我们通知各层我们正处于训练模式,因此批处理 norm 和 dropout 层在训练模式下工作,而不是在 PyTorch 中要求的 eval 模式下工作。计算梯度并更新模型权重。
创建第二个函数来评估我们的模型。正如人们所猜测的,我们知道需要通知层我们处于 eval 模式。我们还停用自动签名引擎,以减少内存使用和加快计算速度。将来,将这两个函数合并为 BioBERT 模型类中的方法会更简洁。
这里,我们将循环遍历我们的纪元,使用我们的两个函数,并打印训练和验证损失/准确性的结果。
我们的结果显示,训练准确率高达 96%,验证准确率高达 95%。考虑到它所花费的时间(尽管在这里模型在可用的 GPU 上运行得非常快!),没有理由增加 epochs。
======== Epoch 1/3 ========
Train Loss: 0.20869970354739556 Train Accuracy: 0.9479462699822381
Val Loss: 0.1037805580667087 Val Accuracy: 0.9576587301587302
======== Epoch 2/3 ========
Train Loss: 0.09325889256480109 Train Accuracy: 0.9650584665482536 Val Loss: 0.09049581730413059 Val Accuracy: 0.9589087301587302
======== Epoch 3/3 ========
Train Loss: 0.0828356556263529 Train Accuracy: 0.9658170515097693 Val Loss: 0.08888424655038213 Val Accuracy: 0.9585449735449736CPU times: user 8min 41s, sys: 6min 12s, total: 14min 54s
Wall time: 14min 58s
当我们考虑损失时,学习曲线表示三个时期的合理损失:
现在我们可以从一篇生物医学论文摘要中随机标记一个句子:
( - O
i - O
) - O
Genetic - O
experiments - O
demonstrate - O
that - O
complementation - O
of - O
an - O
in - O
- - O
frame - O
deletion - O
of - O
HisG - S-Protein
from - O
Escherichia - O
coli - O
( - O
which - O
does - O
not - O
possess - O
HisZ - S-Protein
) - O
requires - O
both - O
HisG S-Protein
and - O
HisZ - S-Protein
from - O
L - O
我们看到它已经正确地标记了单个/单独的蛋白质提及。然而,考虑到大量的“0”表示与手头的任务无关的单词,由于训练数据中的示例数量太多,所以存在过度适合标记为“0”的结果。这种标签不平衡将是未来需要改进的地方。
五、结论
我们大致了解了 BioBERT 是如何运作的,以及它是如何扩展 BERT 的工作的。通过利用 BioBERT,我们试图通过 NER 任务正确地标记生物医学文本。我介绍了我的 BioBERT 实现,它导入了必要的文件,预处理了数据,最后构建、训练和测试了模型。对于 Colab 中 BERT 的更深入分析,我强烈推荐 ChrisMcCormickAI 的教程。在实用自然语言处理的第 10 章中也有一些与 NLP 工具和应用直接相关的有价值的信息(包括 BioBERT!)在医疗保健行业。我希望这有助于引导您了解生物医学领域的最新模型。
[1]:德夫林等人。艾尔。(2018 年 10 月)。伯特:语言理解深度双向转换器的预训练https://arxiv.org/abs/1901.08746
[2]:李等。艾尔。(2019 年 9 月)。 BioBERT:用于生物医学文本挖掘的预训练生物医学语言表示模型【https://arxiv.org/abs/1901.08746
如何改变你在 excel 中的数据来做有效的尾部支出管理?逐步指南|第 03 章
第 03 章—逐步指南的数据准备
在花了几年时间用 Excel、Tableau、Python 进行采购分析,并详细评估了当前市场供应商的产品功能后,我可以自信地说,支出分析作为一个问题被高估和高估了。是的,在支出分析中,机器学习变得绝对必要(我们将在后续章节中讨论这些部分),但如果你的公司刚刚开始进行支出分析,Excel(或者任何可以切割数据的工具)将会很好地完成这项工作。一切都是为了准备和细节,而不是复杂的工具
我们现在将着手准备我们的数据集。你可以在这里找到样本数据集。除了我们在第 2 章中讨论的 4 列之外,我还添加了另外两列,即“供应商类别”和“采购订单类别”。“供应商类别”基于供应商数量,“采购订单类别”基于“采购订单数量”。
花类:
让我们继续添加我们的第一列“消费类”。请仔细遵循以下步骤:
步骤 1: 使用“raw_dataset”工作表插入一个透视文件,并重新排列行&列以匹配下图。确保以下字段处于正确的位置:
商品描述:成排
*总 PO 值:In Values(商品描述的排列百分比运行合计)。*确保该字段按升序排列。
注意:要获得表示为%(如上所示)的总 PO 值,您必须进入“值字段设置”选项。这可以通过点击值字段中的下拉箭头(“ITM _ 总计 _AM2 的总和”)&从下拉列表中选择来找到。之后,在“显示数值为”选项下,选择“ %运行总数在”。最后一步是选择一个基本字段。在这种情况下,基本字段是“商品描述”。
**第二步:**如第 02 章所述,我们的目标是从尾花中分割出主花。因此,向下滚动 total %列,直到达到 80%的数字。从 0%到 80%的项目(换句话说,前 80%)将被标记为“主要花费的项目。同样,从 80%到 100%(换句话说,最底层的 20%)的项目将被标记为“尾花”。将整个列表复制到一个新的单独的 excel 工作表中,并将其命名为“ WIP 工作表”。现在,您的 excel 文件应该类似于下图。
在新的 WIP 工作表中,插入一个新列,并将其命名为“支出类别”(列 C)。在这一栏中,我们会将每个项目标记为“主要支出”项目或“次要支出”项目。对于 B 列,我们有总支出百分比,滚动到 80%支出(即从 0%到 80%),并在 C 列(“支出类别”)中填写**“主要支出”。对于剩下的 20%(即从 80%到 100%),写“尾花”。**重复此过程,直到到达最后一项。您的"*WIP 工作表"*应该如下图所示:
步骤 3: 我们现在几乎准备好在" *WIP 工作表"中使用这些数据,并将其填充回我们的主" raw_data "工作表中。现在只需要一个简单的 Vlookup 就可以了。返回到“raw _ data”工作表,如上所述,使用商品描述上的“Vlookup”*功能,并选择消费类别来填充它。下面是这样做的公式:
= VLOOKUP(B2,’ WIP 工作表’!$A 1 : 1: 1:C$6681,3,FALSE)
其中列 B2 暗示包含商品描述的“raw_data”工作表中的列 B
$A$1: $C$6681 表示“WIP 工作表标签”中的列,A 列包含商品说明,B 列包含累计百分比,C 列包含支出类别
完成后,“raw_data”工作表中的“支出类”列应该如下图所示。搞定!
合同:
让我们添加第二列“合同”。这个简单明了。请参考“ raw_data ”工作表中我命名为“主协议”的列。正如第 02 章所讨论的,逻辑很简单。如果“主协议栏为空(如下图所示),我们将填写“合同不可用”,如果“主协议栏不为空,我们将填写“合同可用”。我们将使用此逻辑填充所有单元格。
下面是这样做的公式:
=IF(I2 <>" ",“合同可用”,“合同不可用”)
其中 I2 表示“raw_data”工作表中的 I 列(名为“主协议”)。< >“符号表示“不等于”,“符号表示空白”。因此,在这个公式中,我们检查 I2 是否不等于空白,然后写“合同可用”或其他。
将此公式拖到“*raw _ data”*工作表的最后一个单元格。完成后,合同列应该如下图所示。搞定!
采购订单:
我们继续我们的下一个专栏“PO”。这里,我们将重复添加合同列时的相同步骤。只是,我们将使用 K 列( Purchase_Order ),而不是 I 列(主协议)。因此,如果“采购订单”列为空,我们将写“采购订单不可用”,如果“采购订单”列不为空,我们将写“采购订单可用”。使用此逻辑填充所有单元格。下面是这样做的公式:
=IF(K2 <>" ",“采购订单可用”,“采购订单不可用”)
其中 K2 表示“原始数据”工作表中的 K 列(名为“采购订单”)。“< >”符号表示“不等于”,“符号表示空白。因此,在这个公式中,我们检查 K2 是否不等于空白,然后写“PO Available”或其他。
将此公式拖到“*raw _ data”*工作表的最后一个单元格。完成后,PO 列应该如下图所示。搞定!
供应商数量:
**关键时刻之一已经到来。**现在,我们将计算每种商品描述的供应商数量。如果你还记得第 2 章,我们首先想知道每个项目的供应商数量,然后将他们进一步细分为高、中、低类别。在 Python 中计算每件商品的供应商数量很容易,但在 excel 中有点复杂(至少我是这样做的)。
我的逻辑很简单,但需要几个步骤。我将首先获得每个商品描述的所有供应商名称的列表。供应商名称可以很多,但商品描述必须是唯一的。简而言之,一对多关系(一个商品描述可以有多个供应商名称)。
第二步是将这些信息复制到一个新的工作表中,然后在 raw_data 工作表中使用 COUNTIF 公式来获得实际的供应商数量。遵循下面提到的步骤来实现这一目标。
从重新排列数据透视表开始
回到我们的数据透视表工作表,根据下图重新排列。如果你能自己做,你可以跳到第三步。否则,请遵循以下说明。
第一步: 我们先从拉商品描述和法定名称信息开始。在数据透视表的行部分,首先拉入“商品描述”,然后拉入“供应商的法定名称”。
第二步: 现在,让我们来改变一下我们透视表的布局。为此,选择数据透视表,然后您将能够在顶部看到 Design 选项卡。在 Design 选项卡下,单击 Report Layout 选项,您将能够看到几个选项。你必须选择下面提到的两个选项:
a .)选择“以表格形式显示”
b .)选择“重复所有项目标签”
第三步: 取消选择商品描述行的小计。这可以通过右击任何商品描述并取消选择“小计”选项来完成(参考第二张图片)。
一旦您完成了*步骤 1、2 和 3,*您的数据透视表应该如下图所示。如您所见,我们现在有一个表格,左边是商品描述字段,右边是供应商的法定名称。完美!
步骤 4: 现在让我们将此表复制到一个新的工作表“供应商数量”中。我们将在 A 栏中显示“商品描述”,在 B 栏中显示“供应商的法定名称”,如下所示。
现在,让我们开始*计数。*我们将使用此表来最终统计每种商品描述的供应商数量。导航回我们的“Raw_Data”工作表,在“供应商数量”列(我们之前插入的那个)中,使用 COUNTIF 公式。由于 COUNTIF 函数需要一个数据范围,我们将使用新的“供应商计数”工作表中的数据范围。下面是这样做的公式:
=COUNTIF(‘供应商计数’!$A 1 : 1: 1:B$13412,Raw_Data!B2)
其中 A1 表示 A 列(包含“商品 _ 描述”),B 列表示“供应商数量”工作表中供应商的法定名称。Raw_Data!B2 暗示到原始数据工作表中的 B 列(包含“商品描述”)。
将此公式(将在 Y 列中输入)拖动到“*raw _ data”*工作表中的最后一个单元格。完成后,“*供应商编号”*栏应如下图所示。我们最终获得了每种商品描述的供应商数量信息。搞定了。
供应商类别
这是我们在本章中增加的少数几个栏目之一。让我们创建一个新列,并将其标记为“供应商类”。如第 2 章所述,我们将进一步将该供应商分为 3 类(如下所述),以帮助我们进行分析。由于我们已经计算了每种材料描述的供应商数量,我们可以将它们分为以下类别之一:
a.) 单个供应商 (其中供应商计数为 1)
b.) 在 1 到 5 之间 (其中供应商数量在 1 到 5 的范围内)
c.) 超过 5 个 (其中厂商数大于 5)
注意:我选择了 5 个供应商作为我的上限。可以根据商品行情适当选择自己的上限。
下面是填充“*供应商类别”*列的公式:
=IF(Y2=1,“单一供应商”,IF(AND(Y2>1,Y2<5),“介于 1 和 5 之间”,“大于 5”))
其中 Y2 表示“raw_data”工作表中的 Y 列(包含“供应商数量”)。这里我们使用了一个 IF 条件。逻辑是针对供应商值的数量为 1 的情况,写“单一供应商”。对于供应商数量值介于 1 和 5 之间的情况,填写“介于 1 和 5 之间”,对于所有其他情况,在“供应商类别”栏中填写“大于 5”。
将此公式(将在“供应商类别列中输入)拖至“*raw _ data”*工作表的最后一个单元格。完成后,“*供应商类”*列应该如下图所示。搞定了。
位置数量
类似于卖方编号,我们现在也需要计算“POs编号”列。让我们在我们的*“raw _ data”工作表中添加一个新列,并将其标记为“位置编号”。*通过我们在第 2 章中的初步分析,我们现在必须知道,我们的数据集中的每个行项目都有一个 PO。我们还有许多订单字段为空的行项目,因此我们在“ PO ”栏中填写了“ PO 不可用”。
计算*【位置号】*的逻辑很简单。我们必须计算商品项目描述字段在数据集中出现的次数。这是假设我们每个行项目都有一个采购订单,并且它是唯一的。在所有实际场景中,情况可能是这样,也可能不是这样。如果您遇到这种情况,我建议您遵循我们在“供应商编号”栏中采用的方法。
回到我们的数据集,使用 COUNTIF 函数计算一个商品描述在数据集中出现的次数是相当容易的。但是,我们必须减去数据集中“ *PO 不可用”*的情况。为了总结这一逻辑,我们必须做到以下几点:
(商品描述出现的次数)——(该商品描述出现 PO 不可用的次数)
为此,我们将使用 COUNTIFS 函数,而不是使用COUNTIFf函数。以下是填充“*位置编号”*列的公式:
= COUNTIFS($B$2:$B$72854,B2,$X$2:$X$72854,“PO Available”)
B2 暗示到“原始数据”工作表中的 B 列(包含“商品描述”),X2 暗示到 X 列(包含“采购订单”和采购订单可用值&采购订单不可用值)。通过选择“PO Available”过滤器,我们将得到同时满足两个条件的结果,即商品描述在数据集中出现的次数以及 PO Available 的条件。
将该公式(输入到栏的*号中)拖动到“*raw _ data”*工作表的最后一个单元格。完成后,“*POs 号”栏应如下图所示。搞定了。
采购订单类别
与“*供应商类别”*栏类似,我们将“*订单编号”*信息进一步细分为 3 个类别(如下所述),以帮助我们进行分析。由于我们已经计算了每种材料描述的采购订单数量,我们可以将它们分为以下类别之一:
a.) 单个采购订单 (一次性采购:其中采购订单数为 1)
*b .)*1 到 12 之间 (采购订单数量在 1 到 12 范围内的现货订单)
c.) 超过 12 个 (高频 POs:其中 PO 计数大于 12)
我们的主要目标是找到高频 POs,以便进行整合。
注意:我将“*高频 POs”*定义为每月至少 1 个 PO(因此每年 12 个 PO)。您可以根据您的初步数据分析来更改该数字。
现在我们已经定义了我们的段,下面是填充“PO*Class”*列的公式:
=IF(AA2=1,“单个采购订单”,IF(AND(AA2>1,AA2 <12),”Between 1 and 12",”More Than 12"))
其中 AA2 表示“原始数据”工作表中的 A 列(包含“采购订单数量”)。这里我们使用了一个 IF 条件。逻辑是针对 PO 值的数量为 1 的情况,写“单个 PO”。对于采购订单数量介于 1 和 12 之间的情况,请填写“介于 1 和 12 之间”,对于所有其他情况,请在“采购订单类别”栏中填写“大于 12”。
将此公式(将输入到“采购订单类别列中)拖动到“*raw _ data”*工作表中的最后一个单元格。完成后,“*PO Class”*列应该如下图所示。搞定了。
结论
全部完成!我们在准备数据集方面走过了漫长的道路。事实上,我们现在都准备好开始我们的切块和切片!在下一章,你将会看到,我们如何从所有这些艰苦的工作中获得益处!
第 04 章
让我们从理解现有数据开始。然后,我们将通过解决 【隐藏的尾巴】 问题,深入分析我们的第一个大的成本节约机会。
[## 尾部支出中最大但经常被忽略的部分是什么?隐藏的尾巴!第 04 章
第四章:隐藏的尾巴。找到并修复它。
medium.com](https://medium.com/procurementintel/tail-spend-analysis-chapter-04-hidden-tail-4e5fdda97194)
我很感激你的评论,这样我可以进一步改进这些课程。
对于即将到来的采购课程的简短总结,您可以随时
订阅我的刊物:【https://medium.com/procurementintel】
在 LinkedIn 上关注我:https://www.linkedin.com/in/gsrm/
轻松定制用于论文和演示的图表
不要让你的观众斜视
在合适的场合使用合适的尺寸。杰西卡·鲁斯切洛在 Unsplash 上的照片
你有没有坐在演示文稿中眯着眼睛看幻灯片,努力阅读带有微小文字的图表?或者更糟的是,在海报上看到一个模糊的身影,让人无法看清坐标轴?人们经常倾向于在不同的媒体上复制相同的数字,如网站上的文章、演示幻灯片、期刊文章(pdf 文档),导致不愉快的用户体验。让我们变得更好。
在这篇文章中,你会学到-
- 为什么要修改每种媒体的数字
- 如何用一行代码轻松修改它们
我分享的例子是用 python 写的,但是我提供了用 R 和 Matlab 复制相同方法的资源。
适用于屏幕的东西不适用于幻灯片
演示文稿和论文/网络文章之间的距离与屏幕大小的比率不同。来自 svgrepo.com和 clipartmax.com和的作品
人们在准备演示时最常犯的错误是使用他们在网上/杂志文章中使用的相同数字。这是错误的,因为人们从不同的感知距离观看文章和演示。当一个人从 2.5 英尺外的约 1 英尺屏幕上阅读文章时,他们从 40 英尺外的约 10 英尺屏幕上观看演示。
这意味着一个在计算机屏幕上看起来可读的图形在投影到幻灯片上并从房间的最后一排观看时可能是不可读的。因此,图形元素必须放大。**根据经验,如果您正在笔记本电脑上制作图表/图形,但想将其包含在演示文稿中,请后退一步,检查图形是否可读。**如果没有,放大注释并加厚线条/点,然后重试。
然而,为每个图形手动地做这件事,或者每次你想要转换你的图形是乏味的。我们如何实现自动化?
介绍样式表
样式表是自动获取几个样式命令的简单方法。本质上,它们包含了改变不同元素的默认样式参数的指令,如图形大小、线条宽度等。尽管 matplotlib 和一起提供了几个预制的样式表,但是它们中的大部分都专注于美学而不是绘图媒介。
要为不同的媒体创建自己的样式表:
- 在 python 中输入“matplotlib.get_configdir()”找出 matplotlib 的配置目录。
- 转到该目录,并在其中创建一个名为“stylelib”的目录
- 在 stylelib 目录中为每个带扩展名的绘图介质创建新的样式表。mplstyle”(例如“presentation.mplstyle”)。该文件的内容将在本文后面解释。
- 你都准备好了!从现在起,您只需输入以下内容,就可以根据您的图形的预期目的使用所需的样式:
plt.style.use(’presentation’)
# for producing figures for your presentation slides
如果你是一个 R 用户,你可以使用级联样式表包跟随这篇文章。如果你是一个 Matlab 用户(我很同情),你可以创建自定义。使用本博客末尾提到的命令将 m 文件作为样式表。至此,让我们学习不同的媒体使用什么样的风格参数。
文章和论文的样式表
我们大部分的数字制作实践都是为文章和论文量身定制的,因为我们在创建它们的同一距离上观察它们。因此,当你创建一个图形时,只要看起来不错,在发布时就应该足够了。
我使用下面的样式表为我的在线文章创建图表(我的“article.mplstyle”文件的内容):
lines.linewidth : 1.5
lines.markersize : 4
figure.figsize: 3.54,3.54
figure.dpi: 200
font.size: 10.0
axes.titlepad: 6.0
axes.linewidth : 0.8
legend.frameon: False
xtick.major.width : 0.8
ytick.major.width : 0.8
对于期刊论文,由于期刊之间的差异,我不会自己调整风格。相反,我使用的是 plotsettings ,这是一个专门为此构建的 python 包——根据每个期刊的规则自动裁剪数据。
演示文稿的样式表
为了演示,我加厚线元素,放大标记元素,提高分辨率,并将文本元素放大 1.5 倍。这大致与观看比率成比例(4/2.5 ~ 1.5),并确保我在笔记本电脑上创建的图形在投影仪上从最后一行观看时看起来相同。我使用下面的样式表为我的演示文稿创建图表(我的“presentation.mplstyle”文件的内容):
lines.linewidth : 2.25
lines.markersize : 6
figure.figsize: 3.54,3.54
figure.dpi: 300
font.size: 16.0
axes.titlepad: 8.0
axes.linewidth : 1.1
legend.frameon: False
xtick.major.width : 1.1
ytick.major.width : 1.1
比较两个样式表产生的输出,差异是显而易见的:
使用两种不同的样式表比较同一个数字。图片作者。
最后,除了调整大小之外,还有许多其他的调整可以让你的数字在演示文稿中更具可读性。你可以减少显示的数据量,使用容易在投影仪上渲染的颜色,等等。在这篇精彩的 PLOS 文章中可以找到这样的提示。
我们学到了什么?
- 善待你的读者,避免在你的文章、论文和演示中使用相同的数字
- 样式表是为每种媒体定制图形的简单方法
- 我的 matplotlib 样式表可以在这里找到
- 一旦创建并保存了样式表,就可以通过键入- plt.style.use(" ")来快速使用它们
有没有其他方法可以根据不同的媒介来裁剪人物?在下面留下回应。
用 Jinja 完全控制你的 Python 情节
使用 SVG 和 Jinja 在 Python 中创建完全自定义的绘图
你是否曾经花了太多的时间挖掘文档,试图让你的图看起来像你想要的那样?下一次,考虑放弃 matplotlib 或 seaborn,使用Jinja
创建一个自定义的绘图。
Jinja 是一种 Python 模板语言,基于 Django 模板,你可能从 Flask 或 Airflow 等其他包中熟悉它。它有很多有用的功能,但你只需要一些基础知识就可以开始了。
在 Jupyter 中,您可以使用 Jinja 将您的视图制作成 SVG(工作流程与 D3 非常相似)并显示它们。
一些基本的 SVG
在我们进入正题之前,让我先介绍一些基础知识。SVG 代表可缩放矢量图形,这意味着所有图像数据都存储为矢量空间中的点,因此可以在不进行像素化的情况下调整大小(不像光栅图像)。
SVG 是基于 XML 的,有许多不同的标签,代表不同的路径和形状。一些关键标签是:
circle
:使用 xy 坐标和半径画一个圆rect
:使用左上角的 xy 坐标加上宽度和高度绘制矩形polyline
:画一条连接 xy 点的路径text
:绘制文本
每个 SVG 元素都有自己可以更改的属性,但是大多数元素都有共同的属性来控制填充和笔画。
创建 SVG 时要记住的另一个关键点是, xy 坐标从左上角的 (0,0) 开始,随着向右下角移动而增加。
关于使用 SVG 的更多信息,请查看 Mozilla 的参考资料这里。
现在到金贾…
Jinja 模板的(迷你)介绍
Jinja 的模板有很好的特性,比如循环、条件和模板继承,这只是皮毛;有大量的功能。
下面是一个 Jinja 模板的基本示例:
{% for name in names %}
Hello, {{ name }}, welcome to {{ place }}!
{% endfor %}
如果你用names = ["tim", "sue", "tom", "sally"]
和place = "my party"
渲染模板,你会得到…
Hello, tim, welcome to my party!
Hello, sue, welcome to my party!
Hello, tom, welcome to my party!
Hello, sally, welcome to my party!
更多关于 Jinja 模板的信息,请查看文档。
现在,让我们继续建立一个金贾的阴谋。
与金佳密谋
让我们使用 Jinja 用一些示例数据制作一个简单的演示散点图。
首先,这里是我将在模板中使用的数据和一些基本布局信息:
用于绘图的数据和布局信息。
现在让我们制作模板,它将是 SVG 的 XML 风格标记和特殊 Jinja 命令的混合:
让我们假设我们的模板作为一个字符串存储在变量plot_template
中。
现在我们可以使用我们的 plot 和 layout 数据渲染模板,代码如下:
下面是作为 svg 的渲染图:
以下是作为参考的 png:
使用 Jinja 在 Python 中创建的 SVG 演示图
对于完整的代码,检查要点在这里。
结论
如果你只是做 EDA 调用plt.scatter(x,y)
仍然是一条路要走,但如果你想能够完全定制你的情节,尝试使用 Jinja。启动可能需要更多时间,但您的模板很容易重复使用,并且您不会受限于您的绘图库所支持的绘图。
SVG 的另一个巨大好处是能够从另一个 SVG 复制路径,并将其合并到您自己的路径中。例如,如果您想将散点图中的点更改为您公司和竞争对手的徽标,您只需下载 SVG 徽标,并用徽标路径替换模板中的圆圈。
感谢阅读!我很想知道你对这项技术的看法——如果你有任何意见或建议,请告诉我!
为机器学习消除数据清理的痛苦
…有了这四个 python 库
根据 Anaconda 最近的 2020 年数据科学状态 调查,这是一个很好的阅读,顺便说一下,大多数数据科学家 66%的时间仍然花在数据加载、清理和可视化上。
现实世界的数据集总是杂乱无章。包含缺失值和错误值、分类数据和缩放不当的变量。在我们可以使用这些数据来建立机器学习模型之前,数据科学家必须(通常是煞费苦心地)分析数据,以确定要应用的适当预处理技术。然后花更多时间执行这些数据清理和转换任务。
幸运的是,目前有开发人员正在研究这个问题的解决方案。在本文中,我将介绍四个开源 Python 库,它们使数据准备过程更容易、更健壮。
1.熊猫简介
pandas-profiling 库是一个工具,它允许您快速了解数据集的质量,并在一行代码中计算基本的统计数据。这个包有一个名为ProfileReport
的函数,默认情况下它会加载一个给定数据集的探索性摘要。
该软件包可以通过 pip 安装。
pip install pandas-profiling[notebook]
让我们加载一个数据集,并在 Jupyter 笔记本中运行标准 profile 报告。
配置文件报告显示如下所示。
2.Dabl
Dabl 由 Scikit-learn 项目的核心开发者之一 Andreas Muller 开发,是一个数据分析库,旨在使机器学习项目的数据探索和预处理部分变得更加容易。
Dabl 可以通过 pip 安装。
pip install dabl
Dabl 有一个内置的功能,可以自动检测数据类型和质量问题,并对数据集进行适当的预处理,为机器学习做准备。这包括执行诸如处理缺失值和将分类变量转换为数值之类的任务。
data_clean = dabl.clean(data)
Dabl 库也有许多用于快速数据浏览的内置可视化功能。简单地在数据集上调用 dabl.plot()
将产生下面的一组图表。
dabl.plot(data, 'class')
3.动力操作研究机构(dynamic operators research apparatus 的缩写)
Dora 库是另一个数据分析库,旨在简化探索性数据分析。
该软件包还包括用于清理、转换和可视化浏览数据集的实用工具。尽管它有别于其他类似库的一个特性是它的数据版本控制能力。
Dora 提供了一个简单的接口,可以在转换数据集时获取数据集的版本或快照。它还保留了所做更改的日志,以便您可以轻松地跟踪转换。
Dora 可以通过 pip 安装。
pip install Dora
下面的代码演示了如何使用这个库来执行数据清理、预处理、数据版本控制和跟踪数据的变化。
4.漂亮的熊猫
Pretty pandas 旨在与核心 pandas 库一起工作,为您的数据提供一种创建“漂亮”汇总表的简单方法。这在与其他人共享数据时尤其有用,比如项目中的利益相关者。
要安装 run。
pip install prettypandas
在下面的代码中,我们用漂亮的熊猫给数据集的汇总视图添加一个总平均值。
我们距离解决作为机器学习项目的一部分,需要在数据准备上花费多少时间的问题还有很长的路要走。这部分是由于现实世界中数据的高度可变性,因此这是一个难以自动化的过程。然而,本文中讨论的库在某种程度上减轻了这项耗时任务的痛苦。
感谢阅读!
我每月发一份简讯,如果你想加入请通过这个链接注册。期待成为您学习旅程的一部分!
向量子领域迈出第一步
你的想法太经典了
量子门和量子电路导论
作者使用 Canva
开始使用量子计算可能看起来令人生畏,如果你在网上搜索 start,你可能会得到和我第一次开始使用量子计算时一样的结果。我到处都在说,要开始,我需要有一些关于量子物理学、量子力学和基本线性代数的知识。一旦我这样做了,我需要学习如何使用 Qiskit (Python 库来编程量子计算机)或另一种编程工具来开始构建量子电路和实现量子算法!不要让我开始需要学习量子算法是如何工作的!
事情变得非常复杂非常快,这可能是相当令人沮丧的!😖
但是…
如果我告诉你,你可以开始构建量子电路,只需要基本的量子门的基本知识,不需要任何类型的编码,会怎么样?
是🤩
你没看错;我们将在不使用任何代码的情况下构建量子电路。
做到这一点的方法是使用一种叫做量子电路模拟器的特殊工具。要使用这些工具中的任何一个,你只需要知道量子计算的三个基础的定义,量子位,叠加和纠缠,以及一些基本的量子门是做什么的。
我们将从量子计算的基础开始:
- 量子位: 量子计算中数据的基本单位。一个量子位可以处于|0⟩态或 state|1⟩态,或者是两种态的叠加态。
- 叠加: 一个术语,指一个物理系统同时以两种状态存在。
- 纠缠: 当两个或两个以上的量子比特共享一个特殊的连接时。
你可以在我的文章“量子计算的三大支柱”中找到关于量子位、叠加和纠缠的更深入的信息
理解量子计算机如何工作的基础
medium.com](https://medium.com/digital-diplomacy/the-three-pillars-of-quantum-computing-d80ff5f50ec7)
现在你已经知道了量子计算的基本原理,我们可以开始谈论基本的量子门,然后开始使用它们构建一些电路。
量子门
外面有许多量子门;一旦你完全理解了基本的,你甚至可以创建你的自定义门。量子门是量子电路的组成部分。它们是在一个或多个量子位上执行特定功能的操作符。它们是经典逻辑门的量子等价物,如今被用于所有技术中。然而,与大多数经典逻辑门不同,量子门是可逆的,这意味着你可以通过重新应用相同的量子位来撤销它们的影响。
数学上,量子门是用酉运算来表示的。酉运算就是方阵(行数和列数相等的矩阵)。另一方面,量子位的状态被表示为一个向量。从几何学的角度来说,向量通常有一个振幅和一个相位来表示它在空间中的三维位置。要找出对任何状态的量子位元应用闸的结果,我们只要用闸的矩阵乘以量子位元的状态向量。
作者使用 Canva
我们现在开始讨论单量子比特量子门。这些门一次只能控制一个门。这些门可以扩展到运行更多的量子位,我们很快就会看到。在本文中,我们将介绍六种基本的量子门:身份门、哈达玛门、泡利(X、Y 和 Z)门和受控非门。
1-身份大门
身份门(符号为 I )是一个单量子位门,它保持量子位的状态不变。这可能看起来没用,我是说,为什么我们会有一个什么都不做的门?I 门有用有两个原因:
- 它通常用于数学计算,以证明门是可逆的。
- 在实际硬件上执行 gate 时,这是很有用的。这是一种精确地告诉它什么都不做或者什么都不做的方法。
作者使用 Canva
2-非门
非门( X )是一个单量子位门,它翻转它所操作的量子位。如果我们给它|0⟩,它会返回一个|1⟩,如果我们给 it|1⟩,它会返回一个|0⟩.在具有许多叠加态的应用中,该门用于将特定态与整体态隔离开来。
作者使用 Canva
3-哈达玛门
哈达玛门(H)是魔法之门🌟。它是负责创造叠加态的门。不管输入态是不是|0⟩ or|1⟩.,这个门都将量子位置于|0⟩和|1⟩态的 50/50 叠加态 H 门可能是最重要的量子门,它是许多量子算法的基本构件。
作者使用 Canva
如果给 h 门一个|0⟩作为输入态,它将产生一个叠加态,量子人们称之为正态|+⟩.如果我们给 h 门一个|1⟩态,它会产生负态|–⟩.
作者使用 Canva
4-Y 门
Y 门和 X 门类似,也是翻转门。然而,这些门之间的区别在于,y 门翻转状态|0⟩,然后将结果乘以一个虚数 j (给它增加一个相位)。这种额外的相位变化使得该门对于创建某些算法中使用的特定相长/相消干涉非常有用。
作者使用 Canva
5-Z 门
Z 门也是翻转门;然而,这个门不会翻转状态的值;相反,它会翻转相位。这个门在将 state|1⟩的相位乘以-1 时保持 state|0⟩振幅不变。
z 门的力量来自于它只影响|1⟩州而不影响|0⟩。这个门经常被用来突出显示系统中的一些状态,而保持其他状态不变。
作者使用 Canva
我们刚刚走过的所有单门量子位都可以通过添加控制和目标量子位扩展到受控门。这种工作方式的一个例子是受控非门。
6-受控非门
受控非(CX 或如图所示的 GIF)门是我们第一个操作两个量子位的门。这个门是一个条件门,当且仅当第一个量子位(控制量子位)的状态是|1⟩.时,它对第二个量子位(称为目标)执行 x 门结合其他的门,CX 门将允许我们构造各种多量子比特操作。
作者使用 Canva
好了,现在我们已经了解了基础知识,让我们来谈谈如何使用这些门——以及更多——来构建一个量子电路。我们将使用量子电路模拟器。
量子电路模拟器
量子电路模拟器是一种特殊的工具,允许你建立和模拟量子电路,而不需要写任何代码或执行任何数学技巧!由于量子计算是一个正在进行的研究领域,新的工具经常被开发出来,以帮助人们熟悉量子门和量子电路,并为量子时代的到来做好准备。最好、最简单的基于浏览器的产品(无需安装😁)量子电路模拟器,在我看来是:
- IBMQ 体验 : IBM 提供了一个拖放式电路编辑器,允许您构建电路并查看结果。
- Quirk : Quirk 是一个拖放式量子电路模拟器,运行在你的浏览器中。这个工具是由谷歌软件工程师克雷格·吉德尼开发的。
- QUI : QUI 是一个编程和模拟环境,旨在让用户可视化和理解量子算法的内部工作原理。
在本文的其余部分,我将使用 IBMQ circuit composer 来模拟两个简单的电路。然而,你可以使用上面的任何模拟器来实验量子电路。
熟悉 IBMQ Circuit Composer
一旦打开 IBMQ Circuit Composer,您将看到这个屏幕:
你可以通过简单的拖放来给特定的量子位设置门。如果你需要更多的量子位,你可以点击最后一个量子位下面的小+号,这将为电路增加一个量子位。您可以通过点击量子位并按下键盘上的 DELETE 键来删除量子位。在右侧,您可以看到一个条形图,显示电路的最终状态。空电路有一个状态|0000⟩.每次添加一个门,产生的状态都会相应地改变。
我们的第一个量子电路
我们现在准备建立我们的第一个量子电路!让我们从一个简单的开始。
假设我们想要创造一个电路,只要它是 1,就翻转任何给定状态的最后一个量子位。例如,|1011⟩会变成|1010⟩,因为最后一位是 1。然而,如果输入状态是|1100⟩,电路不会做任何改变,将返回相同的状态。我如何才能做到这一点?
最初,所有的量子位都被设置为|0⟩状态,所以我们需要创建起始状态,例如,首先是|1011⟩状态,然后应用一些门来翻转该状态的最后一位。
在我们开始之前,状态通常是从右向左读取的,在 composer 中是从上到下。
步骤 1: 创建 starting|1011⟩状态
为了创建|1011⟩态,我们需要将 x 门应用于量子位 q[0]、q[2]和 q[3],如下面的视频所示。
第二步: 翻转最后一个量子位。
为了翻转最后一个位元,我们会在电路中再加入一个量子位元。这个额外的量子位将作为控制量子位。首先,只有当电路的最后一个量子位是 1 时,我才需要这个量子位处于|1⟩状态;否则,它将在|0⟩.这可以通过在 q[3]和 q[4]上使用 CX 门来实现。
如你所见,现在的结果是|10111⟩;我们可以忽略最后一个,因为它是我们刚刚添加的一个额外的量子位,以帮助我们实现我们的目标。也就是说我们的状态还是没变。接下来,我们将使用 q[4]作为另一个 CX 门的控制,并使用它来翻转 q[3]。
现在,我们得到的状态是|10101⟩,没有 q[4],它将是|1010⟩,这是我们想要的结果!耶!
但是,如果我输入最后一个量子位等于 0 的状态呢?让我们看看会发生什么!如果我们将状态|1000⟩输入到电路中,产生的状态将与我们的输入状态相同。
耶!你刚刚建立了你的第一个量子电路,没有进入量子力学或者写代码!👏
如果你知道如何使用电路模拟器工作,你可以建立任何电路,一旦你足够舒适,你可以开始使用代码来创建你的电路,因为你深入到量子领域。
参考
[1] Brylinski,J. L .,& Brylinski,R. (2002 年)。通用量子门。量子计算的数学。
使用 Matplotlib 让你的直方图更上一层楼
如何让最无聊的情节变得有吸引力和知识性
直方图是可视化变量分布的最常用方法。一个简单的直方图对于浏览数据非常有用。然而,与其他著名的绘图类型如饼图、条形图或折线图相比,它们看起来相当乏味。最重要的是,它们需要有统计学背景才能被正确解释。然而,在我们完全抛弃直方图之前,让我们试着让它更漂亮,信息更丰富,也更容易解释!
在本教程中,我们将采用一个标准的 matplotlib 直方图,并从美学角度对其进行改进,同时添加一些有用的组件。为此,我们将遵循一个三步程序,正如我的文章“从数据分析师到数据故事讲述者”中所阐述的:
- 添加信息
- 删除信息
- 强调信息
数据集和第一个图
对于本文,我们将使用来自 kaggle 的“鳄梨价格”数据集。市场中的价格分布是直方图的一个有用的应用。
为此,我们只需要这两个库:
import pandas as pd
import matplotlib.pyplot as plt
因为我们只需要一列(“AveragePrice”),所以我们可以将数据作为一个系列而不是 dataframe 来读取。这样,我们将节省以后指定列的时间。
avocado = pd.read_csv("avocado.csv")["AveragePrice"]
我们的第一个也是非常基本的历史程序可以使用下面的代码非常容易地绘制出来:
fig, ax = plt.subplots(figsize = (6,4))
avocado.plot(kind = "hist")
plt.show()
第一个情节
按照本教程的三个步骤,我们将得到这个最终结果:
我们开始吧!
步骤 1:添加信息
一个显而易见的事情是添加一个标题和轴标签。如果你比较上面的两张图,你还会发现第二张图中的直方图没有那么“块状”。我们可以通过增加仓 的数量来实现这一点,这实质上是直方图将数据划分成的类的数量。更多的箱将使直方图更平滑。最后,您可能已经意识到第二个图形在直方图周围有一条线。这条线被称为核密度估计(KDE)。 KDE 试图计算变量的基本分布,这将在直方图周围画出一条非常平滑的线。然而,只有当我们将 y 轴从绝对值变为密度值时,KDE 才会起作用。这样做的缺点是密度值对大多数人来说很难解释。我们稍后会解决这个问题。首先,我们来编码这个!
添加信息绘图
我们可以看到,可视化现在包含了更丰富的信息。然而,这并不完全是美丽的,有点势不可挡。让我们减少信息量,让剧情更干净。
第二步:删除信息
最后一个数字中的一些信息是不真实的,甚至是完全无用的。例如,对于大多数人来说,y 轴不再是可解释的。我们应该移除刻度和刻度标签并再次用“频率”标记轴。这将使读者了解轴的含义,而不会被不必要的数字所混淆。此外,KDE 还估算了 0 美元以下数值的密度。显然,我们需要通过重新调整 x 轴来解决这个问题。最后,在大多数情况下你可以删除图中的任何记号和刺而不会损失太多可读性。让我们应用所有这些:
用减少的信息绘图
这看起来已经干净多了。最后一步,我们可以强调特定的信息,并进行美学上的改进。
第三步:强调信息
强调信息不仅仅意味着增加字体大小,也意味着选择一种有益于你试图用视觉传达的信息的配色方案。由于这一步需要更多的代码,我将分别展示代码片段。
首先,我们需要一组不同的颜色。前几幅图中的橙色/蓝色组合看起来不太好。改变绘图布局的一个简单方法是改变 matplotlib 样式表。就我个人而言,我喜欢“bmh”样式表。然而,这个样式表添加了一个网格,这会分散我们的绘图注意力。让我们把样式表改成“bmh”,去掉它产生的网格。
plt.style.use("bmh")
# Later in the code
ax.grid(False)
另一个美学上的改进是减少直方图的不透明度。这将使 KDE 更占主导地位,这将给读者一个整体更流畅的印象。
avocado.plot(kind = "hist", density = True, alpha = 0.65, bins = 15)
为了让标题更加突出,我们可以增加它的字体大小。“pad”参数也允许我们添加一个偏移量。
ax.set_title("Avocado Prices in U.S. Markets", size = 17, pad = 10)
在这一步,我也想知道 y 标签“频率”是否是必要的。在测试了这两种变体之后,我发现 y 标签更令人困惑,而不是更有帮助。如果没有给出其他信息,我想我们直观的把 y 轴读成“频率”。
ax.set_ylabel("")
如果我们应用以上所有内容,我们会得到这个图:
带有强调信息的绘图(1/3)
此时,可视化已经为您的演示或报告做好了准备。然而,还有一件事我们可以做,使情节更容易理解。原则上,直方图包含了我们显示百分位数所需的所有信息。遗憾的是,无法直接从剧情中读出信息。如果我们想向老板展示鳄梨价格的第 75 百分位是多少,同时保留关于分布的所有信息,该怎么办?我们可以计算一些百分点,并在图中显示为垂直线。这类似于箱线图,但实际上集成到直方图中。让我们试试这个!
首先,我们要画出垂直线。为此,我们将计算分布的第 5、25、50、75 和 95 个百分点。一种方法是让每一条垂直线比前一条长一点,就像楼梯运动一样。我们也可以给内部线条比外部线条更高的不透明度。
为此,我们将把分位数、线不透明度和线长度存储在一个列表列表中。这将允许我们循环遍历这个列表,并自动绘制所有行。
带强调信息的绘图(2/3)
现在,我们需要添加标签。就像之前一样,我们可以使用不同的不透明度和字体大小来反映分布的密度。为了更好的可读性,每个文本应该相对于百分位线有一点偏移。
带强调信息的绘图(3/3)
我们现在可以使用这个直方图来做出以什么价格出售鳄梨的商业决策。也许我们的鳄梨比一般的鳄梨好一点,我们公司的鳄梨相当出名。也许我们应该收取分布第 75 百分位的价格(大约 1.65 美元)?这个直方图在某种程度上是直方图和箱线图的结合。
这是最终直方图的完整代码:
非常感谢您阅读这篇文章!希望你觉得有用。如果您有任何问题或批评,请给我留言或评论。
如何让你的编程技能更上一层楼
编程技能
遵循简单干净的代码原则,开发简单、可扩展、易读、易维护的程序。
尼古拉斯·酷(Nicolas Cool)在 Unsplash 上的照片
你曾经访问过你最近写的函数吗?也许你需要更新一个功能。但是,由于代码相当复杂,您通过使用“如果它有效,就不要碰它”的原则,让代码保持原样?
如果你现在打开你的遗留代码,你能马上理解它们吗?或者也许你需要花至少几分钟来记住代码是关于什么的?
如果你需要花更多的时间浏览,那么这篇文章很可能适合你。这里我们谈谈在不浪费时间的情况下理解遗产代码的方法 。
如果你遵循我们在这篇文章中描述的原则,你可能不需要浪费更多的时间去理解你的遗留代码,因为它们永远不会过时。
最近,我开始创建一个图书馆。久而久之,库已经超过了几千行。有趣的是,随着库变得更先进,一些意想不到的问题开始出现。
随着代码规模的增长,实现新的功能需要更多的时间。
由于该库处于开发阶段,它可能会有一些功能部件表现不佳。
例如,一个函数可能会因为单元测试中没有考虑到的极端输入值而失败。
这就是为什么每当我实现使用库的其他部分的新功能时,首先,我需要花一些时间来理解相关的函数。
乔治·帕甘三世在 Unsplash 上的照片
在检查了一个新功能并处理了失败的部分之后,随着时间的推移,同一个功能的其他部分会被破坏。
当我回到最近重构的函数时,我发现自己几乎什么都不记得了。我不得不重新检查相同的功能。
这个问题导致我来回地去理解一些代码片段大部分时间在做什么。
在某种程度上,我已经停下来,并开始寻找什么是错的。
尼古拉斯·酷在 Unsplash 上的照片
当我在寻找解决方案时,我发现了一个“干净代码”视频课程[1],它是由《干净代码》一书的作者 Robert C.Martin 准备的。
最后,在干净代码视频课程的帮助下,我已经解决了我所有的问题。不再有导致我浪费时间的糟糕的实现代码。
解决方案是干净的代码
在这里,我整理了《干净的代码》系列中的一些关键规则,即使过了几个星期,我仍然记得。通过应用干净代码原则,我所有的问题都解决了。
永远不要浪费时间借助干净的代码来理解一个函数的行为。
1 —命名
每个变量、类和函数名都应该描述自己。[1]
Guillaume TECHER 在 Unsplash 上拍摄的照片
让我们从回顾下面这段代码开始,这段代码是我在参加 Clean Code 视频课程之前写的。
示例 1:在重构命名之前
在这里,我们可以看到我们有一个网飞数据集,它提供了一种在数据集文件中加载电影的方法。
当我们深入研究这个函数的实现时,乍一看很难理解它到底在做什么。
现在让我们看下面的代码片段,例 1.1,它做的事情和例 1 完全一样。
示例 1.1-重构命名后
在代码示例 1.1 中,我们再次有一个加载电影的网飞数据集。但是,这一次,当我们查看 load movies 函数时,我们可以详细了解代码在做什么。
看代码就像一个英文脚本。
你甚至不需要阅读除了前 7 行之外的任何代码来理解代码在做什么,这与示例 1 相反,在示例 1 中,我们需要阅读所有的 12 行,并且还要弄清楚代码在做什么。
詹姆斯·巴尼特在 Unsplash 上的照片
在例 1.1 中,我们看到我们已经命名了很长时间的助手函数,这些函数只打算被 load_movies 函数使用。
因为没有其他函数会调用这些辅助函数,所以我们可以随心所欲地命名它们,对吗?
一天结束时,没有人再调用它们,我们只是在这里调用它们来给出有意义的函数名,并使代码本身更具描述性,而不需要任何注释。
此外,程序员通常需要理解 load_movies 函数在做什么,而不是理解它的实现细节,比如如何转换格式以及如何准确地从输入文件中读取数据。
如果一个程序员想弄清楚它们,那么他总是可以访问各自的私有函数,这些私有函数只由 load_movies 函数使用。
简而言之,我们应该有长的描述性名字,带有私有函数,这些函数会被调用一两次。
此外,我们应该有简短明了的公共函数,因为不同的程序员会多次调用它们。
最后,函数应该有不超过 2 到 3 个参数以增加可读性。
2 —注释
注释意味着不能写出干净的代码。如果任何注释存在于公共 API 之外,接受你的失败。[1]
如果有任何评论,那么知道是很重要的。[1]
让我们回顾一下下面的代码,例 2。同样,你根本不需要理解它。仅仅通过查看代码,我们就可以看到存在相当多的注释来使代码更容易理解。
示例 2:重构之前
在示例 2 中,我们看到数据有一个时间约束,可以是时间框约束或最大限制约束。
为了理解代码,我们需要阅读代码的每一行,包括注释。即使全部看完,你可能还是对这个时间约束的目的细节不太满意。
现在让我们来看看下面的代码,它是我在应用干净代码原则后写的。
示例 2.1:重构后(重要部分)
在这里,我们看到存在两种取决于间隔的时间约束。如果间隔有效并且属于预期类型,则满足约束,否则不满足约束。
“在这里,我所做的唯一一件事就是试图删除评论.”
如您所见,没有注释和复杂代码的 17 行代码传达了与旧版本的 58 行代码相同的信息。
以下代码片段是示例 2.1 的其余代码。
因为我们的目的是理解 TimeConstraint 类在做什么,我们甚至不需要回顾这段代码。因为,从它的名字区间来看,很清楚这个类是干什么的。
示例 2.2:重构后(剩余部分)
3 —功能长度
尽可能减少函数长度,直到不能。[1]
最佳函数长度为 4 到 10 行。[1]
沙哈达特·拉赫曼在 Unsplash 上拍摄的照片
让我们回顾一下示例 3,它加载了网飞数据集的用户电影评级数据。
示例 3:重构之前
这里我们看到 49 行长 load_ratings 函数。这个函数到底是如何实现其功能的还不太清楚。我们需要阅读每一行代码来彻底理解它。
现在让我们来看看代码的新版本,例 3.1,它遵循干净代码规则。
这里我们看到
我们有 7 行长负载额定值函数。load_ratings 函数本身很好地描述了它所做的事情,没有任何注释。我们甚至不需要阅读其他私有函数来理解代码。
示例 3.1:重构后
4-文件长度
文件应该平均 50-100 行,最多 500 行。[1]
照片由 Maksym Kaharlytskyi 在 Unsplash 拍摄
最后但同样重要的是,现在让我们回顾一下来自推荐系统库的一个代码文件惊喜。
在示例 4 中,我们可以看到代码片段超过 700 行!
尝试阅读代码片段,您很可能会被冗长的注释卡住。
- 它包括对库文档的不可理解的格式注释。
即使从这个库的设计者的角度来看,将文档放在代码内部可能很容易,但这确实使代码难以阅读,并且还会产生很大很长的文件。
永远不要在评论中放 HTML 或者任何格式的文本。这使得注释和代码难以阅读。
实例 4
应用干净代码原则后的变化
在接下来的几周里,在应用干净代码原则后,我的代码中开始出现以下症状:
- 代码是任何人都完全可读的,不仅仅是程序员。
- 除了他们想理解的函数,没有人需要阅读更多的代码。
- 代码看起来简单、漂亮、简短。
- 没有一个代码文件看起来令人生畏,难以理解。
- 任何功能都比以往任何时候都更容易构建。
- 缩放也相当容易。
干净代码原则有用吗?
从我的角度来看,只要阅读 17 行代码就能理解这 58 行庞大的代码在做什么。
这些原则使得代码更易维护、更干净、更简单,并且成本更低,因为没有程序员会浪费时间去理解它。
在使用干净代码原则之前,每当我回到一个无法理解的代码片段时,我会浪费相当多的时间去理解代码,而在这段时间里,我本可以为项目设计和实现新的特性。
照片由玛利亚·宝拉·孔特雷拉斯在 Unsplash 拍摄
干净代码原则
总而言之,我可以说,只要习惯了我在下面总结的干净代码原则,你就可以创造出更专业的代码。
生成的代码简单、可伸缩、易读,并且易于维护。
1-每个变量、类、函数名都应该描述自己。
2-函数最多应该有 2 到 3 个参数来增加可读性。
3-如果有任何评论,那么知道是很重要的。
4-注释意味着不能写出干净的代码。如果任何注释存在于公共 API 之外,接受你的失败。
5-尽可能缩短函数长度,直到你做不到为止。
6-最佳功能长度为 4 到 10 行。
7-文件应该平均 50-100 行,最多 500 行。
永远不要在评论中放 HTML 或者任何格式的文本。这使得注释和代码难以阅读。
从我数百次不同的 Github 代码检查中,我意识到几乎没有一个程序员遵循所有的干净代码原则。
在您的代码中尽可能多地尝试它们,看看我得到的症状是否也会出现在您的代码中。
这些原则绝不是提高编程技能的全面清单。这些只是干净代码系列中所有技术的一小部分。还有很多其他的技巧可以让你更加进步。
克里斯托夫·杰施克在 Unsplash 上的照片
接近尾声
我希望您现在有动力开始学习干净代码原则,并在很大程度上提高您的编程技能。
尝试应用八个干净代码原则,并随意分享你对它们的感受。
想象一下,如果您可以通过使用 Clean 代码中定义的一些令人惊讶的有趣技术来学习如何确保一切都遵循这些规则。
你可以通过参加视频课程或阅读我们在下面提供的参考书籍,发现如何具体实施这些原则。
进一步研究
将您的编程能力从中级过渡到专业。
medium.com](https://medium.com/cyber-explorer/growing-professional-programming-skills-577b7cc76187)
[1]罗伯特·C·马丁,干净代码视频系列(2016)
[2] Robert C.Martin,干净的架构:软件结构和设计的工匠指南
通过理解自连接,将您的 SQL 技能提升到一个新的水平
由 You X Ventures 在 Unsplash 上拍摄的照片
我写的前几篇博客对初学者来说非常棒(不用学习编码的数据概念或培养数据科学家的思维)。但是,我真的想推动自己为我的其他观众创造内容。所以今天,我们将进入更中级的数据分析领域。并讨论自我联接:它们是什么以及如何使用它们将您的分析带到下一个层次。
免责声明:这篇文章假设你已经理解了 SQL 中的连接是如何工作的。如果你还不熟悉这个概念,完全不用担心!把这篇文章留到以后吧,因为我认为当你将来掌握 SQL 时,它肯定会有用的。
什么是“自我”加入?
自连接实际上是字面上的意思——它是将数据库表连接到自身。您可以使用任何类型的连接来执行自连接(左连接、右连接、内连接等)。)—使它成为自连接的是您在两端使用同一个表。只要确保为您的特定场景和期望的结果选择了正确的联接类型。
什么时候应该使用自联接?
如果你在数据分析和数据科学领域工作或学习超过 5 分钟,你就会知道解决一个问题总有 27 种方法。当然,有些比其他的好,但有时差异几乎听不出来。
也就是说,很可能永远不会有一个确切的情况,你必须有一个自我连接,否则你的分析将会萎缩,无处可去。当然,如果你有的话,请在下面的评论中给我一个场景
但是,我至少在一些场景中使用了自连接来解决我的分析问题,无论是在工作中还是在个人分析中。下面是我自己对其中两个最好的(也就是我记得的和能想到的好例子)的看法。
场景#1:消息/响应
假设有一个名为 Chats 的数据库表,它保存了在线服装店发送或接收的所有聊天消息。
对于服装店老板来说,知道她通常需要多长时间来回复顾客的信息是非常有益的。
但是,来自她的客户的消息和发送给她的客户的消息在同一个数据源中。因此,我们可以使用自连接来查询数据,并向店主提供这种分析。我们需要一份聊天表来获取客户的初始信息,一份聊天表来获取所有者的回应。然后,我们可以对与这些事件相关联的日期进行一些日期计算,以计算出店主需要多长时间做出响应。
我将把这个假设的自连接查询写成如下形式:
SELECT
msg.MessageDateTime AS CustomerMessageDateTime,
resp.MessageDateTime AS ResponseDateTime,
DATEDIFF(day, msg.MessageDateTime, resp.MessageDateTime)
AS DaysToRespond
FROM
Chats msg
INNER JOIN resp ON msg.MsgId = resp.RespondingTo
注意:这个 SQL 查询是使用 Transact-SQL 编写的。使用任何适用于您的数据库的日期函数。
这个查询相对简单,因为 RespondingTo 列为我们提供了要返回到哪个原始消息的一对一映射。
场景#2:开/关
假设这次您看到了一个数据库表 AccountActivity,它保存了一个 yoga 订阅站点上可能发生的事件的日志。yoga 网站提供特定的“高级试用期”,顾客在首次加入时可以享受一段时间的会员折扣。在此表中,使用 Premium_Start 和 Premium ed 事件类型跟踪试验的开始和结束日期。
假设这家 yoga 订阅公司的一些业务员工在问 1。有多少人的保费试用期目前活跃,和 2。有多少曾经有高级试用期,但现在没有了。
同样,我们在同一个数据库表中获得了保费期开始和保费期结束的事件(以及其他帐户活动)。
分析请求 A:高级试用期中的帐户
要回答第一个问题,我们需要找到高级会员已经开始但尚未结束的活动。因此,我们需要将 AccountActivity 表连接到它本身,以查找高级开始和高级结束事件匹配。但是,这次我们不能使用内部连接。我们需要结束表中的空行…所以是左连接。
SELECT
t_start.UserId,
t_start.EventDateTime AS PremiumTrialStart,
DATEDIFF(day, t_start.EventDateTime, GETDATE()) AS DaysInTrial
FROM
AccountActivity t_start
LEFT JOIN AccountActivity t_end ON t_start.UserId = t_end.UserId
AND t_start.EventType = 'Premium_Start'
AND t_end.EventType = 'Premium_End'
WHERE
t_end.EventDateTime IS NULL
请注意我们是如何检查并确保我们加入的事件顺序正确的。我们希望高级试用从连接的左侧开始,高级试用在连接的右侧结束。我们还确保用户 Id 在两端匹配。我们不想参加两个不同客户的活动!
分析请求 B:曾经处于高级试用期的客户
关于第二个问题,我们想找到那些甜 premium 试用已经结束的客户。我们将再次需要 self join AccountActivity,但这一次我们可以将它切换得更严格一些。我们需要左右两边的匹配,因为在这个人群中,试验已经结束。所以,这次我们可以选择一个内联接。
SELECT
t_start.UserId,
t_start.EventDateTime AS PremiumTrialStart,
DATEDIFF(day, t_start.EventDateTime, t_end.EventDateTime)
AS DaysInTrial
FROM
AccountActivity t_start
INNER JOIN AccountActivity t_end ON t_start.UserId = t_end.UserId
AND t_start.EventType = 'Premium_Start'
AND t_end.EventType = 'Premium_End'
看,自我结合很有趣。如果在同一个数据库表中有相互关联的事件,它们会非常有用。感谢您的阅读,并祝您查询愉快。🙂
原载于 2020 年 8 月 13 日https://data dreamer . io。
我第一次数据科学实习的收获
我在实习期间学到的一些随机的小事情(附:这些不仅仅是技术上的事情)
图片来自作者
目前,我是 NYU 数据科学中心的数据科学硕士学生。我完成了我在数据科学领域的第一次实习,我很乐意告诉你这一切。
我为一家上下文相关的人工智能公司工作,在那里我们检测来自各种平台的有害行为。
天啊。我玩得开心吗?答案是— 地狱是的!
需要注意的一点是,学术数据科学与行业数据科学有何不同。但是,这种转变让它如此令人兴奋。
我在第一次数据科学实习期间学到了一些随机的事情—
技术技能(从行业角度来看)——我希望我事先就学会了
- 编写 生产级 代码的能力:即使你有丰富的 ML 知识,你也需要知道如何编写生产级代码。这在生产方面节省了大量时间。
- 了解主要的 Git 函数是如何工作的:你工作的公司很有可能把他们的代码放在 Github 上。你至少需要了解 Github 的基础知识:推送、拉取、合并、检出以及所有与版本控制相关的东西。
- 数据清理 :花时间清理你的数据。如果您有 1000 个已清理数据样本和 2000 个未清理数据样本;您的模型在清理数据时可能会表现得更好。因此,我再怎么强调这一点也不为过——学习如何保持您的数据整洁。如果可能的话,编写可重用的代码(这样你不会浪费太多时间)
- 不平衡 数据集:学习如何处理不平衡数据集!在现实世界中,更多的时候,这就是你将要面对的。
我一路走来学到的软技能:
- 有效沟通 :一切。你做了什么,你打算做什么?为什么?怎么会?一切。即使你第一次失败了。交流。
- 学习如何 呈现和解释结果 :作为一名数据科学家,你需要有能力向你的客户解释你的模型在做什么,为什么会给出这样的结果?
主要要点:
- 数据科学牛逼!我很高兴我选择了我热爱的职业道路。
- 找一个你热爱的 领域 。我不能强调它有多重要。我的意思是想想一个公司做的工作。不喜欢,过一段时间就烦了。
- 学你所能学的,向你所能学的人学习 。例如:我公司的首席执行官非常重视团队合作,这很有意义。没有团队,真的能经营一家公司吗?同样,不要固执于自己解决问题。交谈,交流, 交换观点 然后建立一些东西。
TL;博士—
- 有效编码
- 适当沟通
- 热爱数据科学,它也会爱你;)
将机器学习白皮书投入生产
需要考虑的四件事。
图片来自维基百科
当我阅读白皮书时,我通常是带着一个目的去做的,也就是说,手边有一个潜在的挑战,通常是一个很大的挑战。通常,它们真的符合要求。有时,他们甚至会在 Github 上发布源代码。那更好。
作者图片
这是一个简短的故事,讲述了在麻省理工学院从白皮书到生产的一个名为快速深度的项目中吸取的经验教训——在无人机上主动运行,为自主提供感知。
注意——我绝不是在批评快速深度报道、人物或作品。我和他们的交流很有成效。本白皮书讲述了从有趣的白皮书/概念工作证明到“生产”的过程。
能帮上忙的四件事:
尼古拉斯·托马斯在 Unsplash 上的照片
- 从部署的角度选择你的机器学习(ML)语言
- 找到一个运行时推理引擎
- 使用集中的训练数据调整您的模型
- 根据一致的摄像机参数校准您的训练数据。
着眼于部署选择你的机器学习语言
有趣的机器学习模型的研究和开发通常是我们感兴趣的白皮书的重点。研究人员倾向于喜欢 PyTorch。与 Keras/Tensorflow 相比,它提供了额外的灵活性,例如在动态图形中。好吧。然而,Tensorflow 似乎在总体使用上占主导地位,尤其是在运行时性能方面。
实际上有两种方法可以在生产中运行您的模型:
- 在类似于开发环境的环境中,例如 Python、PyTorch、CUDA 或
- 使用针对您的平台和性能优化的推理引擎。
如果你的交付允许 CUDA,你有更多的选择。然而,我倾向于参与上面的第二个项目——嵌入式 Linux 和智能手机项目。例如,在 2010 年 4 月发布的 1.0 版本框架移动神经网络(来自阿里巴巴),他们专注于后端,如 ARM CPU、OpenCL、OpenGL、Metal 和 Vulkan。并且针对 Adreno 和 Mali 系列的 GPU 进行了深度调优。正合我的胃口。
此外,从语言角度来看,“MNN 目前支持 Tensorflow、Tensorflow Lite、Caffe 和 ONNX(py torch/MXNet);后者通过算子融合、算子替换和布局调整来优化图形那就是,ONNX 当然看起来是二等公民。更进一步,它们支持 86 个 Tensorflow 操作,仅支持 34 个 Caffe 操作。
比赛可能不会总是跑得最快,但这是一个非常好的赌注。如有可能,使用 Tensorflow 进行部署。
找到一个有效的部署推理引擎
在之前的一篇文章中,我已经深入地写过这个。总的来说,有许多选择,完成这些选择是漫长而痛苦的。我发现了一个名为的移动人工智能计算引擎 (MACE),它是第一个在我的环境中运行良好的引擎。
您的里程可能会有所不同。为了获得最佳性能,我还想进一步探索 MNN(如上所述)和 tvm.ai 。
使用集中的训练数据调整您的模型
研究论文需要表明他们已经超越了以前的工作。他们的方法是使用基准数据集。在深度估计的情况下,正常的基准是 NYU 深度数据集 V2 。这个数据集来自 2012 年,包含大约 50 多张用 Kinect 摄像头获得的训练图像(RGB-D,D 代表深度)。(一个类似的汽车感知数据集被称为 KITTI,也来自这个时间段。)
(图片来源 NYU Depthv2 训练数据)
这是一个来自 NYU 深度 V2 数据集的样本。即纽约公寓和办公室的内部。
Jason Sung 和 Amy Elting 在 Unsplash 上的照片
相比之下,我们的重点是更多的砂砾,工业设置。
请注意更大的深度和“不同”类型的场景组成。
简而言之,根据 NYU 数据训练的模型在两个方面让我们失望:
- 深度有限。短距离可以避开物体,但更长的距离对于绘制环境以进行路径规划很有价值。
- 在我们的特定环境中,准确性很差。
下一步—查找新数据集
四处搜索,我们发现了二极管,一个类似的数据集,但两者都有更大的数据范围,高达 350 米,以及室内和室外场景。这个好用多了。
但是……(作弊部分……)
在高度相似的图像上训练高度特定的场景仍然是值得的。好吧,你可以说“作弊”,我会继续优化我们的结果,因为我们努力推广。简而言之,我们将从一个高度特定的环境中捕捉大约 5000 张图像,并在此基础上训练我们的模型。
这些最终的图像是用一个实感传感器捕捉的。这比 Kinect 更精确,但仍然受到 10 米(或更小)深度范围的限制。)
简而言之,行之有效的训练方案是:
- 基本模型,利用已经训练好的 Mobilenet
- 继续使用 NYU 深度数据集 V2 进行训练
- 继续用二极管训练
- 利用通过 RealSense 传感器获得的集中训练数据完成训练。
这在期望的域内很好地工作。
然后,校准您的训练数据
你可能已经注意到,到目前为止,我们大概使用了几种不同的相机:(无论 Mobilenet 使用什么);Kinect 二极管;实感;别忘了无人机上的最后一个摄像头。摄像机具有不同的校准参数。
图片来自维基百科
参考针孔摄像机型号。这是高中数学,我就不拖累你了。但是对我们来说两个关键参数是焦距和主点。
焦距在上图中显示为 f。主点没有显示,但表示图像中心在图像平面上的位置,对于相机来说,这通常是关闭的。
你说,那又怎么样。事实证明,你真的不应该在同一个训练数据集中混合和匹配来自不同参数相机的图像。
好消息是相机之间的转换很容易。
下面是一些帮助转换的代码。使用的摄像机校准参数来自 ROS 框架。一般来说,通过的路径是:
- 预处理。一些传感器并不在每个点都提供深度图像。对于这些,图像必须被内涂,以用估计值填充这些点。此外,二极管传感器提供需要平滑的图像,以覆盖一些不适当的高频噪声。
- 将图像从源摄像机转换或“注册”到目标摄像机。
- 深度图像也是如此。顺便说一下,有一个 ROS 节点可以做到这一点,但这不是必需的。
- 后期处理。如果 ROS 节点用于深度配准,则目前仅在绘制中。
下面是我为上面的#2 编写的 Python 代码:
'''
Convert an image between two different sensors. Two cases:
- source completely fills (or more) the destination
- source fills less than full
'''
def registerImage(npImg,sourceSensorDef,destSensorDef):
npImg = npImg.astype(np.float32)
# Principal point adjustment - source
npImg = principalPointAdjustment(npImg,sourceSensorDef) fxS = float(sourceSensorDef.fx)
fyS = float(sourceSensorDef.fy)
widthS = float(sourceSensorDef.width)
heightS = float(sourceSensorDef.height) fxD = float(destSensorDef.fx)
fyD = float(destSensorDef.fy)
widthD = float(destSensorDef.width)
heightD = float(destSensorDef.height)
WinterS = fxS * widthD /fxD
HinterS = fxS * heightD /fyD
WinterS = int(round(WinterS))
HinterS = int(round(HinterS))
WinterD = fxD * widthS /fxS
HinterD = fxD * heightS /fyS
WinterD = int(round(WinterD))
HinterD = int(round(HinterD)) # Assumption - both Width and Height will behave similarly, i.e., crops or add boundary
# if not, we need to handle width and height separately
resizeInterp = cv2.INTER_NEAREST
if WinterD<widthD: # need border on destination
# From ROS 'definition' - make left=right, top=bottom
bdrLeft = (destSensorDef.width-WinterD) // 2
bdrTop = (destSensorDef.height-HinterD) // 2
# but also must adjust width
WinterD = destSensorDef.width - (2 * bdrLeft)
HinterD = destSensorDef.height - (2 * bdrTop) dim = (WinterD,HinterD)
npImg = cv2.resize( npImg, dim, interpolation = resizeInterp ) # resize - use default interpolation - INTER_LINEAR
bdrRight = bdrLeft
bdrBottom = bdrTop
npImg = cv2.copyMakeBorder( npImg,
top=bdrTop,
bottom=bdrBottom,
left=bdrLeft,
right=bdrRight,
borderType=cv2.BORDER_CONSTANT,
value=(float("NAN"), float("NAN"), float("NAN"))
)
elif WinterD>widthD: # crop out source
bdrLeft = (sourceSensorDef.width-WinterS) // 2
bdrTop = (sourceSensorDef.height-HinterS) // 2
WinterS = sourceSensorDef.width - (2 * bdrLeft)
HinterS = sourceSensorDef.height - (2 * bdrTop)
npImg = npImg[ bdrTop:bdrTop+HinterS, bdrLeft:bdrLeft+WinterS ]
dim = (destSensorDef.width,destSensorDef.height)
npImg = cv2.resize( npImg, dim, interpolation = resizeInterp ) # resize - use default interpolation - INTER_LINEAR# Principal point adjustment - destination
npImg = principalPointAdjustment(npImg,destSensorDef)return npImg
总结
和往常一样,一个好的方法是迭代地进行,深入探索技术上未知/未证实的领域。上面概述的四件事将帮助你加速这个过程。
正如托马斯·爱迪生所说,“天才是百分之一的灵感,百分之九十九的汗水(T2)或者,用我的话来说,一个好主意是好的,一个概念的证明是伟大的,在现实世界中工作需要很多努力。
利用航班价格的下跌
比较路由算法以找到最方便的策略
来源:像素
假设你手里有很多空闲时间,你想飞到很多城市,但是你不确定用哪种策略来计划你的旅行。你应该在那天买最便宜的票还是等几天找到最低价?如果你这样做,你能完成你的旅行吗?
我将探索这些想法,并从头开始编写算法,以展示哪些策略最适合我们的梦想之旅。
先做最重要的事情;
- 我们想参观每个城市,
- 我们想把成本降到最低,
- 我们有时间限制,
- 我们总是在第一天从选定的城市开始旅程,
- 我们可以回到以前去过的城市,以达到最低的总成本。
数据是什么样的?
图 1:数据的初始视图
该数据包括所有可能日期的所有可能的航班组合。此处的总天数可以更改,可以添加新的城市,但用于此问题的数据集包括 6 个城市和 40 天(最多)。
有哪些策略?
首先,有每天选择最便宜航班的标准策略。如果我们在慕尼黑,最便宜的航班是去斯图加特,我们会选择去斯图加特。
标准策略
但是如果我们在慕尼黑,最便宜的航班是去斯图加特的,但是明天更便宜呢?这被称为价格下降,它存在于现实生活中的票价。
价格下跌策略
为什么会出现价格跳水?因为航空公司需要在确保每个座位都坐满和赚取足够的钱来支付运营成本之间找到合适的平衡。
出于这个原因,机票价格会根据与航班相关的许多不同因素,如商务旅行和实时预订,非常有规律地上下浮动。价格下跌策略通过比较当天第二天的价格来发现价格下跌。
价格下跌策略
价格跳水策略是否优于正常策略?为此,我们需要创建一个模拟,将一个随机项添加到原始数据库中。这样,该算法可以运行 1000 次,以找到总成本的列表,并且可以应用 T 检验来查看策略之间是否存在差异。
标准和价格下跌策略的分布
T 检验表明,两种策略之间存在显著差异,因此价格下跌策略更好。但是现在问题解决了吗?不幸的是没有,因为价格下跌策略跳过了很多天,需要很多天来总结所有城市。
修改价格下降策略
来源: Pexels
t 检验结果显示价格下降策略比标准策略有显著的改进。但是有一个条件:价格下跌策略在大多数时候都不会结束。这意味着它不能在给定的时间内到达每个城市。为了解决这个问题,当只剩下一个城市的时候,我会去最后一个城市。因为大部分时间这条路线都错过了那一个要完成的城市。
修改后的价格下跌策略
现在让我们看看在给定的 6 个城市中,策略失败的频率。让我们看看改进的价格下降策略是否取得了更好的成功。
基于给定天数的策略完成率
在给定 25 天去所有 6 个城市旅行的情况下,标准策略在 4 %的时间里失败,价格下降策略在 39 %的时间里失败,而改进的价格下降策略在 5 %的时间里失败。
改进的价格下跌策略(Price-Dip-All)具有非常高的完成率,但是 t 统计显示它具有相似的成本,这意味着与正常的价格下跌策略相比,它在价格方面没有显示出显著的改进。
结论
在这篇文章中,我们讨论了一些关于如何计划你的梦想之旅的想法。事实证明,每天购买最便宜机票的标准策略会让你游览每一个城市,但费用很高。
价格下跌策略的出现大大降低了总成本,但它并没有在给定的时间内完成每个城市。对于 6 个给定的城市和 20 天,该算法有 39%的时间无法访问所有城市。价格下跌策略被改变,并修改为访问最后剩下的城市时,有一个城市离开。改进后的策略具有前两种策略的优点,成本低,完成率高。
我希望这篇文章能给你一些关于为你的数据集实现你自己的算法的想法!有什么问题吗?在 Linkedin 上找到我,查看代码。
将人工智能模型从 Jupyter 笔记本带入真实的医院
将人工智能产品化和开发在医疗实践中实用的解决方案的主要挑战
图片来自 Unsplash
从放射学到病人护理,人工智能在医疗保健的许多领域都显示出惊人的潜力。AI 在放射学中的应用包括从胸部 X 射线中检测结核病,从 CT 扫描中检测新冠肺炎和颅内出血,从乳房 X 线照片中检测癌症,从 MRI 中检测脑肿瘤,从 PET 扫描中预测阿尔茨海默氏症的进展,等等。在 DeepTek,我们开发了仅从胸部 x 光就可以诊断 30 多种疾病的模型。除了放射学,人工智能还被应用于病理学,分析电子健康记录,疫情反应的接触追踪,预测再入院和死亡率,等等。强大的研究成果和活跃在这一领域的大量公司证明了人工智能从根本上改变医疗保健的承诺。
尽管如此,这一承诺在很大程度上仍未实现。许多令人兴奋的机器学习技术在基准数据集上表现出了显著的效果,但在学术论文和代码库中却没有使用。人工智能医疗创业公司的估值正在飙升,但他们没有收入,其中只有少数几家公司看到了任何形式的产品化人工智能和商业采用。
作为 DeepTek 的首席数据科学家 DeepTek 是少数几家成功实现其人工智能解决方案商业应用的公司之一——我想分享一下在开发在实践中实际工作的机器学习模型时所面临的关键挑战。以下是它们,没有特定的顺序。
缺乏足够的数据
是的,我们都听过这句话,不是吗?数据科学家总是抱怨没有足够的数据,过了一段时间后,团队的其他成员对这种抱怨充耳不闻。这是一个难以忽视的事实,但是让我们面对这个事实:根本没有办法绕过它。如果你没有数据,你就什么都没有。机器学习项目以数据开始,以数据结束——所有的创新都发生在两者之间。
神经网络渴望数据,它们不仅需要数据量,还需要输入的数据的多样性。成吨的医疗数据存在,但严重支离破碎。它存在于不同医院、诊所、个人电脑、USB 磁盘驱动器、电子邮件的小仓库中,其中很大一部分甚至没有数字化。即使医院允许你访问他们的数据,你也会发现跟踪、编辑和组织这些数据非常困难。HIPAA 和 GDPR 等数据隐私法规虽然本身非常重要,但却让事情变得更加困难。
嘈杂的注释
监督机器学习需要数据样本和标签。该算法首先在匹配样本-标签对上进行训练,从数据中提取模式,并将它们提取到数学模型中。这个模型后来被用来预测任何看不见的样本的标签。一个困难是这些标签经常是嘈杂的。
考虑放射科医生针对给定的病理将 X 射线图像标注为阳性或阴性的情况。作为数据科学家,我们愿意相信这种标签是清晰、确定和明确的。现实有些不同。正如许多研究表明的[ 1 ][ 2 ],在评估 kappa 值范围为 0.3 至 0.8 的研究时,放射科医师之间存在高度的评分者间差异。因此,如果使用放射科医师的注释作为基础事实来构建 AI 模型,它们将从标签本身可能不准确的不确定基础开始。当注释不是来自一个放射科医生,而是来自一个由多个放射科医生组成的团队时,这个问题变得有些复杂——在处理大型数据集时可能就是这种情况。
开源研究数据集(NIH、MIMIC、Padchest 等。)带有使用 NLP 算法从报告中自动提取的标签。NLP 提取过程可能会在标签中引入错误,但是在使用它们时还有另一个微妙的问题。当人类放射科医师评估图像并撰写报告时,放射科医师可以访问患者的临床信息,并且他/她的诊断会考虑该信息。然而,这种额外的信息对于 AI 训练来说是不可用的。在缺乏这些关键信息的情况下,人工智能可能无法学习样本和标签之间的正确对应关系。
培训分布与实际不符
哦,这种事经常发生!考虑以下情况。我们从医院收集了大量的 x 光图像。我们的放射科医生会针对给定的病理(比如结核病)对这些数据进行注释。在这个数据集中,结核病的患病率为 25%。四分之一的样本被标记为结核。我们使用这个数据集训练我们的结核病模型。作为一个新项目的一部分,我们在一个从事结核病人群筛查的医疗保健中心部署了这一模型。在这个人群筛查项目中,结核病的患病率是 5%。该模型的性能如何?
在 DeepTek,这些挑战是我们日常生活的一部分。要了解我们如何克服这些困难,联系我们,我们将很乐意讨论更多。
不太好。该模型针对特定的流行情况进行了训练和评估。它预计在测试阶段会有同样的流行率。当然,有很多方法可以解决这个问题,但是也有更多的问题。医院的 X 射线设备可能与医疗保健中心的不同。患者位置可能不同。医院图像可能会显示导管和胸导联。人群筛查图像可能包括异物,如硬币、别针、珠宝和夹子,因为这些可能是在人们穿着衣服的情况下拍摄的。由于这些因素,模型训练所依据的数据可能与其预期的数据有很大差异。
分布漂移
这与上述问题有关,但需要一个单独的部分。医疗保健行业的流程和工作流处于不断变化的状态。医院会变的。医生会变的。年轻一代的医生和医疗从业者并不羞于使用技术。病人会变的。所有这些的净效果是数据分布一直在变化。一个模型,一旦被开发和部署,永远不会顺利地工作。事实上,在医院中采用人工智能可能会导致医院工作流程本身的根本变化,从而导致数据分布的变化。
分布漂移(也称为概念漂移或数据集漂移)发生在数据分布开始随时间变化时。为了在实践中成功部署人工智能解决方案,他们需要配备自动识别漂移发生的技术,并重新训练和更新模型以纳入这种漂移。
学习不相关的混杂因素而不是相关特征
机器学习算法被优化以在给定数据集上实现最佳性能。尽管我们希望模型在训练中学习正确的特性,但情况可能并不总是这样。众所周知,模型会偷偷利用图像中可能与预测相关也可能不相关的未知特征。例如,如果数据集中的阳性图像主要来自一家医院,而阴性图像来自另一家医院,则模型可以学习区分图像的来源,而不是目标病理;因此,它可能会拾取图像中的对比度差异、扫描主要区域之外的一些文本标记、扫描周围的黑色边界区域或其他一些不相关的特征(也称为混杂因素),而不是学习根据指示病理的视觉症状来区分类别。如果这个模型也带有相同的混淆特征,那么它甚至可以在一个基准集上表现出优异的性能。
一个学习了不相关特征的人工智能模型的例子
对人工智能解决方案在实践中的应用理解不足
在许多组织中,无论是研究机构还是行业机构,技术开发人员都与医疗从业者保持一定的距离。由于这种差距,他们开发的解决方案解决了一个与需要解决的问题有质的不同的问题,以使解决方案对医疗人员实用。确定合适的利益相关者,通过对话引出他们面临的问题,将这些转化为一组明确的要求,客观地制定这些要求,然后设计满足这些要求的解决方案,当你开始计算这个漫长过程中涉及的人数时,这并不是一件容易的事情。
人工智能可以彻底改变医疗保健。通过消除流程中的瓶颈,自动化日常任务,提高诊断准确性,提高人类生产力,并最终降低成本,人工智能可以成为让所有人都能获得医疗保健的游戏规则改变者。为了实现这一潜力,我们需要承认上述挑战,给予它们应有的尊重,并找到缓解它们的方法。在 DeepTek,这些挑战是我们日常生活的一部分。要了解我们如何克服它们,请联系我们,我们将很乐意讨论更多。
如果你喜欢这篇文章,可以在 中型 上查看我的其他作品,在LinkedIn或Twitter,查看我的 个人网页 ,或发邮件给我viraj@berkeley.edu
与有商业头脑的高管谈论数据科学话题
向非技术受众有效传达技术数据科学工作的解释&减少误解
我从经理那里听说过一些数据科学家的故事,他们在技术能力方面非常出色,但缺乏一些基本的业务沟通技能。我还听到数据科学家抱怨说,高层管理人员不理解一些技术术语之间的区别,会在不理解其含义的情况下抛出一些术语,如“大数据”。
这篇文章的目的是帮助双方!数据科学家们,你可以阅读这篇文章,并获得用非技术术语解释行话的帮助。商业领袖,你可以深入了解当前数据术语的真正含义,也许还能更好地理解数据科学家的困境。
解释术语
“人工智能!大数据!深度学习!我们需要在我们的组织中利用所有这些…尽快。”
从 Seema Singh 开始走向数据科学
AI 的定义
我们可以将人工智能定义为“能够感知、推理、行动和适应的程序。”人工智能模仿人类表现出的认知功能,如推理和学习。
机器学习的定义
机器学习是一种特定类型的人工智能,它使用算法来学习数据和输出预测中的模式。机器学习需要相对较大的数据集,数据科学家通常会将数据分为训练集(用于构建模型)和测试集(用于测试模型性能和泛化能力)。
深度学习的定义
深度学习是一种复杂类型的神经网络(仅供参考:神经网络是机器学习的一个子集)。有些人会互换使用神经网络和深度学习这两个术语,但真正的深度学习是当神经网络至少有两个隐藏层时。如果你不知道隐藏层是什么,没关系,你需要知道的是深度学习算法比小型神经网络更复杂(因此计算成本更高)。
大数据是由什么构成的?
从 iauro onTwitter
大数据是一个巨大的时髦词。但是,在您的组织中拥有大量数据和真正拥有大数据之间有什么区别呢?上图概述了使数据被视为“大”的 4 个关键描述符
当您处理大数据时,规模通常以 TB 为单位。大数据是以多种格式出现的数据,如图像、文本、数字等。此外,如果您的公司也在讨论分析流数据(即持续生成的数据),那么您可能正在处理大数据。
消除困惑
“我们公司使用的是尖端的机器学习技术。”
机器学习与数据分析或统计
来自丹·舍万在 wordstream.com的
数据分析和机器学习之间的一个巨大差异是它们寻求回答的问题。
在数据分析中,你想知道类似于我们公司在这个时间点的销售额发生了什么变化?为什么会发生这种事?在机器学习中,你想知道基于过去发生的事情,我们可以预期未来我们的销售会发生什么?
上图详细描述了一些可以通过机器学习解决的商业任务或问题。对于这些任务中的每一项,您都要创建一个模型,用数据训练该模型,然后测试其预测准确性(或另一个度量)。另一方面,数据分析只专注于分析趋势,然后寻找解释。
深度学习与其他机器学习算法
这些图形突出了深度学习和其他机器学习技术之间的两个重要区别(在我看来)。
从杰森·布朗利到machinelearningmastery.com
第一张图解释了深度学习的好处之一-除了执行分类任务之外,它还完成了特征提取的过程(即从初始数据集创建特征)。这意味着数据科学家可以将原始数据输入深度学习算法,例如图像中的像素值,这是他们无法用其他机器学习方法完成的。
第二张图说明了深度学习如何在大型数据集上表现得更好。根据您拥有的数据类型和数量,一种方法比另一种方法更适合您的项目。(计算资源也是一个重要的考虑因素——用大量数据训练算法会花费大量时间。)
最后,深度学习方法最常用于带有标签数据(即结果/分类已知的数据)的行业。机器学习方法通常用于对标记为或未标记的数据进行建模。
设定期望
“那你能在周末之前给我一个预测模型吗?”
*这在我们的数据仓库中没有
数据清理的工作量
来自吉尔出版社forbes.com
《福布斯》公布了 2016 年对约 80 名数据科学家的众筹调查数据。上面的饼状图描述了“你花最多时间做什么”这个问题的答案。
这项调查的一个重要收获是,数据科学家花费高达 80%的时间在数据收集和清理上(在上图中,收集数据和清理/组织数据的总和为 79%)。我曾与数据科学家交谈过,他们说高管们并不总是理解或考虑到简单地为项目准备数据所需的工作量。
精度与时间的权衡
这是我在个人项目中经常思考的问题,但它同样适用于专业项目。第一张图说明了一般的数据科学流程,但在算法投入生产或用于演示之前,建模步骤之后通常会有迭代。
在这个迭代中有一个内在的权衡:随着你在一个模型上花费更多的时间,它的准确性/性能会增加**,但**会以一个递减的速率增加(见:收益递减的定律和这个图中标有 C 的部分)。
如果管理层要求某个准确度级别,例如 95%,他们必须明白,如果数据科学家带着一个准确度为 93%的模型回来,那么与在建模过程开始时增加准确度相比,增加最后 2%的准确度将花费更长的时间。
最后一个想法
我对这里的数据科学家观众还有最后一个要求——清晰简洁地说明你要用你的模型/分析回答什么业务问题,以及项目将如何为公司增加价值。此外,只要有可能,计算你的项目的商业影响(最好用货币单位)。
我认为,如果你能获得技术数据科学技能、沟通技能、和用商业思维看待项目,你对任何公司都是非常有价值的!
感谢您的阅读!如果你觉得这篇文章有帮助,请在 LinkedIn或与你的团队分享。
如果您正在寻找更多关于数据科学主题的简单解释的文章,请查看我如何在我最受欢迎的文章中分解流行的机器学习模型的基础:
尽可能简单地解释 ML 模型是如何工作的
towardsdatascience.com](/machine-learning-models-explained-to-a-five-year-old-f2f540d9dcea)
从 Javascript: Flask 和 fetch API 与 Python 对话
使用 Python 处理动态 web 界面或可视化所需的数据。
一个样本网络— D. Ellis 2020
在数据科学领域,通常需要使用一系列工具,每种工具都与其工作相关。一个需要使用 web 界面可视化的角色,但是处理 Python 脚本,通常最好在 d3 或 THREE.js 中构建一个定制的可视化来显示它,然后根据需要获取数据。本文介绍了如何创建一个简单的 flask 应用程序,它可以使用 Fetch API 向 web 接口提供数据。
创建烧瓶应用程序
我们首先构建一个包含一个空的templates
文件夹和一个app.py
文件的存储库。
App.py
我们的app.py
文件包含创建 web 界面所需的数据。为此,我们使用 flask ( pip install flask
) python 库。为此,我们可以使用以下模板:
######## imports ##########
from flask import Flask, jsonify, request, render_template
app = Flask(__name__)#############################
# Additional code goes here #
###################################### run app #########
app.run(debug=True)
在这里,我们首先导入所需的功能、应用程序结构和运行命令来启动应用程序。
Index.html
定义了 flask 应用程序后,我们现在需要创建一个模板网页。这可以通过将文件index.html
放在模板目录中来完成。
<body>
<h1> Python Fetch Example</h1>
<p id='embed'>**{{embed}}**</p><p id='mylog'/>
<body>
因为我们使用它作为模板,所以我们可以对某些关键字使用 react 风格的替换语法。在这个例子中,下面代码片段中的{{embed}}
将被替换为embed_example
字符串。
[@app](http://twitter.com/app).route(**'/'**)
def home_page():
example_embed='This string is from python'
return render_template('index.html', embed=example_embed)
这定义了当到达 flask app 的主页时运行的代码,需要在 app.py
内的 imports
和 app.run()
行之间添加。****
运行应用程序
最后,我们可以运行应用程序,使用python app.py
并在 web 浏览器中导航到[https://127.0.0.1:5000/](https://127.0.0.1:5000/)
进行查看。
获取和发布—它们是如何工作的?
在传输数据时,我们依赖于 fetch API 中的 GET 和 POST 函数。这些术语不言自明:
- POST 是指将信息发送到一个位置,类似于寄信。
- GET 指的是数据的检索——你知道你有邮件,所以你去邮局领取(索取)。
测试功能
在app.py
中,我们可以为 GET 请求创建一个 URL。下面的代码定义了调用 URL 时的响应。
[@app](http://twitter.com/app).route('**/test**', methods=['GET', 'POST'])
def testfn(): # GET request
if request.method == 'GET':
message = {'greeting':'Hello from Flask!'}
return jsonify(message) # serialize and use JSON headers # POST request
if request.method == 'POST':
print(request.get_json()) # parse as JSON
return 'Sucesss', 200
在一个 GET 请求之后,我们定义一个包含一个greeting
元素的字典并序列化它。接下来,这将被发送回调用的 javascript 程序。
在将下面的代码添加到app.run()
命令之前并执行它之后,我们可以访问[https://127.0.0.1:5000/](https://127.0.0.1:5000/)test
——它应该会产生下面的结果:
{
"greeting": "Hello from Flask!"
}
从 Javascript 调用数据
现在我们已经设置了服务器端的东西,我们可以使用 fetch 命令从其中检索数据。为此,我们可以使用如下的fetch
承诺:
fetch(**'/test'**)
.then(function (response) {
return response.json();
}).then(function (text) {
console.log('GET response:');
console.log(text.greeting);
});
这里我们对/test
运行一个 GET 请求,它将返回的 JSON 字符串转换成一个对象,然后将greeting
元素打印到 web 控制台。通常,JavaScript 代码应该嵌套在 HTML 文档中的<script>
标记之间。
从服务器请求数据
现在我们有了一个工作示例,我们可以扩展它以包含实际数据。实际上,这可能涉及访问数据库、解密一些信息或过滤一个表。
出于本教程的目的,我们将创建一个数据数组,并从中索引元素:
######## Example data, in sets of 3 ############
data = list(range(1,300,3))
print (data)
设置寻呼呼叫
在我们的 Flask 应用程序中,我们可以向 GET 请求添加可选参数——在本例中,是我们感兴趣的数组索引。这是通过页面 URL /getdata/<index_no>
中的附加页面扩展指定的。然后,该参数被传递到页面函数中,并在 return 命令中进行处理(data[int(index_no)]
)。
######## Data fetch ############
[@app](http://twitter.com/app).route('**/getdata/<index_no>**', methods=['GET','POST'])
def data_get(index_no):
if request.method == 'POST': # POST request
print(request.get_text()) # parse as text
return 'OK', 200
else: # GET request
return 't_in = %s ; result: %s ;'%(index_no, data[int(index_no)])
写入提取请求
fetch 请求保持不变,只是将 GET URL 改为包含我们感兴趣的数据元素的索引。这是在index.html
的 JS 脚本中完成的。
var index = 33;fetch(**`/getdata/${index}`**)
.then(function (response) {
return response.text();
}).then(function (text) {
console.log('GET response text:');
console.log(text);
});
这一次,我们不是返回一个对象,而是返回一个字符串并解析它。然后可以根据需要在代码中使用它——无论是更新图形还是显示消息。
摘要
我们探索了一种使用 python 提取数据并将其提供给 javascript 代码进行可视化的方法(替代方法包括 web/TCP 套接字和文件流)。我们能够创建一个服务器端 python 代码来预处理或解密数据,并且只向客户端提供所需的信息。
如果我们有不断更新的数据、大型(高资源)数据集或我们不能直接提供给客户端的敏感数据,这是非常有用的。
*本文中使用的附带示例代码可以在:*找到
使用 Fetch API 在 flask 和一个提供服务的网页之间进行通信
github.com](https://github.com/wolfiex/FlaskFetch)
通过 OpeNDAP APIs 和 Python 挖掘 NASA 的地球数据
走向地球数据工程
美国宇航局在 Unsplash 拍摄的照片
背景
NASA 地球数据对于地球科学家、水文学家以及对使用地球数据(例如,降水、温度等)感兴趣的任何人来说都是非常宝贵的资源。)用于教育、分析、可视化和建模等。这些数据可通过多个平台获得,包括美国宇航局戈达德地球科学(GES)数据和信息服务中心(DISC),以及美国宇航局地球科学数据系统(ESDS)计划等。然而,这些平台需要用户手动访问网站来下载所需的数据。很多时候,Python 程序员和不习惯地理格式的用户似乎无法访问数据格式(例如 netCFD、hdf 等)。
本文试图通过提供一个通过 OpeNDAP 访问这些数据的示例,来减少 python 用户访问 NASA 地球数据的障碍。我们将完全使用 python 来实现数据检索过程的自动化。因此,本指南也有利于地球数据工程和利用 NASA 的数据金矿开发数据管道。
问题陈述:2020 年卡拉奇洪水
我开发本指南的主要动机源于理解导致 2020 年 8 月下旬卡拉奇毁灭性洪水的降水事件的需要。美国宇航局地球数据包括大量数据集,其中包括基于卫星和历史降水事件的建模观测。本指南将说明如何在 python 中访问其中一个数据集,即 GPM IMERG 数据集,以提取卡拉奇及其所在地(2020 年 8 月下旬)的卫星降水数据。
先决条件
通过 python 访问 NASA 地球数据集的关键先决条件是:
1)创建一个 NASA 地球数据账户。它是免费和即时的。
- 2)选择要访问的适当数据集。这里提供了一些探索 NASA 数据集的指南。如前所述,在本文中,我们将从 GPM IMERG hourly product 中访问和检索数据。
3)安装 pydap python 库。虽然有其他基于 python 的方法允许通过 OpeNDAP api 连接到 NASA 数据集,但 pydap 使用起来简单方便,应该可以与任何 python 3.6+版本一起工作。然而,我们建议通过以下命令从 github 提交安装:
pip install git+https://github.com/pydap/pydap.git@fc0dd0e6f180e455dbb68a06a85f84b1eca6754f
连接到 NASA 数据集
一旦创建了地球数据登录并安装了 pydap 库,我们就可以通过 OpenDAP 建立与 NASA 数据集的连接,给定 opendap url。此处提供了一些可用的 OpenDAP 数据集的档案。我们有兴趣观察 2020 年 8 月下旬卡拉奇的次日降水模式。因此, GPM 半小时延迟降水是一个合适的数据集。以下代码块使 python 用户能够通过 pydap 连接到数据集(请提供 NASA 地球数据用户名和密码):
请求数据
一旦与 GPM 数据集建立了连接(该连接在上面的代码中表示为“dataset”),我们就可以提取与我们感兴趣的空间区域相关的数据(在本例中为卡拉奇及其所在地),以及我们感兴趣的时间(在本例中为 2020 年 8 月 25 日至 28 日)。这里需要注意的是,GPM 数据集变量存储在三维数组中,时间作为第一个索引,纬度作为第二个索引,经度作为第三个索引(有关数据格式的详细信息,请参见这里的)。因此,为了从上述代码中的“数据集”请求一个(变量的)块,我们需要输入以下代码行:
requested_data = dataset[var_name][start_time_index: end_time_index, start_lat_index: end_lat_index, start_lon_index: end_lon_index]
如上所述,精确的数据请求需要 I)请求的变量的名称,ii)时间索引的范围,以及 iii)空间索引的范围(纬度和经度界限)。虽然理论上可以请求整个数据集,但是 GPM 数据集是全局的和海量的(至少万亿字节)。因此,请求整个数据集是不可取的。无论如何,这样的请求会在 NASA 的服务器上超时,不会通过。
确定空间范围
这幅图中我们感兴趣的空间区域是卡拉奇及其所在地。因此,我们需要在跨越巴基斯坦卡拉奇的数据请求中提供纬度和经度索引。下面的代码块说明了如何确定这些索引的范围。变量“lat_range”和“long_range”应由用户定义,用于指定所请求数据的空间范围。剩下的代码查找对应于这个范围的 GPM 数据数组索引。
确定时间指数
确定对应于 2020 年 8 月下旬(8 月 25-28 日)的 GPM 数据集时间指数,需要了解数据集本身的开始时间。根据 GPM 数据集的元数据,该数据的开始时间为 2000 年 6 月 1 日 00:00:00。此外,我们使用的 GPM 数据集是半小时一次的。因此,对应于 2020 年 8 月 25 日 00:00:00 的时间索引可以通过找到 20 00 年 6 月 1 日和 2020 年 8 月 25 日之间的 30 分钟间隔的数量来确定。下面的代码块在 GPM 数据集中找到开始时间索引,对应于 2020 年 8 月 25 日,按照上述逻辑。我们还通过核对与索引值相关联的时间变量来检查逻辑的有效性,以确保它确实是 2020 年 8 月 25 日。
获取请求的数据
现在我们已经确定了 GPM 数据的起始时间索引和感兴趣的空间索引,我们可以使用 pydap 请求 GPM 降水。请求 GPM 降水数据的代码如下。请注意,降水变量名为“precipcal ”,我们要求从 2020 年 8 月 25 日开始的 4 天(巴基斯坦卡拉奇)的数据。
将检索到的数据转换为数据帧
通过 pydap 从 NASA 接收的数据被保存为一个“py DAP 模型”对象。这个对象的四个属性是特别感兴趣的,即‘time’,‘lat’,‘lon’和‘precipcal’(请求的变量名);“time”、“lat”和“lon”是表示请求的数据的时间、纬度和经度维度的 numpy 数组,“precipal”(请求的变量)是一个 3D numpy 数组,具有与时间、纬度和经度维度相对应的半小时 GPM 降水量值。下面的代码片段演示了如何将这些数据转换成 pandas 数据帧。
快速查看 2020 年 8 月卡拉奇的降雨
一旦检索到的数据被转换成数据帧,我们就可以通过一个简单的时间序列来快速查看 2020 年 8 月卡拉奇的毁灭性事件。让我们通过的时间序列图(代码也在下面给出)来想象这些雨是如何在卡拉奇 Cantt 地区展开的。
卡拉奇坎特地区 2020 年 8 月的降雨结果如何(图片由作者提供)
最后的想法
本文展示了如何使用 pydap 库和 OpeNDAP api 在 python 中访问 NASA 地球数据集。这里提供的代码片段也可以用作从 NASA 的地球数据开发数据管道的基线,还可以从 NASA 的数据仓库中挖掘出宝贵的见解。
我希望本文的内容对地球数据科学家、工程师和任何对探索地球数据感兴趣的人有用。你可以通过 linkedin 或 twitter 与我联系,进行任何询问、讨论等。
目标编码和贝叶斯目标编码
数据科学竞赛中常用的分类编码技术
安妮·斯普拉特在 Unsplash 上的照片
分类变量的编码问题是特征工程中非常重要的一步。不幸的是,没有适用于所有情况的解决方案。人们发明了多种技术,我在这里介绍其中的一些、这里的和这里的。
在这篇文章中,我将讨论目标编码(又名平均编码)及其改进版本贝叶斯目标编码,以及其在采样贝叶斯编码器中的最新改进。
为什么要对类别进行编码?
给定无限量的干净数据,您将不需要对类别进行编码。您可以为每个类别训练一个模型。例如,对于泰坦尼克号问题,你可以为男性和女性训练不同的模型。如果你有几个分类变量,你必须为它们的每一个组合训练一个新的模型。
这种方法有明显的问题:
- 某些类别组合的数据可能很少。在这种情况下,模型的预测将不具有统计意义。
- 某些类别组合可能在训练集中找不到,但可能出现在看不见的数据中。
通常,这种方法通常会导致过度拟合,并且不用于高基数分类变量。然而,正如在[1]中所证明的,开发正则化技术并实现这种方法的良好推广是可能的。在那里,这项技术被用于模拟 DNA 序列。
基本编码方案
一般来说,分类变量的编码是用一个或多个数字变量替换分类变量的过程,以便得到的数据集可以用于期望数字变量的统计和机器学习算法中。许多编码技术,例如一键编码和顺序编码,都是在 20 世纪早期发展起来的,它们并没有失去它们的重要性。从 scikit-learn 查看一个很棒的用户指南。对于高基数分类变量,这两种技术变得不太有用。序数编码不能从分类变量中提取有用的信息。一键编码为高基数分类变量生成了太多的特征,并且往往产生较差的结果。我们将考虑下面两种对高基数分类变量非常有效的编码。
目标(平均)编码
这种类型的编码被称为目标编码或均值编码。查看 Coursera 课程“如何赢得数据科学竞赛:向顶尖高手学习”中对此类编码的精彩解释
经典论文[2]给出了这种方法的理论基础。这个想法非常简单:让我们使用目标统计对分类值进行编码。正如论文中所描述的:
实际上,这意味着我们计算每个类别的目标变量的平均值,并用目标平均值对该类别进行编码。这种技术适用于二元分类和回归。对于多类分类,应用类似的技术,其中我们用m-1
新变量编码分类变量,其中m
是类的数量。
值得注意的是,尽管作者声称使用目标统计对分类变量进行编码,但实际上只使用了均值。虽然它对于二元分类来说是一个充分的统计量,但对于回归来说却不是,因为它忽略了目标变量的类内变化。贝叶斯目标编码解决了这个问题。
由于目标泄漏,目标(平均)编码有过度拟合的趋势。有各种技术可以解决这个问题。例如,在留一编码器中,从目标统计中减去当前目标值。这减少了目标泄漏。另一种技术是向编码值添加高斯噪声。噪声的强度是模型的超参数。
另一个问题是,一些类别几乎没有训练示例,并且这些类别的目标平均值可能采用极值,因此用平均值编码这些值可能会降低模型性能。为了解决这个问题,该类别的目标平均值经常与目标变量的边际平均值相混合[2]:
对于有许多训练示例的类别,权重λ接近 1,对于稀有类别,权重λ接近 0。例如,它可以被参数化为:
系数λ可用经验贝叶斯模型解释。在这种情况下,我们首先拟合边际分布p(y)
,即我们基于整个数据集找到后验分布。然后,我们可以将这个后验分布用作模型p(y|c)
的先验分布,即给定分类变量值的目标变量的分布。
目标(平均值)编码的这些和其他变体在 python 包类别编码器【3】中实现。目标编码的不同变体似乎从分类变量中提取出略有不同的信息,因此在数据科学竞赛期间,多种技术经常被用于各种叠加方案中。
贝叶斯目标编码
贝叶斯目标编码的主要动机是在编码分类变量时,除了使用目标平均值之外,还使用类别内方差。它是在[4,5]中提出的(看似独立)。主要观点是我们应该计算后验分布的均值、方差和高阶矩。
在贝叶斯学习中,分布的参数本身被认为是随机变量。在看到任何数据之前,参数的分布称为先验分布。基于新数据更新该分布以成为后验分布。对看不见的数据的预测可以通过在参数空间上边缘化来得到。为了避免难以处理的积分,贝叶斯从业者经常使用共轭先验。它们的优点在于具有非常简单的更新规则,使得基于训练示例快速计算后验分布成为可能。更多解释请见下文[5]的摘录。
例如,考虑二进制分类问题。那么二元变量就可以用伯努利分布来描述,只有一个参数p
,就是它属于第一类的概率。第二类的概率是q = 1-p
。在贝叶斯统计中,参数p
本身是一个随机变量,共轭先验是贝塔分布:
后验分布参数的更新规则非常简单:
后验分布参数的解释是α-1 成功和β-1 失败。
[4,5]中的想法是计算每个类别的成功和失败次数,然后根据后验分布的矩生成特征:平均值:
方差:
偏斜度:
可能还有更高的时刻。
同样的技术也可以用于回归和多类分类模型。在[5]中,这种方法被称为共轭贝叶斯模型(CBM)。对于多类模型,共轭先验是狄利克雷分布,对于回归问题,它是正态-逆伽玛分布。
如果我们只使用后验分布的一阶矩:它的均值,CBM 就简化为目标(均值)编码。通过添加更高的矩,我们可以添加目标变量的类别内分布的细节,这可以提高模型性能,前提是相同的分布对于看不见的数据是真实的。这是这种方法的一个弱点,因为模型可能会在更高的时刻过度拟合,而不会在看不见的数据上推广。在这种情况下,常规目标编码比 CBM 产生更好的结果。
在[5]中,先验分布是通过在整个训练数据集上拟合贝叶斯模型而得到的。这对于解决稀有类别的问题非常重要。实际上,您希望控制目标变量的边际分布对后验分布的影响程度,因此通常必须缩小先验分布,以实现更好的模型性能。
[4]中给出了贝叶斯目标编码的一个很好的实现:
使用 Kaggle 笔记本探索和运行机器学习代码|使用 Avito 需求预测挑战赛的数据
www.kaggle.com](https://www.kaggle.com/mmotoki/avito-target-encoding)
它只涵盖了二元分类的情况。在fit()
期间,我们计算成功和失败的次数。在transform()
阶段,我们生成具有条件分布的均值和其他统计属性的特征,如下摘录所示:
一个通用的 CBM 算法可用于不同的 github 编码:
共轭贝叶斯模型编码代码。该库包含可能提交给 2019 年 ECML 的代码…
github.com](https://github.com/aslakey/CBM_Encoding)
我希望这种分类编码技术能被合并到分类编码器包[3]或另一个广泛使用的特征工程库中。此外,我希望看到更多的理论讨论,将贝叶斯目标编码技术放在一个更广泛的统计学习的背景下。
更新:采样贝叶斯编码器
最近发表的预印本 [6]建议对贝叶斯目标编码技术进行改进。不使用后验分布的矩作为新特征,而是建议对后验分布进行采样,并将采样值作为新特征。该思想基于这样的观察,即一般的目标编码,特别是贝叶斯目标编码,可以被表示为使用弱学习器来发现新特征的分层模型。弱学习者试图基于有限的数据子集学习目标变量的表示,在我们的例子中,只有一个变量。那么由弱学习者产生的预测可以被用作输入来训练更健壮的模型。这种技术用于集合模型,如随机森林和梯度增强树。从贝叶斯的角度来看,使用弱学习者来训练模型可以表示如下:
让我给你解一下这个等式。在我们的数据集中,我们有 M 个分类变量,这意味着我们为分类变量 m 的每个唯一值 v 训练 M 个弱学习器。在给定目标值的情况下,我们学习参数 θ 的后验分布 p_mv ,而不是取平均值。一般来说, θ 是一个矢量。类似于贝叶斯目标编码器,我们可以取几个一阶矩,或者通常将任何函数 f() 应用于后验分布的参数。注意,我们还没有得到参数的期望值!我们使用这些函数的输出作为输入(以及不需要编码的数值变量 ξ )来训练模型 y_θ ,然后只取后验分布的期望值。与贝叶斯目标编码器相比,这是采样贝叶斯编码器的主要贡献,在贝叶斯目标编码器中,在应用函数 **f()之前过早地获取期望。**这有助于减少目标泄漏和避免过度拟合。
为了计算期望值,我们可以从后验分布中生成一个样本。因为我们使用共轭先验,这很容易。一旦我们生成了一个样本,我们就可以像这样在上面的等式中估计期望值:
K 是样本大小,或者我们从后验分布生成的参数集的数量。这种方法类似于统计学中的多重插补方法。它对计算的要求也更高,尤其是对于更大的 K 。这篇论文的代码以及所有实验与其他方法的比较可以在 github 报告中找到。
结论
贝叶斯目标编码技术是对标准目标编码的改进,因为它试图从目标变量的类内分布中提取信息,而目标编码忽略了这一点。该方法在 Kaggle 竞赛中证明非常有用,并在 WeWork 上建立了一个模型,该模型处理具有高基数分类变量的数据[5]。采样贝叶斯编码器[6]提供了贝叶斯目标编码的新视角,并为分类特征编码领域的研究和工程提供了更多机会。
参考
[1]邓森,大卫&兴,传化。(2012).多元分类数据的非参数 Bayes 建模。美国统计协会杂志。104.1042–1051.2009.tm08439。
[2]丹尼尔·米西-巴雷卡。(2001).分类和预测问题中高基数分类属性的预处理方案…SIGKDD 探索。3.27–32.10.1145/507533.507538.
[3]麦金尼斯,威廉&肖,查普曼& S,安德烈&黄,韩宇。(2018).分类编码器:一个 scikit-learn-contrib 转换器包,用于对分类数据进行编码。开源软件杂志。3.501.10.21105/乔斯 00501
[4]马特·基托,贝塔目标编码,https://mattmotoki.github.io/beta-target-encoding.html
[5]斯莱基,奥斯汀&萨拉斯,丹尼尔&斯坎罗特,约尼。(2019).用共轭贝叶斯模型为 WeWork 线索评分引擎编码分类变量。
[6]迈克尔拉里奥诺夫(2020)。贝叶斯目标编码中的采样技术。 arXiv:2006.01317
多类分类的目标编码
category_encoders 的 TargetEncoder 有什么问题?
在 Unsplash 上由 Toa Heftiba 拍摄的照片
这篇文章是我的上一篇文章的延续,我的上一篇文章解释了目标编码实际上是如何工作的。文章通过理论和实例说明了二分类任务的编码方法,以及 类别编码器 库如何对多类目标给出不正确的结果。本文展示了当 *category_encoders 的 TargetEncoder 失败时,给出了编码多类目标、*背后的理论,并提供了正确的代码,以及一个示例。
TargetEncoder 什么时候失败?
看看这个数据。颜色是一个特征,目标是好的…目标。我们的目标是基于目标对颜色进行编码。
让我们在这上面做通常的目标编码。
import category_encoders as cece.TargetEncoder(smoothing=0).fit_transform(df.Color,df.Target)
嗯,这看起来不太对,是吗?所有颜色都被替换为 1。为什么?因为 TargetEncoder 采用每种颜色的所有目标值的平均值,而不是概率。
虽然 TargetEncoder 适用于二进制目标为 0 和 1 的情况,但它不适用于以下两种情况:
- 当目标是二进制,而不是 0/1 时。比如 1 和 2s。
- 当目标是多类时,如上例所示。
所以,怎么办!?
该理论
下面是 Daniele Micci-Barreca 的原始论文中介绍的针对多类目标的均值目标编码。
假设标签中有 n 个类。
理论上说,第一步是一次性编码你的标签。这给出了 n 个二进制列,每个列对应于目标的一个类。然而,只有 n-1 个二进制列是线性无关的。因此,这些列中的任何一列都可以删除。现在,使用每个二进制标签对每个分类特征使用通常的目标编码,一次一个。因此,对于一个分类特征,您得到 n-1 个目标编码特征。如果数据集中有 k 个分类要素,则总共会得到 k 倍(n-1)个要素。
我们用一个例子来理解。
一个例子
我们继续前面的数据。
第一步:一键编码标签。
enc=ce.OneHotEncoder().fit(df.Target.astype(str))
y_onehot=enc.transform(df.Target.astype(str))
y_onehot
请注意,Target_1 列表示目标中是否存在 0。如果目标中有 0,则为 1,否则为 0。类似地,Target_2 列表示目标中是否存在 1。
步骤 2: 使用每个独热编码目标对颜色进行编码。
class_names=y_onehot.columnsfor class_ in class_names: enc=ce.TargetEncoder(smoothing=0)
print(enc.fit_transform(X,y_onehot[class_]))
对于 0 类
对于 1 类
对于二班
**第三步:**如果除了颜色还有更多分类特征,对所有特征重复第一步和第二步。
完成了!
因此,数据集转换为:
注意,为了清楚起见,我对所有三个 Color_Target 列进行了编码。如果您知道 one-hot 编码,那么您知道可以删除其中一列而不会丢失任何信息。因此,这里我们可以安全地删除 Color_Target_3 列,而不会丢失任何信息。
完整的代码
你是来拿密码的,对吧!?
我在这里给出了一个函数,它将 pandas 数据帧的特征和 pandas 系列的目标标签作为输入。特征 df 可以具有数字和分类特征的混合。
def target_encode_multiclass(X,y): #X,y are pandas df and series y=y.astype(str) #convert to string to onehot encode
enc=ce.OneHotEncoder().fit(y)
y_onehot=enc.transform(y) class_names=y_onehot.columns #names of onehot encoded columns X_obj=X.select_dtypes('object') #separate categorical columns
X=X.select_dtypes(exclude='object') for class_ in class_names:
enc=ce.TargetEncoder()
enc.fit(X_obj,y_onehot[class_]) #convert all categorical
temp=enc.transform(X_obj) #columns for class_
temp.columns=[str(x)+'_'+str(class_) for x in temp.columns]
X=pd.concat([X,temp],axis=1) #add to original dataset
return X
结论
在这篇文章中,我指出了 category_encoder 的 TargetEncoder 的问题。我解释了关于目标编码的原始论文对多类标签的看法。我通过一个例子解释了这一点,并为您提供了一个可在应用程序中即插即用的工作模块代码。
在 LinkedIn 上和我联系!
在 GitHub 上看看我的一些很酷的项目!