TowardsDataScience-博客中文翻译-2016-2018-三百零三-

19 阅读1小时+

TowardsDataScience 博客中文翻译 2016~2018(三百零三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用 Python 通过 AWS 的反向图像搜索引擎 Rekognition 收集图像标签

原文:towardsdatascience.com/use-python-…

这篇博文讨论了如何将你的图片转化为描述图片内容的文本,这样你就可以在 Jupyter 笔记本上对图片的内容和主题进行分析。一个有用的例子是,如果你收到了数千条推文,你想知道图片媒体对参与度有没有影响。幸运的是,亚马逊、谷歌和微软的工程师没有编写自己的图像识别工具,而是完成了这项任务,并使他们的 API 可以访问。这里我们将使用 Rekognition,这是亚马逊基于深度学习的图像和视频分析工具。

本博客作为如何使用不同的 Rekognition 操作提取信息的示例,并不能代替阅读文档。我尽我所能提供链接,因为它们可能是有用的。

因此,为了收集图像的文本数据,我们将:

  1. 将图像存储在 AWS S3 桶中
  2. 使用 AWS Rekognition 反转图像搜索并返回每个图像的标签
  3. 将数据保存在长数据框和宽数据框中——您可能只需要一个数据框,但是我在代码中给出了将数据保存为两个数据框的方法。

亚马逊在这里描述了 Rekognition 是如何工作的。

aws.amazon.com/rekognition…

打开 Jupyter 笔记本并将数据存储为 pandas 数据框对象后,我们希望导入相关的库。我使用了来自 Twitter 的数据,那里的图像数据是 URL 形式的。

import boto
import boto3
conn = boto.connect_s3()
import requests

如果你在这里遇到了错误,安装 AWS CLI ,并确保你已经安装了 botoboto3

现在连接到我们的桶:

*# Uses the creds in ~/.aws/credentials*
s3 = boto3.resource('s3')
bucket_name_to_upload_image_to = '#########' *#insert the name of your bucket here.*

你如何创建一个桶?什么是水桶?点击此处。

你连接到你的桶了吗?我从用户 GISD 对以下 StackOverflow 问题的回答中了解到这个检查。

*# Do this as a quick and easy check to make sure your S3 access is OK*
**for** bucket **in** s3.buckets.all():
    **if** bucket.name == bucket_name_to_upload_image_to:
        print('Good to go. Found the bucket to upload the image into.')
        good_to_go = **True**

**if** **not** good_to_go:
    print('Not seeing your s3 bucket, might want to double check permissions in IAM')

第一步:将图像存储在 AWS S3 桶中

我们所有的图像都是以网址的形式,我们想把它们都上传到一个 S3 桶,而不必先把它们存储在我们的硬盘上。方法如下:

请记住,这还会创建一个 mapping_dict,这样,如果您的图像 URL 列表是从另一个数据框中获得的,您就能够将其与在以下步骤中创建的图像标签数据框合并。

第二步:使用 AWS Rekognition 反向搜索图像并返回每个图像的标签

首先,我们将探索 AWS API 的三个特性,巧合的是,它们对我的目的最有帮助:检测标签检测文本识别名人。Rekognition 还拥有许多其他功能,包括检测和分析人脸,跟踪人脸,以及检测儿童的不安全内容。

检测标签

response will be a dictionary with keys [‘OrientationCorrection’, ‘Labels’, ‘ResponseMetadata’]

[Output]
{'Labels': [{'Confidence': 99.28775787353516, 'Name': 'Human'},
  {'Confidence': 99.2877426147461, 'Name': 'People'},
  {'Confidence': 99.28775787353516, 'Name': 'Person'},
  {'Confidence': 91.67272186279297, 'Name': 'Audience'},
  {'Confidence': 91.67272186279297, 'Name': 'Crowd'},
  {'Confidence': 91.67272186279297, 'Name': 'Speech'},
  {'Confidence': 78.27274322509766, 'Name': 'Clothing'},
  {'Confidence': 78.27274322509766, 'Name': 'Coat'},
  {'Confidence': 78.27274322509766, 'Name': 'Overcoat'},
  {'Confidence': 78.27274322509766, 'Name': 'Suit'}],
 'OrientationCorrection': 'ROTATE_0',
 'ResponseMetadata': {'HTTPHeaders': {'connection': 'keep-alive',
   'content-length': '536',
   'content-type': 'application/x-amz-json-1.1',
   'date': 'Mon, 04 Dec 2017 03:13:26 GMT',
   'x-amzn-requestid': '18599e6b-d8a1-11e7-8234-c9f1716fbb2e'},
  'HTTPStatusCode': 200,
  'RequestId': '18599e6b-d8a1-11e7-8234-c9f1716fbb2e',
  'RetryAttempts': 0}}

对于下图:

检测文本

text_in_image will be a dictionary with keys [‘TextDetections’, ‘ResponseMetadata’]

注意这里的输出是一个字典的字典。既然这么长,这里就不完整收录了。以下是 text _ in _ image[' text detections ']的简短输出:

[Output]
[{'Confidence': 87.87747955322266,  'DetectedText': 'Protects',  'Geometry': {'BoundingBox': {'Height': 0.0289202518761158,    'Left': 0.8098856210708618,    'Top': 0.3966602385044098,    'Width': 0.05391734838485718},   'Polygon': [{'X': 0.8098856210708618, 'Y': 0.3966602385044098},    {'X': 0.863802969455719, 'Y': 0.3976689577102661},    {'X': 0.8636319041252136, 'Y': 0.4265892207622528},    {'X': 0.8097145557403564, 'Y': 0.4255805015563965}]},
  'Id': 0,
  'Type': 'LINE'},
 {'Confidence': 81.16915130615234,
  'DetectedText': 'Minorcuts',
  'Geometry': {'BoundingBox': {'Height': 0.025231996551156044,
    'Left': 0.8168795108795166,
    'Top': 0.4240514636039734,
    'Width': 0.06063205003738403},
   'Polygon': [{'X': 0.8168795108795166, 'Y': 0.4240514636039734},
    {'X': 0.8775115609169006, 'Y': 0.4253864288330078},
    {'X': 0.8773359060287476, 'Y': 0.4506184160709381},
    {'X': 0.8167038559913635, 'Y': 0.4492834508419037}]},
  'Id': 1,
  'Type': 'LINE'},
.
.
.
}]

对于下图:

See “Protects” and “Minorcuts”?

认识名人

celeb_detect will be a dictionary with keys [‘OrientationCorrection’, ‘CelebrityFaces’, ‘UnrecognizedFaces’, ‘ResponseMetadata’]

类似于 DetectText,recognize small ness 返回字典的字典。以下是 celeb_detect["CelebrityFaces"]的输出:

[Output]
[{'Face': {'BoundingBox': {'Height': 0.10687500238418579,    'Left': 0.4807872474193573,    'Top': 0.15562500059604645,    'Width': 0.16026242077350616},   'Confidence': 99.9999771118164,   'Landmarks': [{'Type': 'eyeLeft',     'X': 0.5403168201446533,     'Y': 0.19756773114204407},    {'Type': 'eyeRight', 'X': 0.5921167731285095, 'Y': 0.20492416620254517},    {'Type': 'nose', 'X': 0.5595902800559998, 'Y': 0.22208547592163086},    {'Type': 'mouthLeft', 'X': 0.5338063836097717, 'Y': 0.23306140303611755},    {'Type': 'mouthRight', 'X': 0.5765158534049988, 'Y': 0.23889882862567902}],
   'Pose': {'Pitch': -3.3401520252227783,
    'Roll': 11.797859191894531,
    'Yaw': -0.263323575258255},
   'Quality': {'Brightness': 23.701353073120117,
    'Sharpness': 99.99090576171875}},
  'Id': '1ax3nr0o',
  'MatchConfidence': 94.0,
  'Name': 'Kim Kardashian',
  'Urls': ['www.imdb.com/name/nm2578007']}]

对于下图:

第三步:将数据保存在长和宽的数据框中

还不错!现在把它们放在一个 for 循环中,这样你就可以得到一个数据帧,其中包含了我们想要使用 Rekognition 检索的所有信息。

长数据将像这样存储:

Data Cleaning idea: If it is a celebrity, remove all other labels as celebrity fashion can be difficult for Rekognition.

宽数据将像这样存储,每张图片一行,列跨越标签、单词和它们的置信度。

这个 for 循环步骤需要很长时间才能用完你的 Jupyter 笔记本。对于 10,000 张图片,我花了大约 8 个小时。Try/except 语句包含在每个组成部分 detect_labels、detect_text 和 recognize _ 中,因为并非所有图像都会从所有三个操作中得到响应。

图像处理愉快!

关于这个主题有很多资源,你可以在我发现每个资源最有用的步骤中找到我使用的链接。我发现 Rekognition 非常有效,但它确实有一些问题(就像任何图像识别工具一样)。特别是,没有被很好分类的照片是特定身体部位(即:嘴)的特写,一张眼影化妆的图像被分类为巧克力或软糖。

I can see how this can be mistaken for chocolate or fudge.

如果您在执行分析之前使用了这段代码,请在评论中链接您的项目,我很乐意看到您的工作。如果 Rekognition 给你的图片带来了任何古怪的标签或者错误的分类,我也想听听。

在我的 GitHub 上找到我的 Jupyter 笔记本:https://GitHub . com/nmolivo/Blogs/tree/master/002 _ AWS recognition

使用 torchtext 加载 NLP 数据集—第一部分

原文:towardsdatascience.com/use-torchte…

PyTorch Tensors 管道的简单 CSV 文件

如果你是 PyTorch 用户,你可能已经熟悉了 torchvision 库,因为 torchvision 已经变得相对稳定和强大,而已经成为 PyTorch 的官方文档。鲜为人知的 torchtext 库试图实现与 torchvision 相同的东西,但使用 NLP 数据集。它仍在积极开发中,并且有些问题可能需要您自己解决【1】【2】。尽管如此,我发现它已经相当有用了。最好使用 torchtext 并在需要时定制或扩展它(如果你的用例是通用的,也许还可以创建一个 PR)。)而不是自己构建整个预处理管道。

在这篇文章中,我将使用有毒评论分类数据集作为一个例子,并尝试使用 torchtext 演示一个加载该数据集的工作管道。我以前在一次不成功的尝试中使用过这个数据集,我们将在这里使用相同的标记化方案:

[## [学习笔记]用于多标签文本分类的 StarSpace

StarSpace 是一个雄心勃勃的模型,试图解决广泛的实体嵌入问题。它已经被创建并且…

medium.com](medium.com/@ceshine/le…)

证明文件

首先需要解决的是文档。在项目自述之外基本没有简洁的代码示例。下一个最好的事情是在 test 文件夹中的单元测试。你必须弄清楚东西在哪里,然后自己把它们放在一起。

您可以使用 sphinx 从 docstrings 构建文档(在本文中我们使用了 torchtext 0.2.1):

pip install sphinx sphinx_rtd_theme
git clone --branch v0.2.1 [https://github.com/pytorch/text.git](https://github.com/pytorch/text.git)
cd text/docs
make html

HTML 页面将位于 text/docs/build/html 文件夹中。

我个人觉得直接看源代码比较容易。

预处理 CSV 文件

import pandas as pd
import numpy as npVAL_RATIO = 0.2def prepare_csv(seed=999):
    df_train = pd.read_csv("data/train.csv")
    df_train["comment_text"] = \
        df_train.comment_text.str.replace("\n", " ")
    idx = np.arange(df_train.shape[0])
    np.random.seed(seed)
    np.random.shuffle(idx)
    val_size = int(len(idx) * VAL_RATIO)
    df_train.iloc[idx[val_size:], :].to_csv(
        "cache/dataset_train.csv", index=False)
    df_train.iloc[idx[:val_size], :].to_csv(
        "cache/dataset_val.csv", index=False)
    df_test = pd.read_csv("data/test.csv")
    df_test["comment_text"] = \
        df_test.comment_text.str.replace("\n", " ")
    df_test.to_csv("cache/dataset_test.csv", index=False)

和上一篇文章一样,我把原始数据放在数据文件夹中,所有从它导出的数据都放在缓存文件夹中。这个 prepare_csv 功能的存在主要有两个原因:

  1. 您必须自己将训练数据集分为训练数据集和验证数据集。torchtext 不会为你这样做。
  2. 需要删除换行符。否则 torchtext 无法正确读取 csv 文件。

是为了确保我们每次都有相同的分成。

标记化

如前所述,标记化方案与前一篇文章中的相同:

import reimport spacy
NLP = spacy.load('en')
MAX_CHARS = 20000def tokenizer(comment):
    comment = re.sub(
        r"[\*\"“”\n\\…\+\-\/\=\(\)‘•:\[\]\|’\!;]", " ", 
        str(comment))
    comment = re.sub(r"[ ]+", " ", comment)
    comment = re.sub(r"\!+", "!", comment)
    comment = re.sub(r"\,+", ",", comment)
    comment = re.sub(r"\?+", "?", comment)
    if (len(comment) > MAX_CHARS):
        comment = comment[:MAX_CHARS]
    return [
        x.text for x in NLP.tokenizer(comment) if x.text != " "]

这个函数返回一个注释的标记列表。很长的注释被修剪为 MAX_CHARS 个字符,否则 NLP.tokenizer 可能需要很长时间才能返回。

加载数据集

import loggingimport torch
from torchtext import dataLOGGER = logging.getLogger("toxic_dataset")def get_dataset(fix_length=100, lower=False, vectors=None):
    if vectors is not None:
        # pretrain vectors only supports all lower cases
        lower = True
    LOGGER.debug("Preparing CSV files...")
    prepare_csv()
    comment = data.Field(
        sequential=True,
        fix_length=fix_length,
        tokenize=tokenizer,
        pad_first=True,
        tensor_type=torch.cuda.LongTensor,
        lower=lower
    )
    LOGGER.debug("Reading train csv file...")
    train, val = data.TabularDataset.splits(
        path='cache/', format='csv', skip_header=True,
        train='dataset_train.csv', validation='dataset_val.csv',
        fields=[
            ('id', None),
            ('comment_text', comment),
            ('toxic', data.Field(
                use_vocab=False, sequential=False,
                tensor_type=torch.cuda.ByteTensor)),
            ('severe_toxic', data.Field(
                use_vocab=False, sequential=False, 
                tensor_type=torch.cuda.ByteTensor)),
            ('obscene', data.Field(
                use_vocab=False, sequential=False, 
                tensor_type=torch.cuda.ByteTensor)),
            ('threat', data.Field(
                use_vocab=False, sequential=False, 
                tensor_type=torch.cuda.ByteTensor)),
            ('insult', data.Field(
                use_vocab=False, sequential=False, 
                tensor_type=torch.cuda.ByteTensor)),
            ('identity_hate', data.Field(
                use_vocab=False, sequential=False, 
                tensor_type=torch.cuda.ByteTensor)),
        ])
    LOGGER.debug("Reading test csv file...")
    test = data.TabularDataset(
        path='cache/dataset_test.csv', format='csv', 
        skip_header=True,
        fields=[
            ('id', None),
            ('comment_text', comment)
        ])
    LOGGER.debug("Building vocabulary...")
    comment.build_vocab(
        train, val, test,
        max_size=20000,
        min_freq=50,
        vectors=vectors
    )
    LOGGER.debug("Done preparing the datasets")
    return train, val, test

该功能有两个主要组件:data.Fielddata.TabularDatasetcomment变量指定了comment_text列的预处理管道,并在trainvalidationtest数据集之间共享,因此它们使用相同的词汇。一些细节:

  1. sequential=True指定该列保存序列。
  2. tokenizer=tokenizer指定记号赋予器。如果输入列足够干净,可以使用内置的标记器,例如tokenizer="spacy"
  3. fix_length将所有序列填充或修剪到固定长度。如果未设置,长度将是每批中最长序列的长度。
  4. pad_first=True从左侧填充序列。例如,如果目标长度为 5,A text sequence将被填充为<pad> <pad> A text sequence
  5. tensor_type指定返回的张量类型。由于在大多数情况下我们使用 GPU 来训练模型,将其设置为torch.cuda.LongTensor将省去我们稍后将其移动到 GPU 内存的麻烦。
  6. lower指定我们是否将所有英文字符设置为小写。

另一个非常方便的特性是.build_vocab,它构建了词汇表,因此我们可以在以后将记号/单词转换成整数,并且可以选择性地为您加载预训练的单词向量(comment.vocab.vectors将是与当前词汇表对齐的加载向量)。在处检查可用的预训练矢量max_size设置最大词汇量,min_freq设置一个单词在语料库中出现的最少次数。

字段toxicsevere_toxicobscenethreatinsultidentity_hate为二元变量。稍后我们需要将它们组合在一起作为模型的目标。

data.TabularDataset.splits做的基本和data.TabularDataset.__init__一样,但是同时读取多个文件。测试数据集在单独的调用中加载,因为它没有目标列。我们必须在 csv 文件中以精确的顺序指定字段,并且不能跳过任何列。因此,我们必须明确指定("id", None)来跳过第一列。

创建批处理并遍历数据集

def get_iterator(dataset, batch_size, train=True, 
    shuffle=True, repeat=False):
    dataset_iter = data.Iterator(
        dataset, batch_size=batch_size, device=0,
        train=train, shuffle=shuffle, repeat=repeat,
        sort=False
    )
    return dataset_iter

这应该很简单。它会返回一些我们可以迭代的东西,当整个数据集都被读取后就会停止。我们还没有使用高级的sort特性,因为我们使用的是固定长度,我们可能不需要这样做。

下面是一个简单的用法示例(针对一个时期):

for examples in get_iterator(
            self.train_dataset, batch_size, train=True,
            shuffle=True, repeat=False
        ):
    x = examples.comment_text # (fix_length, batch_size) Tensor
    y = torch.stack([
        examples.toxic, examples.severe_toxic, 
        examples.obscene,
        examples.threat, examples.insult, 
        examples.identity_hate
    ], dim=1)

并使用加载的预训练向量(假设您的单词嵌入位于model.word_em,训练数据集作为train_dataset加载):

model.word_em.weight.data = \
    train_dataset.fields["comment_text"].vocab.vectors

就是这样!我们差不多已经有了开始构建和训练模型所需的东西。

**20180207 更新:**我注意到get_iterator既没有random_state也没有seed参数。实际上是靠random内置模块来管理随机性。因此,您需要执行以下操作之一来获得不同时期之间的不同批次:

  1. 在历元之间用不同的种子运行random.seed(seed)(在调用get_iterator之前)
  2. get_iterator中使用repeat=True。您必须自己在循环内部定义一个停止标准,否则 for 循环将永远继续下去。

未完待续…

上述方法存在一个重大问题。真的很慢。在我的电脑上,整个数据集加载过程大约需要 7 分钟,而实际的模型训练大约需要 10 分钟。我们应该序列化标记化的序列,也许还应该序列化词汇表,以使它更快。一旦我想通了,我打算在下一篇文章中写下如何去做。

除了序列化,许多事情也可以改进。例如,一个更灵活的训练/验证分割方案会有很大帮助。高级排序机制和压缩序列可能也值得探索。

附加链接

更详细的教程:

[## Torchtext 教程

大约 2-3 个月前,我遇到了这个库:Torchtext。我漫不经心地浏览了自述文件,意识到…

阿尼.我](anie.me/On-Torchtex…)

第二部分出版:

[## 使用 torchtext 加载 NLP 数据集—第二部分

序列化和更容易的交叉验证

medium.com](medium.com/@ceshine/us…)

Python 环境

  • Python 3.6
  • 数字版本 1.14.0
  • 熊猫
  • PyTorch 0.4.0a0+f83ca63(应该很接近 0.3.0)
  • 火炬文本 0.2.1
  • 空间 2.0.5

这篇文章中使用的所有代码

(不包括示例用法。)

使用 torchtext 加载 NLP 数据集—第二部分

原文:towardsdatascience.com/use-torchte…

序列化和更容易的交叉验证

Source

[## 使用 torchtext 加载 NLP 数据集—第一部分

PyTorch Tensors 管道的简单 CSV 文件

towardsdatascience.com](/use-torchtext-to-load-nlp-datasets-part-i-5da6f1c89d84)

在第一部分中,我们讨论了如何从 csv 文件加载文本数据集,标记文本,并通过 torchtext 将它们放入张量。现在,我们将解决该解决方案中的两个问题(仍然使用有毒评论数据集):

  1. 加载时间太长:每次你想运行一个新的实验,重新加载数据集会浪费你很多时间。
  2. 交叉验证方法的有限选择:实际上只有一个选择——可以通过 seedVAL_RATIO 参数控制的随机分割。

序列化

首先,TabularDataset不幸的是不能直接序列化。我们从观察开始寻找替代方案,在__init__方法中,TabularDataset 将文件读入示例列表:

with io.open(os.path.expanduser(path), encoding="utf8") as f:
    if skip_header:
        next(f)                                   
    examples = [make_example(line, fields) for line in f]

下一个观察是TabularDataset的超类Dataset接受一个参数examples(一个例子列表)。所以现在很清楚,我们需要的是序列化来自 **TabularDataset** 实例的示例,并根据请求创建 **Dataset** 实例。额外的好处是序列化了comment字段实例。

更具体地说,以下是一般的工作流程:

def read_files():
    comment = data.Field(...)
    train = data.TabularDataset(...) 
    test  = data.TabularDataset(...)
    comment.build_vocab(...)
    return train.examples, test.examples, commentdef restore_dataset(train_examples, test_examples, comment):
    train = data.Dataset(...)
    test  = data.Dataset(...)
    return train, test

前两个返回的变量是重建数据集的基本组件。如果你愿意,你可以改装一个comment字段实例,但是如果你不这样做,它会更快。初始化数据集时,只需插入comment作为字段之一。

交叉验证

因为现在我们从一系列例子而不是 CSV 文件中创建数据集实例,所以生活变得容易多了。我们可以按照我们想要的任何方式拆分示例列表,并为每个拆分创建数据集实例。对于分类任务,我通常更喜欢分层 K-Fold 验证。但因为有毒评论数据集是多标签的,所以更难做分层。我们将在下面的章节中使用简单的 K-Fold 验证。

把它放在一起

完整代码请参考帖子末尾。以下是新解决方案与第一部分中的旧解决方案之间的一些比较:

  1. 我们使用和以前完全一样的记号赋予器。
  2. 尽管不必创建训练/验证分割,我们仍然需要一个简化的prepare_csv 函数来从原始 CSV 文件中删除 \n 字符。
  3. 这个简洁的库joblib可以消除通过pickle模块显式序列化的需要。它的一个特性是对输出值的透明和快速磁盘缓存,这可以通过创建一个缓存设置MEMORY并在任何想要缓存的函数上使用**@MEMORY.cache** 装饰器来实现(在本例中,函数read_files读入 CSV 文件并返回两个示例列表和一个字段实例)。
  4. 主函数get_dataset现在返回一个生成器一个测试数据集。生成器为每次迭代提供一个训练数据集和一个验证数据集,并在您运行所有可用的 K 次迭代后实现 K 重验证。

以下是在 5 重验证方案下训练 5 个模型的脚本示例:

train_val_generator, test_dataset = get_dataset(
    fix_length=100, lower=True, vectors="fasttext.en.300d",
    n_folds=5, seed=123
)
for fold, (train_dataset, val_dataset) in \
    enumerate(train_val_generator):
    # Initialize a model here...
    for batch in get_iterator(
        train_dataset, batch_size=32, train=True,
        shuffle=True, repeat=False
    ):
        # Train the model here...
    # Create prediction for val_dataset and get a score...
    # Create inference for test_dataset...

如果你忘了,这里有一个特征和目标提取的例子:

x = batch.comment_text.data
y = torch.stack([
        batch.toxic, batch.severe_toxic, batch.obscene,
        batch.threat, batch.insult, batch.identity_hate
    ],dim=1)

加速

这取决于你的 CPU 的能力和你的磁盘的读取速度。在我的电脑里,第一次调用get_dataset需要 6 分多钟,之后大约 1 分钟。

有毒注释数据集加载器的更新版本

使用无监督的机器学习来寻找你的产品的潜在买家

原文:towardsdatascience.com/use-unsuper…

让算法自己学习…

什么是无监督机器学习

欢迎来到我关于数据科学的第三篇文章!在我之前的帖子中,我讨论了我如何使用监督机器学习来为一个慈善机构寻找捐助者。回想一下,在监督机器学习中,您有输入变量(X)和输出变量(Y ),并且您使用算法来学习从输入到输出的映射函数。**相比之下,在无监督的机器学习中你只有输入数据(X)而没有相应的输出变量。**无监督学习的目标是对数据中的底层结构或分布进行建模,以便了解更多关于数据的信息。这些被称为非监督学习,因为不像上面的监督学习,没有正确的答案,也没有老师。算法被留给它们自己的装置去发现和呈现数据中有趣的结构。

无监督学习问题可以进一步分为聚类和关联问题。聚类:聚类问题是您想要发现数据中的内在分组,比如按照购买行为对客户进行分组。关联:关联规则学习问题是你想要发现描述大部分数据的规则,比如购买 X 的人也倾向于购买 y。

项目亮点

在我将在这里描述的项目中,我使用了来自德国一家邮购销售公司的 Bertelsmann Arvato Analytics 的真实财务数据。我的任务是识别构成该公司用户基础核心的人群。换句话说,我处理了一个集群问题。

在接下来的段落中,我将详细阐述我实现目标的步骤。就像在大部分机器学习问题中,无论你的算法有多复杂,都必须先清理数据。我们开始吧:)

数据处理

有四个数据集与此案例相关:

  • Udacity_AZDIAS_Subset.csv:德国一般人口的人口统计数据;891211 人(行)x 85 个特征(列)。
  • Udacity_CUSTOMERS_Subset.csv:邮购公司客户的人口统计数据;191652 人(行)x 85 特征(列)。
  • Data_Dictionary.md:所提供数据集中要素的详细信息文件。
  • AZDIAS_Feature_Summary.csv:人口统计数据特征属性汇总;85 个特征(行)x 4 列

人口统计文件的每一行代表一个人,但也包括个人以外的信息,包括他们的家庭、建筑和邻居的信息。我使用这些数据将普通人群分成具有相似人口统计特征的群体。目的是了解客户数据集中的人如何适应这些创建的分类。

让我们看看我们将使用哪些功能。

*# Load in the general demographics data.*
azdias = pd.read_csv('Udacity_AZDIAS_Subset.csv', sep = ';')

*# Load in the feature summary file.*
feat_info = pd.read_csv('AZDIAS_Feature_Summary.csv', sep = ';')print(feat_info)

在字典文件中,所有这些特性都有更详细的描述。即,提供了它们在英语中的含义,以及这些特征的不同级别的含义。

请注意,特征属性摘要的第四列(在上面作为feat_info载入)记录了数据字典中的代码,这些代码表示缺失或未知的数据。虽然文件将它编码为一个列表(例如[-1,0]),但它将作为一个字符串对象读入。我将匹配“缺失”或“未知”值代码的数据转换为 numpy NaN 值。

*# turn missing_or_unknown to list* 
feat_info['missing_or_unknown'] = feat_info['missing_or_unknown'].apply(**lambda** x: x[1:-1].split(','))

*# Identify missing or unknown data values and convert them to NaNs.*
**for** attrib, missing_values **in** zip(feat_info['attribute'], feat_info['missing_or_unknown']):
    **if** missing_values[0] != '':
        **for** value **in** missing_values:
            **if** value.isnumeric() **or** value.lstrip('-').isnumeric():
                value = int(value)
            azdias.loc[azdias[attrib] == value, attrib] = np.nan

评估各栏缺失数据

*# Perform an assessment of how much missing data there is in each column of the*
*# dataset.*
missing_data = pd.Series(azdias.isnull().sum() / len(azdias))
missing_data.plot(kind='barh', figsize=(10, 20))missing_data[missing_data > 0.2].index.tolist()['AGER_TYP',
 'GEBURTSJAHR',
 'TITEL_KZ',
 'ALTER_HH',
 'KK_KUNDENTYP',
 'KBA05_BAUMAX']*# Remove the outlier columns from the dataset. (You'll perform other data engineering tasks such as re-encoding and imputation later.)*azdias = azdias.drop(['AGER_TYP','GEBURTSJAHR','TITEL_KZ','ALTER_HH','KK_KUNDENTYP','KBA05_BAUMAX'], axis = 1)

我已经用柱状图评估了缺失的数据。我已经将丢失值超过 20%的列归类为异常值。结果,我找到了 6 个这样的列,我放弃了。其他突出的异常值是有 13%缺失值的 PLZ8 特性;以及具有 15%缺失值的 KBA05 功能。

评估每行的缺失数据

就像评估列中缺失数据的情况一样,我寻找含有缺失数据的异常行。我将阈值设置为每行 10 个缺失值,并将数据分为两组:缺失值数量多的行(即高于 10),缺失值数量少的行(即低于 10)。我比较了这两组之间几个非缺失特征的分布。目的是了解我是否应该以特定的方式对待这些数据点。

*# How much data is missing in each row of the dataset?*
missing_data_rows = azdias.isnull().sum(axis = 1)missing_data_rows_low = azdias[azdias.isnull().sum(axis=1) < 10].reset_index(drop=**True**)

missing_data_rows_high = azdias[azdias.isnull().sum(axis = 1) >= 10].reset_index(drop=**True**)**def** countplot(columns, num):
    fig, axs = plt.subplots(num, 2, figsize=(15, 15))
    fig.subplots_adjust(hspace =2 , wspace=.2)
    axs = axs.ravel()

    **for** i **in** range(num):

        sns.countplot(missing_data_rows_low[columns[i]], ax=axs[i*2])
        axs[i*2].set_title('missing_data_rows_low')
        sns.countplot(missing_data_rows_high[columns[i]], ax=axs[i*2+1])
        axs[i*2+1].set_title('missing_data_rows_high')

countplot(missing_data_rows_high.columns, 3)

对于我检查过的一些特性,缺失值多的行和缺失值少的行之间似乎有不同的分布。这意味着缺失值数量多的行和缺失值数量少的行之间的数据在性质上是不同的。缺失数据数量少的行组将被考虑用于进一步分析,而缺失数据数量多的行组最终将被视为附加聚类。

数据角力

**def** clean_data(df):
    *"""*
 *Perform feature trimming, re-encoding, and engineering for demographics*
 *data*

 *INPUT: Demographics DataFrame*
 *OUTPUT: Trimmed and cleaned demographics DataFrame*
 *"""*

    *# Put in code here to execute all main cleaning steps:*
    *# convert missing value codes into NaNs, ...*

    df_copy = df.copy()

*# Identify missing or unknown data values and convert them to NaNs.*
    **for** col_name **in** df.columns:
        df_copy[col_name] = df_copy[col_name].map(**lambda** x: np.nan **if** str(x) **in** feat_info.loc[col_name].missing_or_unknown **else** x)

    *# remove selected columns and rows, ...*
    c_removed =['AGER_TYP','GEBURTSJAHR','TITEL_KZ','ALTER_HH','KK_KUNDENTYP','KBA05_BAUMAX']

    **for** c **in** c_removed:
        df_copy.drop(c, axis=1, inplace=**True**)

    df_copy = df_copy[df_copy.isnull().sum(axis=1) < 10].reset_index(drop=**True**)

    **for** col **in** df_copy.columns:
        df_copy[col] = df_copy[col].fillna(df_copy[col].mode()[0])

    *# select, re-encode, and engineer column values.*
    multi_level = []
    **for** column **in** df_copy.columns:
        **if** feat_info.loc[column].type == 'categorical' **and** len(df_copy[column].unique()) > 2:
            multi_level.append(column)

    **for** col **in** multi_level:
        df_copy.drop(col, axis=1, inplace=**True**)

    df_copy['decade'] = df_copy['PRAEGENDE_JUGENDJAHRE'].apply(create_interval_decade)
    df_copy['movement'] = df_copy['PRAEGENDE_JUGENDJAHRE'].apply(create_binary_movement)
    df_copy.drop('PRAEGENDE_JUGENDJAHRE', axis=1, inplace=**True**)

    df_copy['wealth'] = df_copy['CAMEO_INTL_2015'].apply(wealth)
    df_copy['life_stage'] = df_copy['CAMEO_INTL_2015'].apply(life_stage)
    df_copy.drop('CAMEO_INTL_2015', axis=1, inplace=**True**)

    df_copy = pd.get_dummies(data=df_copy, columns=['OST_WEST_KZ'])

    mixed = ['LP_LEBENSPHASE_FEIN','LP_LEBENSPHASE_GROB','WOHNLAGE','PLZ8_BAUMAX']

    **for** c **in** mixed:
        df_copy.drop(c, axis=1, inplace=**True**)

     *# Return the cleaned dataframe.*
    **return** df_copy

我创建了一个清理数据函数,可以应用于一般人口统计数据和客户统计数据。

主成分分析

PCA 是最常用的无监督机器学习工具之一。主成分是数据集中原始特征的线性组合,旨在保留原始数据中的大部分信息。主成分分析是一种基于现有特征从数据集中提取新的“潜在特征”的常用方法。想象一个主成分,就像你想象一个潜在特征一样。

当我们拥有包含成百上千个特征的数据集时,为了有效地构建模型,我们必须减少维数。有两种方法可以做到这一点:

a) *特征选择:*特征选择包括从您确定最相关和最有用的原始数据特征中寻找一个子集

b) *特征提取:*特征提取包括提取或构建称为潜在特征的新特征。

特征转换

我执行了特征缩放,这样主成分向量就不会受到特征缩放的自然差异的影响。

*# Fill the Nan values with the mode of that respective column.***for** col **in** missing_data_rows_low.columns:
        missing_data_rows_low[col] = missing_data_rows_low[col].fillna(missing_data_rows_low[col].mode()[0])*# Apply feature scaling to the general population demographics data.*normalizer = StandardScaler()
missing_data_rows_low[missing_data_rows_low.columns] = normalizer.fit_transform(missing_data_rows_low[missing_data_rows_low.columns])missing_data_rows_low.head()

降维

*# Apply PCA to the data.*

pca = PCA()
missing_data_rows_low_pca = pca.fit_transform(missing_data_rows_low)*# Investigate the variance accounted for by each principal component.***def** scree_plot(pca):
    *'''*
 *Creates a scree plot associated with the principal components* 

 *INPUT: pca - the result of instantian of PCA in scikit learn*

 *OUTPUT:*
 *None*
 *'''*
    num_components = len(pca.explained_variance_ratio_)
    ind = np.arange(num_components)
    vals = pca.explained_variance_ratio_

    plt.figure(figsize=(10, 6))
    ax = plt.subplot(111)
    cumvals = np.cumsum(vals)
    ax.bar(ind, vals)
    ax.plot(ind, cumvals)

    ax.xaxis.set_tick_params(width=0)
    ax.yaxis.set_tick_params(width=2, length=12)

    ax.set_xlabel("Principal Component")
    ax.set_ylabel("Variance Explained (%)")
    plt.title('Explained Variance Per Principal Component')

scree_plot(pca)

*# Re-apply PCA to the data while selecting for number of components to retain.*

pca = PCA(n_components=41)
missing_data_rows_low_pca = pca.fit_transform(missing_data_rows_low)

基于 PCA 图,解释的方差在 41 个成分之后变得极低,并且之后不变。所以我又用 41 个成分做了主成分分析。

每个主成分是一个指向最高方差方向的单位向量(在考虑了早期主成分捕获的方差之后)。权重离零越远,主分量在相应特征的方向上就越多。如果两个特征具有相同符号的较大权重(都是正的或都是负的),那么一个特征的增加会与另一个特征的增加相关联。相比之下,具有不同符号的特征可能会表现出负相关性:一个变量的增加会导致另一个变量的减少。

对普通人群应用聚类分析

**def** get_kmeans_score(data, center):
    *'''*
 *returns the kmeans score regarding SSE for points to centers*
 *INPUT:*
 *data - the dataset you want to fit kmeans to*
 *center - the number of centers you want (the k value)*
 *OUTPUT:*
 *score - the SSE score for the kmeans model fit to the data*
 *'''*
    *#instantiate kmeans*
    kmeans = KMeans(n_clusters=center)

    *# Then fit the model to your data using the fit method*
    model = kmeans.fit(data)

    *# Obtain a score related to the model fit*
    score = np.abs(model.score(data))

    **return** score*# Over a number of different cluster counts...*
*# run k-means clustering on the data and...*
*# compute the average within-cluster distances.*scores = []
centers = list(range(1,30,3))

**for** center **in** centers:
    scores.append(get_kmeans_score(missing_data_rows_low_pca, center))*# Investigate the change in within-cluster distance across number of clusters.*
*# HINT: Use matplotlib's plot function to visualize this relationship.*plt.plot(centers, scores, linestyle='--', marker='o', color='b');
plt.xlabel('K');
plt.ylabel('SSE');
plt.title('SSE vs. K')

*# Re-fit the k-means model with the selected number of clusters and obtain*
*# cluster predictions for the general population demographics data.*

*# Re-fit the k-means model with the selected number of clusters and obtain*
*# cluster predictions for the general population demographics data.*

kmeans = KMeans(n_clusters=22)
model_general = kmeans.fit(missing_data_rows_low_pca)predict_general = model_general.predict(missing_data_rows_low_pca)

根据该图,我们可以看到 22 似乎是一个足够的集群数量。后来的变化率是 SSE 极低。

将客户数据与人口统计数据进行比较

在对人口统计数据进行聚类之后,我们对客户统计数据应用相同的数据清理步骤和聚类。目的是看哪个对公司来说是强大的客户群。

如果与一般人群相比,客户数据的聚类中有更高比例的人(例如,5%的人被分配到一般人群的聚类,但是 15%的客户数据最接近该聚类的质心),则这表明该聚类中的人是公司的目标受众。另一方面,聚类中的数据在一般人群中的比例大于客户数据(例如,只有 2%的客户最接近捕获 6%数据的人群质心)表明该人群在目标人口统计之外。

分析客户数据过多的聚类

*# What kinds of people are part of a cluster that is overrepresented in the*
*# customer data compared to the general population?*
over = normalizer.inverse_transform(pca.inverse_transform(customers_clean_pca[np.where(predict_customers==11)])).round()
df_over = pd.DataFrame(data = over, columns = customers_clean.columns)
df_over.head(10)

这个细分市场由年龄在 46 岁到 60 岁之间的个人组成,他们不是财务上的最低要求者。也就是说,他们可能是退休或接近退休的人,渴望消费商品和服务。

分析客户数据代表性不足的聚类

*# What kinds of people are part of a cluster that is underrepresented in the*
*# customer data compared to the general population?*
under = normalizer.inverse_transform(pca.inverse_transform(customers_clean_pca[np.where(predict_customers==16)])).round()
df_under = pd.DataFrame(data=under, columns=customers_clean.columns)
df_under.head(10)

这部分人由较年轻年龄组(45 岁以下)的人组成,失业人口比例较大。

项目结束

回想一下,在数据处理步骤中,我们确定丢失数据数量较多的行组最终将被视为一个额外的聚类。上述组中的簇 22 是最后添加的簇。我们可以看到,在大多数集群中,人口百分比和客户百分比之间存在相当大的差异。在大多数集群中,一般人口所占比例过大。例如,在聚类 11 中,客户部分被过度表示;它由年龄在 46 岁到 60 岁之间的人组成,他们都不是财务上的极简主义者。也就是说,他们可能是退休或接近退休的人,渴望消费商品和服务。所以把它当成一个客户群是有道理的。另一方面,在聚类 16 中,客户细分未被充分代表。这部分人由较年轻年龄组(45 岁以下)的人组成,失业人口比例较大。由于他们大多失业,他们很可能依靠社会保障生活。因此,他们没有大量的可支配资金来购买销售给他们的产品。

结束语

如果你坚持到了最后,非常感谢你的阅读:)我知道这些帖子很长,并且包括许多代码片段,但我真的认为忽略机器学习的技术方面对于展示算法如何工作是不可行的。这个项目对我来说是有益的,因为它包含了真实世界的财务数据和真实世界的商业目标。

我希望这能让你理解无监督机器学习如何应用于商业和营销。如果你想浏览我写的所有代码,你可以在我的 github 上访问我的项目。

在 LinkedIn 上关注我:【www.linkedin.com/in/andreiga…

上帝保佑你!

检测盈余操纵和欺诈的有用工具

原文:towardsdatascience.com/useful-tool…

在 MSBA 的夏季学期,我遇到了当时我处理过的最大的数据集。这是财务会计课程的作业。该主题与利用公司会计数据检测盈余操纵和欺诈有关。

数据集来自 Compustat,这是一个关于全球活跃和不活跃的全球性公司的金融、统计和市场信息的数据库(引自维基)。老师给我们提供了数据库。我们的任务是通过不同的模型和工具来检测收入异常。

这个过程令人生畏,但充满乐趣。一个月后,我决定重温这些作业。在这篇文章中,我将介绍我所学到的检测盈余操纵和潜在欺诈的模型和工具。

这篇文章将从理论和实践两方面来写。我将尽力阐述我所知道的工具,并展示如何实现结果的代码。这些工具应用于 1988 年至 2017 年的年度数据,以及数据集中的每一家公司,这些数据展示了盈余操纵趋势的整体情况。

在下一篇文章中,我将介绍我是如何使用这些工具对全球最大的生物技术公司之一安进公司进行盈余操纵研究的。

工具和技能

主要工具:Python Spyder 和 R

使用的技巧:用熊猫清理数据,用 Matplotlib 和 ggplot2 可视化,线性回归,固定效应回归

分析工具和流程概述

A.清理和切片数据

B.简单的探索性数据分析

C.盈余管理的间接证据

D.本福特定律

E.全权应计模型

F.经营现金流和应计模型

A.清理和切片数据

Compustat 是一个庞大的数据集。在数据字典中,它包含近 1000 个变量,数据跨越近半个世纪,包含详细的公司信息。它的 CSV 文件将近 1.6GB,用户无法用一个简单的 excel 打开它,加载到 R 和 Python 需要一段时间。

在作业中,我的目标是描述某个数据块的经济真相。所以我按照教授的指导进行了数据清理和切片,后来我将数据导出为大小合适的 csv 文件,并将其附在我的 Github 中。如果感兴趣,可以下载并试用它。

数据清理过程需要几个步骤。

(1)仅选择几个变量,包括 gvkey(公司标识符)、datadate(报告期)、fyear(财政年度)、revt、rect、ppegt、epspi、ni、at、oancf、sic 和 rdq。

(2)样本年份限定在 1988 年至 2017 年之间。

(3)放弃任何缺少资产、收入、净收入、每股收益、应收账款和经营现金流的观察。

(4)如果 PPE 丢失,将其设置为零。

(5)放弃任何收入和应收账款为负数的观察。

(6)删除基于除列 rdq 之外的所有列的重复观察。

按照说明,我编写了如下 python 代码。在该过程之后,数据帧保持大约 248,288 行,这是可以接受的。

compustat = pd.read_csv("compustat_1950_2018_annual_merged.csv")
compustat_1 = compustat[["gvkey","datadate","fyear","revt","rect","ppegt","epspi","ni","at","oancf","sic","rdq"]]
compustat_2 = compustat_1.loc[compustat_1["fyear"] > 1987]
compustat_2 = compustat_2.loc[compustat_2['fyear'] < 2018]
compustat_3 = compustat_2[compustat_2["revt"] >=0]
com_3 = compustat_3[compustat_3['rect'] >= 0]
com_4 = com_3.dropna(subset = ['at','revt','ni','epspi','rect','oancf'])
com_5 = com_4.drop_duplicates(com_4.columns.difference(['rdq']))
com_6 = com_5.fillna(0)

B.简单的探索性数据分析

这一部分试图呈现我清理的数据的全貌。我先简单算一下文件中所有公司的组合 2017 年的营收、净收入、总资产的平均值。逻辑讲师选择这三个指标进行观察的原因非常简单。这些指标对投资者来说很容易理解,也成为操纵的首要目标。

此外,我用简单的代码块绘制了从 1988 年到 2017 年这三个指标的趋势。

df2 = df.groupby('fyear').agg({'revt':'mean', 'ni':'mean', 'at':'mean'})plt.figure(figsize=(10,8))
plt.plot(df2['revt'], linestyle = 'solid')
plt.plot(df2['ni'], linestyle = 'dashed')
plt.plot(df2['at'], linestyle = 'dashdot')
plt.legend(df2.columns.values.tolist())
plt.title('Trend for Revenue, Net Income & Total Asset 1988-2017')
plt.show()

从上面的图像中,我们可以看出,与收入和净收入相比,总资产的平均值大幅增加。对于整个行业来说,财政的资产数量正在增长。这是否意味着某种操纵?(暂时不知道)。至于净收入,其平均值多年来没有太大变化。也许这意味着净收入的质量或计算方式使其更难操纵。我将更进一步,并在稍后揭示这些工具的不同应用的更多细节。

C.盈余管理的间接证据

接下来,我计算了每个公司从 t 年到 t-1 年的每股收益(EPS)和资产回报率(ROA)的变化,并进一步在-0.1 和+0.1 的范围内绘制成直方图。这张图表可以给我们一个可能的盈余管理的更间接的暗示。

我使用 group by 和 shift 函数来创建滞后年度的 EPS 和 ROA。

df3 = df
df3['previous_eps'] = df3.sort_values(['fyear']).groupby('gvkey')['epspi'].shift()
df3['eps_change'] = df3.epspi - df3.previous_eps

我用 Matplotlib 创建了两个相似的图表。

plt.style.use('seaborn-white')
plt.figure(figsize = [15,6])
plt.hist(df4_eps, bins=20, align = 'left')
plt.plot((0,0),(0,8000),'r--')
plt.title('EPS Change Distirbution')

图表显示,在数据集中的所有公司中,每股收益的分布比净资产收益率的分布更不对称。此外,我们还观察到,对于每股收益,正数的频率略大于零,这意味着每年,公司的每股收益往往比前一年表现更好。

这种差异有几个原因。盈余管理可能是一个原因,其他原因如经理更加努力工作也是可能的。

通常,EPS 是利益相关者和市场更关心的指标。它比 ROA 更明显地反映了经理的表现。此外,可以通过回购或向市场释放更多股票来操纵或控制每股收益。这可能是两个关键指标图形对称性差异的原因。

变成单个公司范围,也可以让我们一窥盈余操纵的证据。我可以对某个公司的数据进行子集化,就像上面那样画出对称图,观察异常。

D.本福特定律

本福德定律,也称为首位数定律,是关于许多现实生活中的数字数据集中前导数字的频率分布的观察结果(引自维基百科)。对于一大组数据或列值,本福德定律告诉我们,第一个数字的出现遵循一些规则和概率。因此,如果计数/频率的结果与本福特定律有一些偏差,则存在更高的操纵可能性。

按照老师的指示,我将工具从 Python 切换到 benford.analysis 软件包可以轻松计算列的第一位和第二位。我用收入经营现金流总资产作为观测值。

revenue_bf <- data.frame(benford(abs(df$revt), number.of.digits = 1, sign = 'positive', discrete = TRUE, round = 3)$bfd)[,c("digits","data.dist", "benford.dist")]colnames(revenue_bf) <- c('Digit', 'Sample_Revenue', 'Benford_Distribution')ggplot(data = revenue_bf, aes(x = as.factor(Digit), y =Benford_Distribution)) +
  geom_bar(stat='identity') + 
  geom_line(aes(Digit, Sample_Revenue, col = 'Sample_Revenue'), linetype = 1) + 
  geom_point(aes(Digit, Sample_Revenue), size = 4, col = 'red')+
  ggtitle('Theoretical Distribution v.s. Sample Revenue Distribution - 1st Digits ')

从上面的三张图中,我们可以看到三列中第一位数字的理论分布和样本分布。视觉上,没有那么巨大的差别。

我决定利用卡方检验来看看理论分布和样本分布之间是否真的没有显著性差异。结果如下。

从 p 值来看,经营性现金流并不重要也就不足为奇了。然而,根据测试,收入不会偏离太多,这超出了我的预期,这表明在第一位数操纵的可能性很低。对于资产而言,当其 p 值较低且显著时,其第一位数被操纵的概率较高。还记得一年中的资产图表吗?它的平均值增长了很多。从本福德定律中,我进一步证实了操纵资产的可能性高于所有公司。

在查看第一个数字后,每个特定列的第二个数字也值得调查。与第一个数字略有不同,第二个数字包含数字零,这改变了每个数字的分布百分比。三个指标的结果如下所示。

从上面的三张图中可以明显看出,样本收入、现金流和资产中零的出现频率高于理论上的本福特分布。一种可能的解释是,当公司计算数字时,他们可能倾向于将 9 四舍五入到 10,这导致 0 多 9 少。这可能是有意或无意的,但绝对值得更多的检查,尤其是在分析单个公司时。

从卡方检验来看,所有三个指标的 p 值都非常显著。在所有的收入中,最重要的一项是,这可能意味着经理们倾向于做一些把戏,如收入四舍五入,以获得更好的数字表现。

E.全权应计模型

讲师告诉我们,证券交易委员会使用自主应计模型来筛选公司的不当盈余管理。公式如下:

在这个 OLS 模型中,应计项目是净收入减去经营现金流。除了 SIC 之外的所有变量都来自上一年的数据。因此,简单地说,OLS 模型试图测试以前的业绩指标对今年应计项目的预测能力。SIC 是行业分类器,这意味着对于不同的行业,可能有不同的组和不同水平的估计,可能授予不同的应计项目。

因此,使用面板数据回归来运行整个数据集是一个好主意。代码如下。

fixed_effect.accrual <- plm(accrual ~ cash_revenue + ppe + sic, data= accrual_df, index = c('sic'), model = 'within')

拟合直线后,模型的真正目标是找到残差的绝对值。对此的解释是,如果一个公司,与同行业的其他公司相比,有更高的残差绝对值。其收益更偏离行业标准,具有更高的操纵可能性。

accrual_df$residual <- fixed_effect.accrual$residuals
accrual_df$residual <- abs(accrual_df$residual)

我将在下一篇文章中展示 Amgen 公司的流程。

F.经营现金流和应计模型

该模型还使用 OLS 预测能力,使用应计项目和上一年的经营现金流来预测下一年的经营现金流。公式如下:

我决定对数据集中的每一行进行回归拟合。代码是这样的。我们得到拟合回归的总结。

df$accurals = df$ni - df$oancfdf2 <- df[,c('gvkey','fyear','oancf')]
df3 <- mutate(df2, fyear = fyear - 1) %>%
  rename(., next_oancf = oancf)
df <- left_join(df, df3, by = c('gvkey',"fyear"))oc_reg <- lm(df$next_oancf ~ df$accurals + df$oancf)
summary(oc_reg)

综上所述,应计项目和前期现金流量的 p 值显著,这意味着两者都与下一年的经营现金流量高度相关,并且与目标变量正相关。

之后,导师让我们把数据分成两组,2002 年之前和之后。因此,我在两组数据上运行相同的模型,并得到两个拟合的 OLS 模型的摘要。

1988–2002 Operating cash flow model

2003–2017 Operating cash flow model

从上面的总结中,我们可以从 r-squared 和估计中看出,模型的预测能力在 2002 年之前更为显著。这种差异的经济真相可能是,随着 2002 年后对应计项目或经营性现金流的更多操纵,该模型的预测能力从那时起就被扭曲了。

有了这个模型,它也有助于发现单个公司操纵现金流。策略是将数据分成相等的时间范围,并观察每个时间段的预测能力,以检测可能的盈余管理。在我的下一篇文章中,我也将再次讨论这个问题。

结论

在这篇文章中,我尽力阐述了我在课堂上学到的工具,并展示了将这些工具应用于整体数据的过程。这是一个真正具有挑战性的过程,但通过重新审视数据集和这些模型,我开始意识到进一步研究的深度。在不久的将来,我肯定会继续我的欺诈和利润操纵之旅。

  • 特别感谢我的财务会计课的老师,他给了我一个鼓舞人心的夏天。
  • 所有代码都可以在我的 Github 中找到。请随时给我一些反馈。
If you like the article, feel free to give me 5+ claps
If you want to read more articles like this, give me 10+ claps
If you want to read articles with different topics, give me 15+ claps and leave the comment hereThank for the reading

机器学习的用户体验

原文:towardsdatascience.com/user-experi…

众所周知,机器学习在可解释性方面存在困难,或者更确切地说,是缺乏可解释性。如果您的用户必须处理数字输出,就像在销售、交易或市场营销中使用的系统一样,这是一个问题。如果用户对 ML 输出的解释是错误的,那么实际的度量标准就无关紧要了,你最终会得到糟糕的用户体验。如果您尝试将用户从旧的透明算法切换到 ML,问题甚至会更大——不满意的用户可能会试图反对切换到 ML。此外,尽管听起来有些反直觉,但用户的数学能力可能会对你不利,因为最有经验的用户会给你最大的阻力。

在这里,我概述了当您开始将系统切换到 ML 时,克服用户推回的方法。坦率地说,这些想法中的大多数可以应用于任何黑盒系统,而不仅仅是 ML。其中一些与前景理论有关,这在一本很棒的书《T2 思考,快与慢》中有描述。

变速杆

一些司机喜欢手动档而不是自动档,仅仅是因为他们喜欢控制的感觉。

假设旧系统实现了一个简单易懂的算法,用户可能会选择永远保留它,只是因为他们喜欢清晰和可控的感觉。你的 ML 模型将缺乏对它如何得出特定结果的可解释性,甚至最简单的算法,如基于阈值的 if-condition,在用户眼中也可能胜过 ML。

来自有经验的用户的反推甚至更强,因为他们已经掌握了多个临时变通办法,补偿了简单算法的低复杂性。变通方法的一个例子是:“如果价格低于 100 美元,但周差价小于 2%,那么不要买股票”。他们越有经验,就越看不到 ML 的附加值。

有两种方法,你可以尝试用变速杆。强调当这些权宜的解决方法严重失败时的场景。此外,如果没有其他事情,尝试将你的新 ML 模型与旧算法并行推出,以吸引两种受众——喜欢手动挡的用户和喜欢自动变速器的用户。

概率不是直观的

您可能认为增加输出的可信度会使它更容易理解。例如,ML 输出不是说“购买 APPL 股票”,而是说“以 80%的信心购买 APPL 股票”。可惜概率不是直观的。例如,与 5%和 0%相比,65%比 60%好多少?大家一致认为,把某人的胜算从 0%提高到 5%,比 60%→65%更让人印象深刻。

我们倾向于给 0%→5%的增长赋予不成比例的显著性,这被称为可能性效应。类似地,我们倾向于给 95%→100%的增长赋予不成比例的巨大意义——确定性效应*。*

例子

假设我们有一个 ML 系统,它会对你是否应该购买股票期权提出建议。它提出了两个建议:

购买股票期权 A,有 95%的机会获得 100 万美元 购买股票期权 B,有 100%的机会获得 91 万美元

大多数人会规避风险,选择 B,因为确定性效应,尽管第一笔交易的数学预期更好。

现在假设您的 ML 系统输出另一对推荐:

购买股票期权 C,有 5%的机会获得 100,000 美元 购买股票期权 D,有 100%的机会获得 5,100 美元

大多数人会冒险选择 C,再次无视数学期望。用户的偏见也会根据他们认为自己目前是处于赢还是输的情况而发生巨大变化,这可以用的四重模式来描述。

如果你在你的系统的输出中包括概率,你可能最终会被用户以他们自己的方式重新解释你的 ML 系统的输出,这取决于他们的个人因素。

解决方案之一是完全避免输出概率。例如,假设您的系统预测购买股票期权 A 将获得 1,000,000 美元的回报,其中 100,000 美元是标准差。您可以降低置信度,向用户推荐“购买股票期权 A 以获得 800,000 美元”,这里您忽略了这个推荐有 95%的置信度——2 个标准差。在某种程度上,你不是将评估概率的任务委托给用户,而是自己做决定。好处是用户之间对输出的解释不会有太大的不同。明显的缺点是,你要为自己打电话负责。

控制点

如果用户花时间思考系统的输出,那么参考点可能会出现在你面前。参考点是用户用来比较系统输出的东西。它可能是一些以前的历史数据,一些在过去发生的值得纪念的案例,或者一些他们用来最初测量输出的简单测量。

假设你的旧的简单算法根据股票价格的每日变化给出建议,例如,如果每日变化大于 5%,那么它建议买入。如果你的用户已经使用这个老算法很长时间了,那么他们可能已经开发了一个参考点——价格的每日变化。每次看到股票推荐,他们做的第一件事就是查看价格的每日变化。

你的新机器学习模型可能比旧算法更复杂,因为它可能能够挑选出与价格每日变化无关的其他信号。一旦你向用户提供的推荐没有显著的日常变化,用户可能会认为它们有问题而丢弃它们,你的系统将失去可信度。

了解用户是否有参考点以及参考点是什么非常重要。最好的方法是坐在用户旁边,让他们像平常一样使用你的系统。然后问关键问题:“当你开始查看系统的输出时,你做的第一件事是什么?”。答案很可能是参考点。

分三步走的计划

识别和处理变速杆可以让你照顾那些断然反对切换到 ML 的用户,独立于其质量。在用户界面中避免概率会让你摆脱大范围的人类偏见。有时最好自己打个电话,隐藏信心估计。参考点可能对你的 ML 模型有偏见,识别它将帮助你确保用户对你的 ML 系统有一个公正的评价。

照顾好这三个方面将会大大减少用户反对机器学习的机会。

使用 3D 可视化来调整 ML 模型中的超参数

原文:towardsdatascience.com/using-3d-vi…

这篇文章的大部分是交互式可视化,你可以在上面悬停、缩放和移动。在电脑上阅读比在手机上阅读更好,但手机上的横向模式至少会让你比纵向模式更好地看到情节。

想象一下,你正试图为 Kaggle 的 Rossmann 商店销售竞争开发一个解决方案。你已经做了大量的功能工程,并创造了大量的新变量,这可能有助于你更好地预测未来的销售。

您创建了一个随机森林,并试图找到其最佳超参数。大概有 1000 多种你想要评估的组合。您可以运行随机搜索来分析其中的一个子样本,或者运行网格搜索来探索整个参数网格。

Some of the parameters are evenly spaced on a log scale. You can do that with np.logspace

你做了后者,现在有了一些数据。使用 rf_gridsearch.best_params_ 可以获得在测试集上产生最佳结果的 3 个参数(max_features: 0.25,min_samples_split: 13,n_estimators: 45)。但是,如果你想在三维空间中可视化所有被训练的随机森林的表现呢?

等等,这些流行语是什么意思?

决策树 是一种受监督的机器学习算法,它给定一个数据集,将其递归地划分为具有彼此更相似的目标变量的子集。给定一些带有用于训练它的自变量的新数据,它可以预测因变量。

A decision tree used for regression. Credit: this great post from UC Berkeley

一个 随机森林 (从现在开始的 RF)是一个决策树的集合,这些决策树是在全部训练数据的子集上训练的,并且使用特征的子集。这允许它们具有较少相关的个体决策树,因此它们将更好地概括且具有较少的过度拟合。它们比神经网络训练起来更快,是解决结构化数据的分类和回归问题的一个很好的快速的首次尝试。

我们可以在 RFs 中设置几个超参数。请在 scikit-learn 的文档中阅读所有相关内容。其中一些最重要的是:

  • n _ estimators:RF 中树的数量。
  • min_samples_split:将一个子集(又名节点)再分成两个子集的最小样本数。与最小样本叶和最大深度相关
  • max_features : 分割节点时要考虑的最大特征数(独立变量)

RF 的复杂性随着较高的 n 估计量、最大特征和较低的最小样本分割而增加。

交叉验证是一种用于在机器学习模型中寻找最佳超参数的技术。为了执行它,我们必须将数据分成3 个子集:一个训练集(用于训练模型)、一个验证集(优化超参数)和一个测试集(最后检查模型的性能,就像我们已经在生产中一样)。我们使用一些分数来评估模型的性能,这些分数将根据我们试图解决的问题类型(回归、分类、聚类……)而变化。

A pic is always worth 1000 words!

对于回归, R2 (R 平方)效果很好,是我用过的。一般来说,模型越复杂,训练集中的分数就越好。在测试集上,它也会随着模型复杂度的增加而增加,但在某个点之后,它不会增加,还会减少。我们所做的交叉验证就是试图找到那个点。

好了,我们走吧🔥

在我们的例子中,模型复杂度是 3 个超参数的函数。我们接下来要做的是,尝试可视化在超参数的 3D 网格中找到最佳模型的位置,以及所有组合的表现。请注意,在图中,我使用了词语测试集测试分数,但我指的是验证。

第一:2D 热图

作为一种快速的方法,我们可以用可能的不同参数对绘制热图,以查看在测试和训练集中实现最大 R2 的区域。这可以通过几行代码来完成:

R2 scores for the test sets

R2 scores for the training sets

但是这样做我们仍然只能看到结果的一小部分。为了看到所有这些(并且比热图更清晰),我们需要创建 3D 可视化。

散点 3D

使用 Plotly 我们可以创建各种各样的漂亮的交互式可视化。首先,让我们创建一个 3D 散点图,其中点的大小与训练时间成比例,颜色与测试集中的 R2 分数成比例。

See this in fullscreen mode here

很好,但我们还是看不到太多。我们可以说 max_features 越大,min_samples_split 越小,测试分数就越大,但是很难悬停在 3D 散点图中间的点上。

这样做的代码对于 Medium 来说太长了,但是你可以在这里看到所有的内容

更好:添加滑块

我们有 3 个独立变量,这 3 个参数是我们要优化的。更直观的方法是保持其中一个变量的值不变,绘制测试 R2 分数与其他两个变量的 3D 表面。 这更接近我们习惯看到的 1D 验证曲线,如果我们添加一个滑块来移动第三个变量,我们可以有效地看到与之前的图相同的信息,但以更清晰的方式

Fullscreen mode here.

或者,如果您更喜欢 3D 散点图,以便您可以看到每个单独的点,这就是。点数的大小与训练时间成比例,颜色与 R2 分数成比例。

Fullscreen

最后但同样重要的是…

How the size of the bubbles will be after scaling it.

有一种方法可以显示第一个 3D 散点图,显示所有的点,但使测试分数最高的点比其他点大得多,这样我们就可以专注于它们。这是通过将平均测试分数除以其最大值,并以一种特殊的方式进行缩放来获得我们想要的大小。

最后,如果我们这样做,这就是情节的样子。重要的几点现在看得更清楚了:

This is an image. To see the interactive plot go here

如果我们想更进一步,优化 4 个超参数,我们可以将第 4 个维度作为滑块添加到该图中,就像前面的例子一样,并且能够通过 4 个维度有效地可视化数据。想不到!

点击查看 Python 笔记本中创建这个的代码

玩得开心!

用 Python 中的马尔可夫链语句生成器生成‘真假新闻’。

原文:towardsdatascience.com/using-a-mar…

Photo by rawpixel on Unsplash

实话实说:今天的新闻头条都很疯狂。如果他们关注唐纳德·特朗普,那他们就特别疯狂。有时疯狂到你会问自己它们是否真实!你所读到的是真实发生的事情,还是仅仅是随机收集的单词被做成新闻标题? 需要一个例子?

川普禁止朝鲜进口独角兽

很疯狂,对吧?当然,这个标题是基于女演员艾莉莎·米兰诺的小孩说的话。没有一个成年人会想出如此荒谬的事情…

“根据肖恩·斯派塞的说法,唐纳德·川普是“骑在彩虹之上的独角兽”

哦天啊。对我来说,这听起来像是由一个随机的句子生成器生成的。可惜事实并非如此,我想知道随机生成的新闻标题会有多疯狂(或者是否会如此)。所以我决定构建一个 Python 脚本,自己看看。

该脚本由一个快速的 web scraper 组成,可以获取尽可能多的新闻标题,并在马尔可夫模型句子生成器中使用它们来创建我自己的“真正的假新闻”标题。尽管 Python dictionary 数据类型看起来最初很适合马尔可夫模型,但我想为它使用数据框和熊猫。仅仅是因为我想练习一些熊猫的功能,在这种情况下,我最终对最“优雅”的方式不感兴趣,但我想快速得到结果,并在过程中学习一些东西。首先,我设置了一个脚本,该脚本使用关键字“Donald Trump”访问一个流行的新闻网站。然后,我分离出包含标题的文本,并将它们写入一个文本文件。我发现这个网站对设置我的小代码非常有帮助:

https://real python . com/python-web-scraping-practical-introduction/

在任何一天,这都会给我带来大约 100 到 120 条新闻标题。不错,但是当然这样做一次只能产生很少种类的单词,我的马尔可夫链有陷入一个独特的单词链的风险——在最坏的情况下——只是重复已经存在的新闻标题。谢天谢地,在 Windows 中设置一个任务调度程序很容易,它会每天在后台执行我的文件,让我的文本文件不断增长。我现在要做的就是耐心等待,直到积累了大量的头条新闻。大约一周半后,我有了 1000 多个头条新闻。我认为对于这样一个高度不科学和荒谬的项目来说,这已经足够了。在加载了我的文本文件,并做了一些粗略的清理,消除了一些重复出现的新闻出口签名和双标点符号等。,我终于可以开始把文本放进我的马尔可夫模型了。我决定使用一个单词的前缀或“引导”。我不想详细讨论马尔可夫链,但简单来说,我会总结如下: 对于每个单词,我们收集任何句子中的每个后续单词。基于一个跟随单词与其“对手”相比的频率,我们将分配一个单词跟随某个引导单词的可能性。然后,我们可以从文本中的整个单词列表中随机选择一个单词,然后根据我们指定的可能性随机选择句子中的下一个单词。我们将逐字逐句地创建一个新句子,它基于我们用作输入的文本的属性。真新闻进→真假新闻出。

在将文本文件分割成单个单词并将它们存储在变量‘words’中之后,我定义了一个包含三列的 pandas 数据帧:一列‘lead’定义了前导单词。对于每个引导词,都有一个“跟随”的词,并在我们的第二列‘follow’中被捕获。第三列- ‘freq’ -将显示我们可以在文本中观察到多少次“引导”和“跟随”的特定组合。我们将在这些列中填充什么?嗯,第一列很简单——简单地说,我们文本中的每个单词都将在这一列中写成一行。对于文本中每个索引为 i 的单词,接下来的单词就是索引为 i + 1 的单词。我们简单地从再次用我们的文本填充“follow”列开始,但是这次从文本中的第二个单词开始。对于最初 n 行的文本,这填充了 n-1 “跟随”字。我们文本中的最后一个单词没有自动的追随者,所以我们将使用一个合成的字符串变量来填补空白。我称之为“结束词”(请不要把它与总统在某个神秘的学徒磁带上说的类似的话混淆)。

import pandas as pd
dict_df = pd.DataFrame(columns = [‘lead’, ‘follow’, ‘freq’])
dict_df['lead']=words
follow = words[1:]
follow.append('EndWord')

在继续之前,我将创建一个单独的单词数组,包含每个句子的所有最后的单词。在我后面的代码中,我将使用这些结束词来“自然地”结束我随机生成的句子。这有一个很好的副作用,我不必担心我的马尔可夫链会“穿过”标题,这意味着一个标题的最后一个词不应该被认为是下一个标题的第一个词的线索。毕竟,我不是在处理一个连续的文本,而是在处理一个个独立的句子。通过在我的句子生成器到达这样一个end_word之后对我的句子进行删减,这不应该是一个问题。

end_words = []
for word in words:
    if word[-1] in ['.','!','?'] and word != '.':
        end_words.append(word)
print(end_words)

到目前为止一切顺利。现在,我统计引导词和跟随词的每个组合的出现次数,并使用 group_bytransform 将结果分配给 frequency 列。

dict_df['freq']= dict_df.groupby(by=['lead','follow'])['lead','follow'].transform('count').copy()

这些行仍然不是惟一的,所以在使用 Python 中的 pivot 功能创建一个大矩阵之前,我删除了重复的行,其中每个引导词作为行索引,每个跟随词作为列。然后,行 i 中的引导词和列 j 中的跟随词的组合的频率是该矩阵中的元素 a_ij

dict_df = dict_df.drop_duplicates()
pivot_df = dict_df.pivot(index = 'lead', columns= 'follow', values='freq')

对于每一行,我将所有的频率相加,并将行 i 中的每个元素除以行 i 的总和。这导致百分比总和为 1,当我的句子生成器为某个引导词选择跟随词时,它将用作概率分布。例如,如果在单词“fake”之后,我们观察到 7 次随后的单词“news”和 3 次单词“tan ”,则最终被选择的概率将分别是 0.7 和 0.3。

sum_words = pivot_df.sum(axis=1)
pivot_df = pivot_df.apply(lambda x: x/sum_words)

有了这些,我就可以为句子生成器定义我的函数了。我用一个起始词来初始化句子生成器。这个单词可以是从所有单词的集合中随机选择的单词。但由于我的文本只包含唐纳德·特朗普的标题,我认为确保他的名字也出现在我们的假新闻标题中是有意义的。因此,在我的例子中,我从“唐纳德”开始。从这个单词开始,生成器根据我们设置的概率矩阵选择一个后续单词。它将继续使用所选的跟随单词作为新的引导单词,一个单词接一个单词地添加到我们的句子中。如果句子生成器找到了我们的结束词数组中的一个词,句子将把这个词作为最后一个词并返回我们的句子。如果生成器到达我们之前定义的合成“EndWord ”,它将简单地为引导我们走上这条死胡同的引导词绘制一个新的跟随词。如果我们看到一个结束词,而我们的句子只有两个词长,这同样适用(我有几个例句,上面只有“唐纳德·特朗普”。。就像《唐纳德·特朗普》里那样。—努夫说)。

from numpy.random import choice
def make_a_sentence(start):
    word= start
    sentence=[word]
    while len(sentence) < 30:
        next_word = choice(a = list(pivot_df.columns), p = (pivot_df.iloc[pivot_df.index ==word].fillna(0).values)[0])
        if next_word == 'EndWord':
                continue
        elif next_word in end_words:
            if len(sentence) > 2:    
                sentence.append(next_word)
                break
            else :
                continue
        else :
            sentence.append(next_word)
        word=next_word
    sentence = ' '.join(sentence)
    return sentence
sentence = make_a_sentence('Donald')

仅此而已。

我肯定不会用这段代码赢得(特朗普主持的)选美比赛,但它快速、肮脏、Python-noob 友好,并且完成了工作。诚然,文本越大,分配概率的整个过程将变得越慢,但对于我的示例,它仍然只花了几秒钟,所以我认为还没有必要进行耗时的优化。让我们来看看一些“真正的假新闻”的标题:

唐纳德·特朗普批评特朗普痴迷星战燃烧。 -(听起来似乎有理)

唐纳德·特朗普打破了真正的唐纳德·特朗普忠诚度测试。——(如果发生那种事该有多酷?)

唐纳德·特朗普的团队投诉白人。——(耶…大概不会)

唐纳德胜过最会吹牛的人。 ——【他最差也是)

唐纳德·特朗普的助手们觉得他今年秋天会当选总统。 ——(我们都做……我们都做)

唐纳德·特朗普、罗莎和其他个人,包括第 45 任总统是造币厂的青年。 -(新鲜?)

唐纳德·特朗普,你到此为止。 ——(对我的口味来说可能有点太远)

当然这些都是一些成功的例子。很多句子出来绝对是胡言乱语(不值得 covfefe,但仍然是胡言乱语):

唐纳德·特朗普知道谁是阿撒·富兰克林为尤塔工作的前助手罗莎·马尼高尔特·纽曼。 -(???)

那么,我们从这件事中学到了什么?你作为一个读者,可能不多。但是我对我的代码感到很开心,并且开始用一种我通常不会遇到的结构来处理数据。如果您有反馈或建议,请随时联系我们。谢谢!

附言:

如果你想要一个更复杂的特朗普马尔可夫链,看看这个由更聪明的人制作的随机特朗普推特生成器:

filiph.github.io/markov/

使用人工智能转录从你已经给出的演示文稿中创建博客文章

原文:towardsdatascience.com/using-ai-tr…

在我作为技术顾问的工作中,我最终要向我的公司 Pariveda 的客户、合作伙伴和其他人做很多介绍。我一直在努力寻找更有效地传播知识的方法。科技让这变得容易多了。有了现代的会议软件,你可以很容易地记录你正在向别人演示的东西。在过去的一年左右,我一直采取“记录一切”的方法。如果录音很糟糕,或者我说了不该说的话,我可以删除录音,但如果录音很棒,我可以用它来分享 PowerPoint 演示文稿无法捕捉的深度。

在今年 AWS re:invent 的筹备阶段,我花了很多时间与客户一起工作,帮助他们计划他们的一周,使用我整理的快速卡片来记录我的提示&技巧。我在网上搜索,看看是否还有人提供同样的建议,结果一无所获。我觉得这是一个写博客来填补空白的好机会。然而,我是一个非常慢的作家,所以我不想从零开始。

AI 来救援了!随着 AWS 的最新进展,我可以在几分钟内获得录制的演示文稿的转录,并且只需支付1 美元即可获得 40 多分钟的转录(在免费的 60 分钟/月之后)。我一直在想如何应用人工智能来帮助我提高效率,所以我采用了以下流程来构建这个帖子:

  1. 制作一个演示文稿,亲自进行演示
  2. 录制演示文稿(即使用网络会议软件或手机)
  3. 使用人工智能转录工具,如亚马逊转录从画外音获取文本
  4. 将文本复制到博客平台,添加幻灯片中的图像,并调整语气,使其看起来像一篇博客文章

4 steps to build a blog post from what you’re already presenting

使用这种方法,我能够在大约一个小时内完成一篇 1300 字的中型文章。在这篇文章中,我将向你介绍我使用的过程,并讨论一些我认为可以使用的其他方法。让我们开始吧…

第一步:制作一份精彩的演示文稿,

在这种情况下,我在当天早些时候向 Pariveda 的观众演示了最大化 re:invent,演示被录制下来,以便其他人可以在以后观看。我确信几乎每个阅读这篇文章的人都做了很棒的演讲,所以我把这部分留给你。你不一定需要幻灯片演示,白板会议或只是一个讲座就可以了。

第二步:向某人演示,并记录演示过程

有很多方法可以记录你这些天说的话。如果您正在演示幻灯片,您可以使用公司的软件轻松启动网络会议,并以这种方式录制音频和幻灯片。Pariveda 使用 zoom 进行网络会议(旁白:Zoom 是高质量视频会议的一个很好的工具),所以我使用 Zoom 来获得这个记录。如果你只是想要音频,你可以使用 iOS 上的内置语音备忘录应用程序或 Android 上的 Google Keep 来录制音频。关键是要获得音频记录文件,这样你就可以转录它,使你的职位。

Recording of the presentation video from Zoom

步骤 3:使用人工智能转录演示文稿

所有三大云供应商都提供人工智能转录服务( AWS微软谷歌),许多其他供应商也是如此。在这种情况下,我正在为 AWS re:invent 做一个帖子,所以使用 AWS Transcribe 才有意义。为了使用这项服务,我首先将录音上传到 S3。接下来,我创建了一个指向该文件的新转录作业(您可以在控制台中完成)。

Creating a new Transcription Job

这将创建一个需要几分钟运行的作业。

Job completes after a few minutes

当作业完成时,您将能够找到并下载输出文本。在这种情况下,它运行了大约 6 分钟,并将结果文件放入我们的 S3 桶中。

{
    "TranscriptionJob": {
        ...,
        "Transcript": {
            **"TranscriptFileUri": "**[**https://s3.amazonaws.com/transcriptions-pariveda-chicago/Transcribe-reInvent-guide.json**](https://s3.amazonaws.com/transcriptions-pariveda-chicago/Transcribe-reInvent-guide.json)**"**
        },
        "CreationTime": "2018-11-14T20:35:20.418Z",
        "CompletionTime": "2018-11-14T20:41:02.633Z",
        "Settings": {
            "ChannelIdentification": false
        }
    }
}

当您下载 JSON 时,它会在一个名为**“抄本”**的字段中提供实际文本,该字段可用于从音频中捕获原始文本。

{
  "jobName": "Transcribe-reInvent-guide",
  "accountId": "336843223770",
  "results": {
    "transcripts": [
      {
        "transcript": "Sure. All right, so the biggest thing that i found last year reinvent was because **he's** grown so big..."
      }
    ],
    "items": [
      {
        "start_time": "1.954",
        "end_time": "2.304",
        "alternatives": [
          {
            "confidence": "0.5040",
            "content": "Sure"
          }
        ]
...

在浏览文档的过程中,您可能会发现一些特定的错误,这些错误基于您的讲话模式是非常常见的。我喜欢将内容复制到文本编辑器中,使用查找-替换来纠正单词,而不是那些人工智能一贯误认为这些单词的单词。此外,您还可以在此时向文本中添加段落。这也是更新你的自定义词汇的好机会。

另一个旁注:通过这个过程我学到的一件事是,我在我的谈话中经常使用“所以”这个词。我现在正在努力减少这种使用。

步骤 4:将文本复制到博客平台,添加幻灯片中的图像,并调整语气,使其看起来像一篇博客文章

现在您已经有了文本形式的演示文稿的编辑版本。你所需要做的就是添加一些图片,使帖子更有趣,并调整流程,使其感觉更像是书面的而不是口头的。这花了我大约一个小时,但这是我第一次经历这个过程。我希望接下来的几个会花更少的时间。

如果你有兴趣分享如何加快将有思想的内容发布到网上的技巧,请直接联系我或在评论中联系我。

利用数字实验数据进行方差分析

原文:towardsdatascience.com/using-analy…

单向方差分析(ANOVA)用于确定两个或两个以上独立(不相关)组的均值之间是否存在任何统计上的显著差异(尽管你倾向于只在至少有三个而不是两个组时使用)。

从以前的学者生涯进入数字分析领域——学习了生物力学和统计学——我有很多问题,关于我以前学到的统计技术如何融入我的“日常工作”。鉴于 Optimizely 的统计引擎使用连续的 AB 测试方法来比较两个或更多独立组的平均值,没有理由(只要流量允许)不能对分段数据执行方差分析(ANOVA ),以检测人口统计数据、设备、平台或区域数据之间的统计差异。

为此,本文将既是对这些方法的探索性报告,也是如何执行这种分析的逐步说明,前提是您已经与 AB 供应商建立了分析集成。

首先,确保你的分析集成正确地标记了然而你的流量是通过你的实验供应商节流。通过这种方式,您将能够拥有一个初始段,该段根据实验条件(即您正在执行分析的变化)来分离您的数据。确保您正确实施了标记,也意味着您可以跟踪您的指标。这对于 ANOVA 如何收集和组织数据至关重要。数据将处于浏览器级别(每个用户的单独数据点),但出于本指南的目的,我将数据导出显示为未折叠,因此您可以看到我将测试的组。为了这个分析的目的,我将着眼于我的一个实验组/变体的设备/平台比较;我们就叫它AAT7:

当这些数据折叠起来时,您可以看到各个浏览器和各种指标的性能。出于本指南的目的,我已经忽略了各个浏览器 ID。我不太擅长用颜料,所以我用山谬·里维的《突破点》把它们抹掉了:

在本文中,我将使用我们的每个浏览器的内容条目指标。通过进行 ANOVA,将计算该指标的平均值,因此对于我们的 AA 条件,我们将得到每个设备/平台的每个浏览器的平均内容项。这将告诉我们,对于该实验条件,每个设备/平台之间是否存在统计上的显著差异;这可以提供关于设备如何针对这种特定的 web 变化而执行的更加精细的统计分析。然后,您需要从您的分析工具执行数据下载,删除浏览器 ID(现在不需要 Keanu)和任何不感兴趣的指标。对于这种形式的分析,我将使用 R, so import your。csv 或。xlsx 到您的 R 环境中:

我们现在将执行单向 ANOVA,从而在实验组(设备/平台)之间比较相同的指标(每个浏览器的内容项目))。在 RStudio 中,你需要安装“stats”包。在某些时候,您可能希望开发一些脚本来自动处理数据,但对于本指南,您可以使用以下语法来执行单向方差分析:

您会希望将其分配给 R 中的一个新项目,这意味着您可以执行汇总分析以及可视化和事后程序:

对您的新项目调用 summary 将会得到以下输出:

您可以看到 R 为您提供了重要的代码,因此您可以分析 ANOVA 的总体效果。在这种情况下,我们寻找一个小于 0.05 的 p 值来检测统计上显著的影响。正如所见,我们在这个实验中的 p 值小于 0.001,这意味着我们在这个方差分析中有一个非常显著的 p 值。因此,我们可以自信地得出结论,在这个实验条件下,设备/平台类型和每个浏览器的内容项之间存在显著差异。确定统计分析如何帮助您对细分市场进行更精细的分析。

然而,这种整体输出并没有告诉我们显著差异在哪里,因此我们可以执行 Tukey 多重成对比较(事后分析),这是一种可以识别差异存在的工具。其语法和输出应该如下所示:

从上面的输出可以看出,对于我们的 AA 变量( p < 0.05),移动设备的表现明显比平板电脑和电脑差。这为我们提供了关于该实验条件下这些设备/平台之间的统计差异的宝贵信息。由此我们可以得出 UX 对这种变化的考虑;这可能是因为 AA 在移动设备上存在可用性或功能性问题(例如,它无法正确适应屏幕,它可能会在页面上移动项目)。这种分析意味着您可以将结果提供给利益相关者,他们随后可以执行后续的 web 分析,以评估移动设备性能如此之差的原因。

我很快在 ggplot 中绘制了一个图(请安装 ggplot2 来执行这个分析),只是为了描绘出这些数据绘制时的视觉效果。使用 stat_compare_means ,您可以将方法设置为“anova ”,这将在您的图上显示您的 p 值:

我知道上面的图显示了一些明显的统计异常值,我们将来可能会忽略这些异常值;但我只是想从视觉角度展示数据可能是什么样子——正如您可以看到的,移动设备的性能明显比其他设备差。我将在不久的将来发表一篇关于数据清理的文章。类似地,在执行方差分析之前,您还将调查您的数据的分布——这将是我将来与大家分享的另一篇文章。我要强调的是,这只是一个基本的一步一步的方法,你可以通过数字数据下载对你的细分市场进行统计分析。本文中讨论的方法可以帮助您更客观地描述不同变化下的细分市场表现,而不是单独呈现趋势和提升。

我期待每个人对这份报告的建设性反馈。我期待在不久的将来,随着更多 90 年代动作片英雄的出现,浏览器 id 将会消失。

使用分析进行更好的决策

原文:towardsdatascience.com/using-analy…

日益复杂的世界、数据的大规模扩散以及保持竞争前沿的迫切愿望促使组织关注使用分析来推动战略业务决策。商业分析使经理们能够了解他们业务的动态,预测市场变化和管理风险。在维护库存、定价解决方案或招聘人才时,公司不再“凭直觉”,而是采用分析和系统的统计推理来做出提高效率、风险管理和利润的决策。

数据和分析正在破坏现有的商业模式和生态系统。新数据集的激增和大规模数据迁移功能的引入正在破坏现有的信息和技术孤岛。从使用粒度数据来个性化产品和服务,到扩展数字平台来匹配买家和卖家,公司正在使用业务分析来实现更快和基于事实的决策。事实上,研究表明,数据驱动的组织不仅可以做出更好的战略决策,还可以获得更高的运营效率、更高的客户满意度以及强劲的利润和收入水平。最近的研究还表明,以数据为中心的组织获得客户的可能性增加了 23 倍,保留这些客户的可能性增加了 6 倍,盈利的可能性增加了 19 倍。

今天的分析从业者拥有大量的分析能力和技术。这些技术包括最基本的技术,“描述性分析”,涉及为后续分析准备数据,到“预测性分析”,提供先进的模型来预测和预测未来,到顶级的分析,称为“规定性分析”,利用基于机器的学习算法和动态规则引擎来提供解释和建议。凭借其多样化的使用案例和应用,这些技术现在在组织层面上进入客户、劳动力、供应链、财务和风险战略已不再令人惊讶。

数据是新的石油,公司获取和理解数据的最佳方式是数字化他们的流程。数字化客户互动可以提供大量信息,公司可以将这些信息反馈到战略、销售、营销和产品开发中。详细和精细的数据可以使公司微定位他们的客户,并个性化他们的产品和服务。进一步的内部数字化生成了管理人员可以用来改善其运营的数据,包括路线和运输、资源分配和调度、产能规划和制造。这些趋势也导致许多公司在预测和高级分析的共同基础上融合他们的“商业智能”和“运营研究”部门。这两个团体现在都在使用统计和数学技术来解决战略性的商业问题,并使决策系统化。

数据分析凭借其深远的使用案例和多样化的应用,正在成为战略业务决策的基石。从帮助企业做出面向消费者的营销决策,到帮助他们解决关键的运营效率低下问题,分析正在从根本上改变人们对数据重要性的认识。先进的统计模型通过从非常规数据集提供有价值的见解,并使公司能够探索新的业务领域,进一步推动了这一事业。接下来的几个部分将探讨数据和分析给当今企业带来的巨大而多样的机遇。

充分利用消费模式:

在一个日益以客户为导向的时代,组织积累了大量的消费者信息和数据。为了保持竞争力,组织必须利用这些消费者洞察来塑造他们的产品、解决方案和购买体验。麦肯锡(Mckinsey)的研究表明,战略性地利用消费者行为洞察的组织,其销售增长利润率比同行高出 85%,毛利润高出 25%以上。因此,对管理者来说,考虑消费者信息的战略重要性是很重要的。

通过深思熟虑的市场细分对客户进行全面而精细的了解,可以为经理提供关于购买习惯和偏好的深刻见解。例如,一家电信公司可以使用先进的预测分析模型来减少客户流失并衡量营销活动的有效性。类似地,在线零售商可以通过寻找新老访问者的组合、跳出率和平均会话持续时间等问题的答案来了解其网络存在。这些问题提供了重要的见解,让我们了解什么类型的内容、通过什么渠道和形式可能对关键的消费群体产生最大的影响。

此外,模式数据还可以生成有价值的客户洞察,用于指导营销支出。例如,一家汽车销售商研究了其消费者的购买和行为历史,发现其大部分高端消费者更有可能依赖经销商分销商的产品推荐,而不太可能受贸易展览和营销宣传材料的影响。这反过来帮助营销人员重新分配预算。因此,商业分析使管理者能够获得关于市场条件的竞争情报,更成功地锁定消费者并优化流程。

利用数据推动绩效:

虽然组织花费大量时间分析消费者数据和一线盈利机会,但同样重要的是专注于提高生产力和绩效。数据和分析在降低效率和简化业务运营方面可以发挥巨大作用。例如,报告和分析仪表板可以识别数据相关性,并为经理提供详细的见解,以执行成本评估、同行基准和定价细分。同样,使用分析来衡量卓越运营、产品创新和劳动力规划等领域的关键绩效指标,可以产生经过计算的见解,以解决复杂的业务场景。

商业分析还可以改善组织吸引、保留和发展人才的方式。例如,亚洲的一家咨询集团最近决定进行重大重组。作为该计划的一部分,领导层希望确定具有高度成功潜力的员工,并更好地了解关键绩效指标。分析团队首先简化数据点,如职业历史、教育背景、绩效、年龄、婚姻状况和人口统计数据。在通过多元回归模型运行整理后的数据后,团队能够确定在特定角色中最有机会成功的员工档案。研究和分析还提出了对公司整体增长影响最大的关键角色。因此,公司围绕关键职能角色和人才群体进行了重组。

数据分析提供独特价值主张的另一个领域是供应链。供应链是寻找战略机会和优势的好地方,部分是因为它们错综复杂的性质,部分是因为它们对公司成本结构的重大贡献。通过使用分析,公司不仅可以识别现有结构中隐藏的低效率,以实现更大的成本节约,还可以通过执行风险建模和评估来分析重要的供应链投资和决策。然后,管理人员可以深入研究具体的改进机会,如库存管理、渠道管理、采购和物流。

通过分析管理风险:

如今,组织面临着来自结构化数据(如数据库)和非结构化数据(如网站、博客和社交媒体渠道)的巨大风险。通过利用风险分析,公司可以更好地量化、衡量和预测风险。管理人员需要将风险分析视为一种企业范围的方法,并应开发将不同组织级别和职能的数据整合到一个中央平台的方法。通过建立衡量和管理风险的标准基线,公司将能够将风险考虑纳入其核心战略决策过程,并预测可能的情况。

银行正在通过发现利用交易和行为消费者数据的新方法来引领这一分析领域。事实上,他们通常会超越传统的结构化信息,如信用评分报告,并且还会寻找非常规的信息来源,如会员卡消费者数据和政府信息。通过获取如此庞大的数据集,银行能够提高其信贷风险模型的准确性、覆盖范围和可预测性。从在执行前识别高风险付款到预测客户拖欠抵押贷款付款的可能性,风险模型通过提供先进和有价值的见解而处于领先地位。因此,公司应该专注于增强和探索运营商业模式。

高级数据模型将使有风险的业务决策更加统一,提高数据质量,并提供更大的灵活性来满足非常规的数据需求。通过提高风险意识,管理者将更善于应对不确定性,并更善于战略性地做出决策。

结论:

在这种由数据驱动的动荡环境中,业务经理需要同时透过两个镜头来看问题。首先,他们必须识别高风险和有回报的机会,如进入新的市场和改变现有的商业模式。其次,他们必须继续关注将分析纳入其核心业务决策流程。通过将数据分析嵌入其核心战略,业务经理可以简化内部业务流程,识别消费者趋势,解释和监控新出现的风险,并建立持续反馈和改进的机制。推动分析转型将因此使公司获得竞争优势,并站在数字颠覆的最前沿。

参考资料:

  1. 分析时代:在数据驱动的世界中竞争
  2. 捕捉数字消费者
  3. 风险分析三分钟指南
  4. 数据分析和劳动力战略对绩效改善和税收效率的新见解
  5. People analytics 揭示了人力资源可能犯的三个错误
  6. 从您的客户数据中获取价值

使用 API 和 Google Sheets 评估梦幻英超的前景

原文:towardsdatascience.com/using-apis-…

我是一名狂热的 FPL 球员,使用梦幻英超的 API 和 Google Sheets 来轻松分析球员数据。

你可能会因为不得不依赖他人的零星数据(例如,进入梦幻英超 Reddit )而感到沮丧,并想要做自己的分析。

使用 Fantasy Premier League API 和一个电子表格工具,我们可以将球员数据加载到 Google Sheet 中,并过滤不同的选秀权、总得分、每场比赛的得分等等。

电子表格的伟大之处在于,几乎每个人都知道如何在某种程度上使用它们,而且通过对 Google Sheets 进行一些非常小的修改,就可以很容易地使用 Google Sheets 的 API,所以如果你不是技术人员,这不是问题。

在这之后的下一步将是真正地将数据加载到像 Tableau Public 这样的工具中以评估数据,但现在我们只想得到数据并开始使用它。如果对 Tableau 公共教程有足够的需求,我也会写的,所以如果你想看的话,请鼓掌或者回应。

设置 Google 工作表

我们要做的第一件事是在谷歌工作表中设置一个新的工作表。重要的是使用 Google Sheets 而不是 Excel 之类的东西,因为 Google Sheets 是可脚本化的,通常更擅长处理与互联网交互的东西,如 API。Excel 并不是真正为一个必须与互联网对话的世界而设计的。

我在这里使用了几个技术术语,因此,对于外行来说,API 是从数据库访问数据的常用方法(我们将使用的 API 被 FPL 用来生成他们的球员信息屏幕), JSON 是输出这些数据的标准格式。技术专家喜欢 JSON,因为它受到许多不同平台的支持,它有简单的标记,格式化后很容易阅读和查询。

但是 Google Sheets 不支持现成的 API 或 JSON,所以我们需要添加一个脚本,该脚本可以获取 API URL (Fantasy Premier League 的数据提要)并以 JSON 格式返回我们想要的数据,然后将其格式化为我们可以阅读的电子表格。

做到这一点真的很容易。

转到工具>脚本编辑器

然后,您应该会看到这样的屏幕:

首先,您希望删除 Code.gs 文件中的所有内容,因此它是空白的:

接下来,我们将重命名该文件:

我们将把它命名为“ImportJSON”

您的屏幕现在应该看起来像这样:

接下来,转到这个 pastebin,将所有内容复制到那里,并粘贴到 ImportJSON 文件中。屏幕现在应该看起来像这样:

我们已经完成了这里的工作,是时候回到我们的 Google 工作表并加载数据了。点击文件>保存保存我们的功能。

我们刚才所做的实际上是向这个 Google Sheet 添加一个名为 ImportJSON 的新函数,我们现在就要使用它。

返回到您的电子表格,它应该在另一个选项卡中打开。

使用 ImportJSON 提取梦幻英超 API 数据

现在,我们将使用刚刚创建的函数从梦幻英超 API 中提取数据。

在电子表格中,将此公式复制到单元格 A1:

= ImportJSON("【fantasy.premierleague.com/drf/bootstr…")

重要提示:在敲 enter 之前,复制最后一个引号(在 bootstrap-static 之后),替换掉 https:// 之前的花引号,否则会出错。Medium 自动将引号转换为花引号,Google Sheets 无法识别。

注意:这个 API 没有被 FPL 官方记录或以任何方式支持,并且它会随着 FPL 网站的更新而不断变化。然而,这个特殊的 API 端点在过去的几个赛季中工作得很好,所以希望这个继续工作。如果我发现它坏了,我会进来更新这个帖子。

修改后的公式应该如下所示:

你会知道它起作用了,因为配方已经变绿了。然后你应该按回车键。如果你看到的不是上面的内容(比如公式后面的引号),Google Sheets 已经破坏了这个公式,你应该再次粘贴这个公式。

然后,电子表格应该在第一个单元格中显示“正在加载”。不要担心当你悬停在上面时它会显示错误,Google Sheets 只是有一个想法:

如果一切正常,数据应该已经加载到您的电子表格中,并按照每个玩家的数字 ID 进行排序。每个球员在整个赛季中都持有自己的 ID,这对于与其他数据源进行交叉引用非常有用,所以我不会删除“元素 ID”字段。

Google Sheets / Excel 中的数据分析

我们就快成功了,但是在我们开始分析数据之前,还有几个重要的步骤要做。

我们需要做的第一件事是将这些数据复制到一个静态电子表格中。尽管 ImportJSON 非常擅长从 API 中提取数据,但它往往在排序和过滤数据方面有问题。

ImportJSON 还有一个令人讨厌的倾向,那就是不断尝试刷新数据,这使得处理起来很麻烦,并且很快就会达到 API 的极限。使用静态文档更容易(也更快),因为它不会不断地试图下拉数据。

旁白:不过,有帮助的是,你可以在每个游戏周之后回到谷歌电子表格(把这个放在你的谷歌硬盘里),它会提取最新的数据。我不建议在比赛周进行的时候这么做,因为我们都知道 FPL 在比赛周进行的时候似乎有问题。

不过,获得静态工作表的最简单方法是简单地将数据下载为 Excel 电子表格。这样,您就可以利用 Excel 的优势——处理相对大量的数据而不会出现延迟。

如果您确实想使用 Google Sheets 中的数据,您可以随时将数据导入到 Google Sheets 中,就像我在这里所做的那样。

您将会看到单元格 A1 现在是#NAME,因为这个新的电子表格不知道“=ImportJSON”是什么(保存时函数不会被转移)。请随意将该字段更改为 ID。

字段标题应该是不言自明的(包括一些看起来非常有趣的标题),一旦你进入静态电子表格,你可以随意修改。

您的第一步应该是设置一些过滤器:

  • 按每场比赛的点数排序(AJ 列)
  • 将列 AJ 转换为数字列(格式>数字),并过滤掉小于 4 的行。
  • 将“元素选择方式”转换为数字列(“格式”>“数字”),并过滤到 15%以下(如果您正在寻找差异)。

你也可以在不同的栏目中进行计算来制定你自己的标准,设置条件格式来突出显示符合特定条件的绿色玩家,或者过滤列表来匹配你在 FPL 的观察列表。

除了 Excel/Google Sheets,下一步将是使用 Tableau 之类的工具来绘制数据图表。这方面的一些高级示例如下:

就是这样。现在你有数据知道是否真的值得在卡尔弗特-勒温身上下注,或者是否真的值得在阿圭罗身上花额外的钱而不是耶稣。

现在去看看剩下的列,过滤/排序到你的心满意足。即使您没有在 Tableau 中创建图表,这也会给您一些数据,帮助您研究您的选择。

使用 Bagging 和 Boosting 提高分类树的准确性

原文:towardsdatascience.com/using-baggi…

Bagging 和 boosting 是两种可以用来提高分类回归树(CART)准确性的技术。在这篇文章中,我将从我在早期文章中开发的单个 90+点葡萄酒分类树开始,并将其分类精度与两个新的袋装和提升算法进行比较。

因为打包和提升都依赖于分类器的集合,所以它们被称为“集成”方法。这两种分类器本身都不是一种分类器,而是通过聚合其他几个子分类器的预测来产生分类预测。

我将再次使用从《葡萄酒爱好者》杂志上搜集的葡萄酒评论数据,该杂志可在 www.kaggle.com/zynicide/wi…免费获得。它包含了 150,000 种葡萄酒的分数,以及每瓶葡萄酒的价格、酒厂、产区、品种&等信息。对于这个项目,我将只使用美国种植的葡萄酒。

首先,我将使用 sci-kit learn 的 DecisionTreeClassifier 对我的 70%的数据(训练样本)训练一个单一的分类树,无需超参数调整。这将作为未来合奏表演的基准:

制袋材料

Bagging 使用了一种简单的方法,这种方法在统计分析中反复出现——通过合并多个估计值来改进一个估计值。Bagging 使用训练数据的引导抽样构建 n 个分类树,然后组合它们的预测以产生最终的元预测。

Sci-kit learn 实现的 bagging ensemble 是 BaggingClassifier,它接受一个基础分类器的名称作为输入,bagging ensemble 将复制该分类器 n 次。BaggingClassifier 的主要调整超参数是在元预测中创建和聚合的基本分类器的数量。

以下是 bagging 系综在改变(1)基本估计量的数量和(2)基本估计量的大小(叶子的数量)时的表现:

如上所示,bagging 预测精度对基础估计量的限制很敏感。在实践中,限制基估计量的大小在 bagging 系综中是多余的,因为 bootstrap 抽样获得了与限制基树相似的结果。

另一个关键的观察是,bagging 集成的性能不会超过单一 CART 基准,直到估计器的数量超过阈值水平。单树装袋集成的准确性比单个 CART 差很多——如果你问这是怎么回事,可以用 bootstrap 采样来解释:由于 bootstrap,单树装袋集成中的基本估计器不会使用 100%的训练数据。Bootstrap 采样是一种可调参数的 bagging 分类器。

助推

为了展示 boosting 方法的功效,我将使用 AdaBoost,它在 sci-kit learn 中实现为 AdaBoostClassifier。这种类型的集成创建了 n 个基本估计量,就像 bagging 一样,但它是以迭代的方式实现的,如下所示:

  1. 使用正常方法训练基于估计值#1
  2. 观察基础估计器#1 错误预测的训练数据样本,并为这些样本创建权重 D>1.0
  3. 训练基础估计量#2,在计算同质性基尼/熵度量时将权重 D 应用于样本
  4. 重复 n 次。

通过这种方式,增强创建了连续的基本分类器,这些基本分类器被告知对来自训练数据的误分类样本给予更大的重视。像 bagging 一样,来自所有提升基本分类器的结果被聚集以产生元预测。

与 bagging 相比,boosting 集成的精度随着基估计量的增加而迅速提高。此外,在我的示例中,无论基础估计器是终止的树桩还是完整的树,提升集成的精度都收敛到超过估计器数量= 15+时的原始 CART 精度。

Boosting 和 bagging 是两种能够从分类算法中挤出额外预测准确性的集成方法。使用任一方法时,应仔细调整超参数,以找到模型灵活性、效率和预测改进的最佳平衡。

[## dasotelo/Wine_Bag_Boost.py

github.com](github.com/dasotelo/Py…)

将 Bash 用于数据管道

原文:towardsdatascience.com/using-bash-…

作为一名数据科学家,使用 bash 脚本创建数据管道非常有用。这些脚本的可能性几乎是无限的,但是在这里,我将通过一个非常基本的 bash 脚本来下载数据并计算数据集中的行数和列数。

一旦你掌握了使用 bash 脚本的诀窍,你就可以拥有创建物联网设备的基础,以及更多,因为这一切都与 Raspberry Pi *一起工作。*有一个很酷的项目,你可以用它来使用 twitter api 下载你所有的 twitter 消息,然后预测 twitter 上某个用户的消息是否是垃圾消息。它可以在你房间的树莓 Pi 服务器上运行!不过这有点超出了本教程的范围,所以我们将从查看旧金山的 汽车速度数据集开始!

此外,获取实时数据的能力、复制结果的能力对于数据科学来说是非常必要的。在本教程中,我将向您展示如何使用 bash 和 Unix 命令创建数据管道,然后您可以作为数据科学家在工作中使用这些命令

先决条件

  1. 熟悉命令行(知道如何创建目录、更改目录和创建新文件)
  2. Linux 或苹果电脑
  3. 互联网连接

目标:创建一个 bash 脚本来完成以下任务

  • 从在线资源下载数据
  • 计算数据中的行数
  • 记录数据中列的名称
  • 遍历多个文件并给出所有这些信息

第 1 部分:下载数据文件

对于本教程的第一部分,假设我们正在使用 旧金山限速数据 ,我们想通过命令行创建我们的整个管道。我们需要开始为这个作品创建一个文件夹,我称之为cars_pipeline

要在 Unix 中做到这一点,您需要在命令行上执行以下命令:

  • 制作目录

mkdir cars_pipeline

  • 搬进新主任

cd cars_pipeline

一旦我们进入这里,我们将创建一个新的 bash 脚本,我称之为:download_data.sh你可以随意命名,只要它以扩展名.sh结尾

  • 创建文件的命令是:

touch download_data.sh

现在我们已经创建了这个文件,我们将把数据下载到我们正在工作的文件夹中。为此,我们将使用名为 nano 的文本编辑器。

  • 为了在 nano 中打开我们的文件,我们在命令行中执行以下命令:

nano download_data.sh

一旦打开它,您将通过粘贴以下代码来创建您的第一个 bash 脚本:

  • 除了 #,带#的文本都是注释!/bin/bash ,它被称为 shebang ,是每个 bash 脚本所必需的
#!/bin/bash # Command below is to download the data
curl -o speed.csv https://data.sfgov.org/api/views/wytw-dqq4/rows.csv?accessType=DOWNLOAD

要保存:

  • 控制+ o
  • 进入
  • 控制+ x

现在我们已经保存了文件,让我们来看看这个用来下载数据的大命令:

curl -o speed.csv https://data.sfgov.org/api/views/wytw-dqq4/rows.csv?accessType=DOWNLOAD

  • curl是下载命令
  • -o是输出的 a 标志
  • speed.csv是输出名称
  • [https://data.sfgov.org/api/views/wytw-dqq4/rows.csv?accessType=DOWNLOAD](https://data.sfgov.org/api/views/wytw-dqq4/rows.csv?accessType=DOWNLOADis)是下载数据的网址

现在,要下载,我们只需在终端中使用以下命令运行 bash 脚本:

bash download_data.sh

如果您现在查看该文件夹,您将看到您已经下载了文件 cars.csv!

如果您对此有任何疑问,请询问,您可以随时通过替换 url 来下载不同的文件。同样,您可以向脚本传递一个命令行参数,这样您就可以使用该脚本下载您想要的任何数据。

这个脚本非常简单,所以让我们转到一个稍微难一点的脚本,它会告诉我们数据集中的行数和列数。

第 2 部分:为所需信息解析文件

在这里,我们将创建一个更复杂的脚本,这将更深入。我将仔细检查每一行,解释它是做什么的,然后在最后把它们作为一个脚本放在一起。

我将第二个脚本命名为:process_data.sh,您可以随意命名,只要它以扩展名.sh结尾。

您将使用与上面相同的过程来编辑和保存您的 bash 脚本。您可以跟随文章,或者向下滚动并使用 nano 复制整个脚本。

第一行:shebang

#!/bin/bash

我们将把文件名作为命令行参数传入,并用我们的结果保存一个文本文件。因此,我们将使用一个名为echo的命令,它打印出跟随其后的值。为了访问参数,我们将列举它们,第一个是$1,第二个是$2,依此类推…

我们希望它保存文件的名称,因此我们将使用命令:

echo "The name of the file is:" $1

现在,我们将使用以下命令来计算 csv 中的行数:

lines=$(wc -l < $1)echo "The file has" $lines "lines"
  • 我们创建了变量 lines 来计算我们作为命令行参数传入的文件中的行数!更多关于 wc 命令 的信息,请点击
  • 然后我们打印出文件的行数!

接下来,我们将从 csv 文件中获取列名!为此,我们将在 bash 脚本中使用以下命令。

colnames=$(head -n 1 < $1)

这将创建一个变量,其中只包含 csv 的第一行!将所有这些放在一起(以及我添加的一些内容,以便日期自动填充到文本文件中),我们得到以下脚本:

#!/bin/bashecho "Data Processed by Elliott Saslow"DATE=`date +%Y-%m-%d`echo "Date is: "$DATEecho ""echo "The name of the file is:" $1echo ""lines=$(wc -l < $1)echo ""echo "The file has" $lines "lines"echo ""colnames=$(head -n 1 < $1)echo ""echo "Column names are: "echo ""echo $colnames

现在,要运行该脚本,我们像上面使用 nano 一样保存它,并在命令行中使用以下命令运行它:

bash process_data.sh speed.csv > text.txt

该命令执行以下操作:

  • 调用脚本
  • 传递我们正在查看的文件(speed.csv)
  • 将输出传递给一个名为text.txt的文本文件

如果您运行了这个程序,并且正确地完成了其他所有工作,那么您的文件夹中就会有一个文本文件,它包含质量控制检查的开始,您可以将它用于您的数据管道!

请在评论中告诉我你在哪里遇到了困难,以及我可以如何帮助你!

干杯

利用双向生成对抗网络估算市场风险管理的风险价值

原文:towardsdatascience.com/using-bidir…

我们将探索双向生成对抗网络(甘比)在市场风险管理中的应用:评估投资组合风险度量,如风险价值(VaR)。生成敌对网络(GAN)允许我们隐式地最大化复杂分布的可能性,从而允许我们从这种分布中生成样本——这里的关键点是隐式最大似然估计原理,由此我们不指定这种复杂分布被参数化为什么。在许多其他金融服务用例中,处理可能来自复杂分布的高维数据是市场风险管理的一个关键方面。GAN,特别是本文中的,将允许我们处理潜在的复杂金融服务数据,这样我们就不必显式指定分布,如多维高斯分布。

市场风险管理:风险价值(VaR)

风险值是对投资组合风险的一种度量。例如, -5%1% VaR 意味着有 1%的机会获得低于 -5% 的投资组合回报。把它想象成投资组合回报分布的(较低)百分位或分位数,也就是说,我们关心的是尾部风险——损失非常大的投资组合价值的小概率。如此巨大的损失是由我们自己的资金来弥补的,也就是说,与其他人的资金相比,资本是一种昂贵的资金来源,也就是债务。因此,风险值的估计和类似的市场风险管理措施告知银行和保险公司他们需要持有的资本水平,以便缓冲意外的经济下滑——市场风险。

出于我们的目的,让我们从从 Yahoo 获取 5 只股票的数据集开始。股票有苹果、谷歌、微软、英特尔和 Box。我们对 2016 年的数据使用每日频率。我们使用股票的每日收盘价来计算连续复利:

让我们假设我们投资组合中的 5 种资产的权重相等。基于这个投资组合权重的假设,我们可以计算投资组合的回报。

让我们估计预期收益向量、波动向量、相关性和方差-协方差矩阵。方差-协方差矩阵从估计的波动率向量和相关矩阵中恢复:

在哪里

是哈达玛的产品。

投资组合波动估计为:

我们考虑市场风险管理中使用的 3 种主要方法,特别是对 VaR 的估计。请注意,有多种不同的方法来估计风险值和其他更一致的风险衡量指标,如条件风险价值(CVaR),但是我们只考虑少数几个主要的方法。

VaR:方差-协方差法

第一种是方差-协方差方法,使用估计的投资组合波动率

在高斯假设下估计 VaR。让我们假设我们试图估算 1%的 VaR:这意味着有 1%的概率获得低于 VaR 值的投资组合回报。使用方差-协方差方法,计算如下:

VaR:历史模拟法

第二种方法是一种非参数方法,我们从历史数据中进行替换采样,以估计投资组合的回报分布。1%的风险值只是这个投资组合回报分布样本的适当分位数。

VaR:蒙特卡罗方法

第三种方法是使用上述方法从多维高斯分布进行蒙特卡罗采样

最后,1%的 VaR 仅仅是这个投资组合回报分布样本的适当分位数。

VaR:估计值

对于我们的股票回报数据,来自上述 3 种银行常用的市场风险管理方法的 1% VaR 估计值如下:

方差-协方差:-2.87%历史模拟:-3.65% 蒙特卡洛模拟:-2.63%

现在我们转向使用双向生成敌对网络(甘比)进行 VaR 市场风险管理。

双向生成对抗网络(甘比)

生成性对抗网络(GAN)的两个主要组件是生成器和鉴别器。这两个组成部分相互竞争。这样,发生器学习如何从噪声中创建真实的合成样本,即潜在空间 z ,而鉴别器学习如何区分真实样本和合成样本。关于甘的详细解释,请看我下面这篇文章:

甘比通过添加第三个组件扩展了 GAN:编码器,它学习从数据空间 x 映射到潜在空间 z 。发生器的目标保持不变,而鉴别器的目标被改变以在真实样本和合成样本之间进行分类,此外还在真实编码(即由编码器给出的)和合成编码(即来自潜在空间 z 的样本)之间进行分类。

发电机

假设我们事先知道潜在空间 z 的位置:

给定从这个潜在空间的抽取,生成器 *G,*深度学习器,输出合成样本。

编码器

这可以显示为发生器的反转。给定从数据空间的抽取,深度学习器编码器 E 输出真实的编码。

鉴别器

鉴别器 D 是一个深度学习器,目的是分类样本是真实的还是合成的,即样本是否来自真实数据分布,

或合成数据分布。

此外,它旨在对编码是否真实进行分类,

或者合成的。

让我们将鉴别器 D 表示如下。

我们假设正面的例子是真实的,即,

而反面例子是合成的,即,

最佳鉴别器、编码器和发生器

类似于 GAN,甘比具有以下目标函数。

让我们仔细看看鉴别器的目标函数。

我们已经找到了给定一个生成器和一个编码器的最佳鉴别器。现在让我们关注发生器和编码器的目标函数,其本质上是最小化鉴别器的目标函数。

我们将注意到发生器和编码器的上述目标函数中的 kull back-lei bler(KL)偏差。

回想一下λ发散的定义。

如果λ取值为 0.5,这就称为詹森-香农(JS)散度。这种发散是对称的和非负的。

记住这一点,让我们再次看看发生器和编码器的目标函数。

从上面的生成器和编码器的目标函数中可以清楚地看出,获得的全局最小值是 -log(4) ,这发生在以下条件成立时。

当上述保持詹森-香农发散时,即,

将为零。因此我们证明了最优解如下。

给定上述结果,我们可以证明最佳鉴别器将是 0.5

最佳编码器和生成器是彼此的反函数

在最优生成器和编码器中,我们可以证明生成器和编码器是彼此的反函数。回想一下前面的生成器和编码器的定义。

此时,最佳鉴别器是 0.5 ,即鉴别器不能有效地区分真实数据和合成数据,因为合成数据是真实的。请记住,在这一点上,可能性已经被隐含地最大化,因此从合成分布中获取的任何样本都应该与从真实分布中获取的样本相似。简而言之,如果发生器、编码器和鉴别器的最优性成立,那么合成数据应该看起来与真实数据相似,或者更确切地说是相同。记住这一点,让我们稍微重写一下最佳发生器和编码器函数。

进一步回想一下,以下适用于最佳发生器和编码器。

在上面请注意以下几点;还要注意,我们假设生成器不是编码器的反函数,以提供反证法。

回想一下发生器和编码器最优性条件。

在上面请注意以下几点。

如果最优性成立,那么如下所示成立。

然而,由于我们假设生成器不是编码器的反函数,因此上述条件不成立,从而违反了最优性条件。

因此,我们通过矛盾证明了在生成器和编码器的最优性下,生成器是编码器的反函数。

对于与发生器相反的编码器,可以显示出上述相同的论点。

在上面请注意以下几点;还要注意,我们假设编码器不是通过矛盾提供证明的生成器的反函数。

回想一下发生器和编码器最优性条件。

在上面请注意以下几点。

如果最优性成立,那么如下所示成立。

然而,由于我们假设编码器不是生成器的反函数,因此上述条件不成立,从而违反了最优性条件。

因此,我们已经通过矛盾表明,在生成器和编码器的最优性下,编码器是生成器的反函数。

因此,我们已经通过反证法证明了最优编码器和生成器是彼此的反函数:如果它们不是彼此的反函数,那么这将违反编码器和生成器的最优条件,即,

甘比与自动编码器的关系

此时,在这里回顾我以前关于自动编码器的文章可能是个好主意:goo.gl/qWqbbv

注意,给定一个最佳鉴别器,生成器和编码器的目标函数可以被认为是自动编码器的目标函数,其中生成器扮演解码器的角色。发生器和编码器的目标函数仅仅是最小化鉴别器的目标函数,即,我们没有明确地指定重建损失的结构,就像自动编码器那样。这种重建损失的隐式最小化是甘比的另一个优点:不需要明确定义重建损失。

让我们提醒自己生成器和编码器的目标函数。

让我们来处理

首先,然后是

以类似的方式第二次。这些定义如下。

简要回忆一下 Radon-Nikodym 导数的定义:

接下来就是。

现在是第二个学期:

接下来就是。

还要注意。

现在我们将证明这一点

为了证明这一点,假设

因此,

随着

几乎到处都是。这意味着

定义得很好。

现在我们将证明这一点

为了证明这一点,假设

因此,

随着

几乎到处都是。这意味着

定义得很好。

在...的支持之外

0 。同样,在

在...的支持之外

0 。我们从前者开始。

注意,因为

这意味着

假设这个成立,我们清楚地表明

这是一个矛盾。

因此,

几乎无处不在

这意味着

几乎无处不在

因此

在支架上

0 ,即:

在...的支持之外

0

在...的支持之外

0

注意,因为

这意味着

假设这个成立,我们清楚地表明

这是一个矛盾。

因此,

几乎无处不在

这意味着

几乎无处不在

因此

在支架上

0 ,即:

在...的支持之外

0

因此,前面提到的 KL 偏差很可能是非零的

在这个空间中,我们展示了

让我们假设在这个地区

这一套

这意味着

因此,以下成立。

显然,上述内容意味着

并且与早先关于支持的定义相矛盾,即,

因此

是一个空集,因此

最后请注意,这意味着

让我们假设在这个地区

这一套

这意味着

因此,以下成立。

显然,上述内容意味着

并且与早先关于支持的定义相矛盾,即,

因此

是一个空集,因此

最后请注意,这意味着

我们已经清楚地表明

这意味着

是唯一一个

可能非零。

因此。

我们已经清楚地表明

因此,

我们已经清楚地表明

因此,

在上面的大量证明中,我们已经展示了甘比与自动编码器的关系。甘比可用于表示学习或自动特征工程。

在这一点上,我们已经定义了甘比,现在我们将实现它并将其用于我们前面提到的特定用例。

履行

我在这里做的工作是用 Python 和 R 代码在下面的 git repo 上维护的:【github.com/hamaadshah/…

结论

在我们结束这篇文章之前,让我们来看看一个未经训练的甘比的投资组合回报分布。

从上图可以清楚地看出,未经训练的甘比的样本投资组合收益分布与实际的投资组合收益分布明显不同。我们可以想象,这是可以预料的。

与经过训练的甘比形成对比:下图将清楚地显示 GAN 类型模型对于市场风险管理的价值,因为我们已经获得了这种学习的投资组合回报分布,而不必依赖于关于实际投资组合回报分布的可能不正确的假设,例如多维高斯分布。

请注意,我们也许应该使用进化算法或强化学习器来自动学习适当的 GAN 或甘比架构:也许这将是未来文章的主题。

最后,我们更新了使用不同市场风险管理方法的风险值估算表,如下所示。我们可以看到,甘比提供的风险值估计与其他市场风险管理方法提供的估计相似,如果不是完全相同的话。这为我们使用甘比进行市场风险管理提供了一个很好的健全性检查,因为它提供了相对于完善的现有市场风险管理方法的竞争结果。

方差-协方差:-2.87%历史模拟:-3.65% 蒙特卡洛模拟:-2.63%

双向生成对抗网络:-4.42%

与我们可能拥有衍生品或其他投资组合组成部分的潜在投资组合相比,我们必须处理的 5 只股票的投资组合并不特别复杂。在一个潜在复杂的投资组合中,获得正确的投资组合回报分布是一个已经被证明可以通过深度学习解决的问题,特别是甘比。这个结果对于市场风险管理和任何其他不同的问题空间都是有用的,在这些问题空间中,我们需要从一个潜在的复杂的,也许是未知的分布中产生样本。

在我的后续文章中,我们可能会看到一个复杂的回溯测试场景,即验证甘比提供的市场风险管理 VaR 类型估计是否适用于我们尚未看到的未来投资组合回报分布,并可能使用更复杂的投资组合。

我的这篇文章的目的是清楚地表明,一个训练有素的甘比可以用于给定投资组合的市场风险管理风险值估计。

参考

1.古德费勒,我,本吉奥,y 和库维尔(2016)。深度学习(麻省理工出版社)。 2。Geron,A. (2017)。用 Scikit-Learn&tensor flow(O ' Reilly)动手进行机器学习。 3。金玛博士和韦林博士(2014 年)。自动编码变分贝叶斯(【arxiv.org/abs/1312.61… 4。scikit-learn.org/stable/#5。https://towards data science . com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f 433990 D1 6 .https://stack overflow . com/questions/42177658/how-to-switch-back end-with-keras-from-tensor flow-to-the ano 7 .blog.keras.io/building-au… 8。https://keras . io9。f . chollet(2018)。用 Python 深度学习(曼宁)。10。约翰·赫尔(2010 年)。风险管理和金融机构(皮尔逊)。 11。https://towards data science . com/automatic-feature-engineering-using-deep-learning-and-Bayesian-inference-application-to-computer-7 B2 bb 8dc 7351 12 .https://towards data science . com/automatic-feature-engineering-using-generative-adversarial-networks-8e 24 B3 c 16 BF 3 13 .Donahue,j .,krhenbüHL,p .和 Darrell,T. (2017 年)。对抗性特征学习(arxiv.org/pdf/1605.09…)。 14。github.com/eriklindern…