数据工程——如何使用 Google App 脚本构建 Google Drive 数据管道
通过 3 个简单的步骤从您的 Google Drive 获取数据
另一天,另一个管道。亲爱的读者朋友们,我是你们友好的邻里数据从业者,为你们带来了另一条数据管道,以满足你们所有的工程需求。让我们跳过关于如今数据有多重要的闲聊,因为我已经在我之前的所有文章中多次提到它。底线,如果你不使用数据,你就错过了。现在,如果除了一张凌乱的桌子,还有什么东西是每个人都讨厌的,那就是一个凌乱的数据仓库。
拥有一张漂亮干净的桌子是没有意义的,因为这意味着你什么也没做。—加来道雄
请不要将这个概念应用于数据仓库。它实际上与引用的内容相反。
拥有一个混乱的数据仓库是没有意义的,因为这意味着你什么也做不了。真的,你可以以后再感谢我。
因此,当涉及到通过组织数据仓库的架构来为科学家和分析师保持数据仓库的功能时,数据工程师是至关重要的。必须构建干净的管道来维护来自各种来源的正确数据摄取,无论是来自组织本身还是来自外部来源。如果你自己是一名数据工程师,你今天会有所收获。即使你不是,也要倾听并欣赏工程师所做的事情。毕竟,正是他们为您提供了清晰易读的数据,并将其输入到您的复杂模型中。
在我的上一篇文章中,我谈到了如何建立一个 Gmail 数据管道。这是假设你通过 gmail 收件箱从外部来源获得常规数据。然而,如果出于某种原因,您的客户拒绝每周向您发送一封附有数据的电子邮件,该怎么办呢?相反,你的客户更喜欢通过一个共同的
Google Drive 文件夹定期与你分享数据。就像将文件拖放到他/她的浏览器中一样简单。在一分钟内,数据将被接收到您的数据仓库中,并生成有意义的见解/报告。那不是很酷吗?没有吗?就我一个人出去玩?那很有趣,因为我过去常常嘲笑那些讨厌的人的工作。看来我们没什么不同。
我经常被问到的问题是— 我为什么要关心?
好吧,即使你现在没有得到这个问题,谁又能说你将来不会得到呢?此外,如果出现这种情况,你可以向你的客户提出这样的解决方案。这可能会也可能不会增加你的专业感。此外,它还会增加你的酷点,我们数据从业者对此无法满足。
考虑到谷歌通过整合大量技术(如谷歌文档、谷歌表单、谷歌照片、谷歌日历、谷歌一切)而几乎主导了在线存储市场,它也被许多评论网站评为顶级云存储服务之一。这里有一个的例子。
拜托,你得承认。你自己用谷歌驱动,不是吗?
但是不要相信我的话。以下是谷歌趋势统计数据的支持。
在 Github 中也有一堆与 Google Drive 相关的支持代码。我们正在寻找大约 6k 个存储库和价值 800 万的代码。所以不要担心开发人员,我们支持你。
更不用说它可以与 Google Bigquery 顺利集成,如果您已经将它用作数据仓库,这是一个优势。Google Drive 是愚蠢的证明,用户友好,几乎每个人都在使用。很快,您将能够使用这个云服务作为您的来源之一,通过 3 个简单步骤将数据摄取到您的数据仓库中。
Google Drive 数据管道
- 自动从 Google Drive 文件夹中提取、转换和加载数据到您的首选数据仓库,最多一分钟即可完成
- 一个自动化系统,可以更好地将你的 Google Drive 文件组织到数据库中。只保留你需要的,其余的都扔掉。
- 愚蠢的证明。拖放。停止下载附件并手动上传到数据仓库。
我将使用谷歌应用程序脚本来执行这个管道。这样做的缺点是谷歌应用程序脚本无法与任何真正的工作管理系统相比,如 Apache Airflow 。因此,你无法真正监控你的管道。但是,默认情况下,Google App Script 会在失败时向您的 Gmail 帐户发送电子邮件。Google App 脚本 UI 还提供了一个简单的脚本摘要来监控错误。
因此,我建议将这种解决方案用于具有最小复杂性的简单管道。这里没有任何写日志或发邮件的步骤。它只是抓取数据,执行一些转换,并将其加载到您的数据仓库中。简单快捷。
我也在用谷歌大查询作为我公司的数据仓库。这里的好处是 Google App Script 能够用 2-3 行代码连接到 Google Bigquery。你可以选择使用任何你喜欢的 WMS 和数据仓库,无论如何 Google Drive API 应该是可调用的。
第一步。设置您的 Google Drive
管道的第一步是建立一个 Google Drive 文件夹,我们从中提取数据。提取你的 Google Drive 中的所有文件是可能的。然而,我们只想要与管道本身相关的 csv 文件。因此,我们必须为每个管道创建一个 Google Drive 文件夹,以便数据可以与其他数据区分开来,这是为了避免将来出现任何不一致。相当直接。
进入你的谷歌硬盘。右键单击空白区域的任意位置,然后选择新建文件夹。将该文件夹命名为您想要命名的管道,这样就设置好了。在该文件夹中,创建一个名为“Processed”的文件夹来存储所有已处理的数据。现在,您应该有一个专门用于管道的文件夹,其中包含一个名为“已处理”的文件夹。
第二步。在 Google App 脚本中创建管道
戴上你的学习帽,因为我们将深入一点代码。我有没有提到谷歌应用脚本只使用 Javascript 作为他们的语言?如果这让你厌烦,克服它,因为你不会永远用 Python 编码。
进入你的谷歌应用脚本主页。
选择新脚本并开始编码。
在键入任何代码之前,我们必须启用一些 API,以允许 Google App 脚本连接到 Google Drive 和 Google BQ。在菜单栏上,选择:
资源->高级 Google 服务->打开 Bigquery 并驱动 API
// Replace this value with the project ID listed in the Google
// Cloud Platform project.
var projectId = 'your project ID';
// Create a dataset and table in the BigQuery UI ([https://bigquery.cloud.google.com](https://bigquery.cloud.google.com))
// and enter its ID below.
var datasetId = 'your dataset name';
var tableId = 'your table name';
var location = 'your bigquery location'// defining the folder to store the csv file
// folder for files to be saved in
var processedfolderId = 'your processed folder ID';
var folderId = 'your folder ID';
在这段代码中,我们定义了 GCP 项目、Google BQ 数据集、表和位置以及 Google Drive 文件夹。Google Drive 文件夹的 ID 可在此处找到:
function scan_files() {
var folder = DriveApp.getFolderById(folderID);
var processedfolder = DriveApp.getFolderById(processedfolderId);
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
if (file.getName().substring(0, 10) != 'processed_' || file.getName().substring(0, 7) != 'loaded_') {
loadCSVfromdrive(file);
}
}
};
在这个块中,我们定义了一个由 Google App Script 定期运行的函数来扫描我们指定的文件夹中的文件。如果有已存在的文件,我们将把它传递给函数 **loadCSVfromdrive。**但是,如果文件以名称“processed_”或“loaded_”开头,我们将忽略该文件。我们将用这个前缀命名我们已经处理/接收到 BQ 中的所有 csv 文件,以区别于尚未加载的数据。我们也会将它们放入“已处理”文件夹中。
function loadCSVfromdrive(file) {
var fileId = file.getId();
var filename = file.getName();
var csvData =Utilities.parseCsv(file.getBlob().getDataAsString());
var headers = [list of headers];
var length = csvData.length;// defining an array for each row of data
abstractarray = [headers];
//looping through each row of data from the raw file , transforming //it and append it to the array
for (var a = 1; a < csvData.length; a++){
// Transformation of data begins here (example below)
var description = csvData[a][14] + " " + csvData[a][25] + " " + csvData[a][26] + " " + csvData[a][27];
var reference = csvData[a][15];
var transaction_type = csvData[a][21];
// Transformation of data ends here contents = [description, reference, transaction_type];
abstractarray.push(contents);
}// defining the contents of the csv, should be an array of arrays
var csvContent = ''; abstractarray.forEach(function(infoarray, index) {
dataString = infoarray.join(',');
csvContent += index < abstractarray.length ? dataString + '\n' :dataString;
});// create a csv file which contents are the csv contents we defined //in the processed folder
filename_new = 'processed_' + filename
file_new = processedfolder.createFile(filename_new, csvContent);
在这段代码中,我们定义了将要加载到 Google BQ 中的 CSV 文件的内容。这仅适用于在接收到数据仓库之前需要清理/转换的数据。如果您计划从 Google Drive 文件夹加载原始数据,您可能会忽略大部分代码块。与使用 Python 的 Pandas 相比,Javascript 必须逐行转换数据,这就是为什么我们使用 for 循环来转换每行的所有数据,并将该行附加到我们的 csvcontent 中。如果你知道如何在 Javascript 中像熊猫一样操作,请在我的 DMs 中滑动,因为我对 JS 相当陌生。我们还在转换后在处理过的文件夹中创建一个名为“processed_filename”的文件,以便与原始数据区分开来。
// Create the data upload job.
var job = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
maxBadRecords: 0,
fieldDelimiter: ',',
skipLeadingRows: 0,
writeDisposition: 'WRITE_APPEND',
sourceFormat: "CSV"
}
}
}; job = BigQuery.Jobs.insert(job, projectId, file_new);
while(true) {
jobstatus = BigQuery.Jobs.get(projectId, job.getJobReference().getJobId(), {location : location})
if(jobstatus.getStatus().getState() == "DONE") {
break;}
}// saving the loaded file as the name 'loaded' so that it
//doesnt get loaded the next time
DriveApp.getFileById(fileId).setName('loaded_' + file.getName());
Logger.log(file_new)
}
我们正在这里设置装载作业。如果您在 Google Drive 中接收累积数据以覆盖您的数据仓库中的数据,您可以将 writeDisposition 参数更改为‘WRITE _ TRUNCATE’。成功加载数据后,我们将文件重命名为“loaded_filename ”,这样它就不会在将来被加载。如果出现任何问题,您也可以返回到该文件夹检查您的原始数据。这是管道的完整代码。
第三步。在 Google App 脚本中设置触发器
恭喜你,你已经到达了数据管道的最后一步。
别担心,从这里开始不会再有代码了。我们现在要做的就是设置触发器来运行我们的管道。
进入你的谷歌应用程序脚本主页。
我的项目->悬停在您的项目上->触发器
这应该会把你带到触发页面。
点击新建触发器并设置您的触发器。
如你所见,这是一个快速、简单且愚蠢的证明。像我承诺的那样。
记得选择 scan_files 功能作为要运行的功能。您可以选择函数运行的时间间隔。在 Google App Script 中,目前可用的最短时间间隔是以分钟为单位。即使对你来说,这也太短了。她就是这么说的。
恭喜
您已经成功构建了您的个人 Google Drive 数据管道。
数据团队是否要求将 Google Drive 中的一些数据输入到他们的模型中?你现在每分钟都可以这样做!自豪地拍拍自己的背。
我希望你今天学到了新东西。如果我激发了你对数据的兴趣,那么我就帮了大家一个忙,为数据行业招募了一名新人才。我们又不是已经饱和了。作为结束,我将再一次放弃引用。
成功没有秘诀。它是准备、努力和从失败中学习的结果。—科林·鲍威尔
订阅我的时事通讯,保持联系。
感谢 的阅读!如果你想与我取得联系,请随时通过 nickmydata@gmail.com 或我的 LinkedIn 个人资料 联系我。也可以在我的Github中查看代码。
数据工程——如何在 Apache Airflow 中设置数据管道之间的依赖关系
使用传感器设置数据管道之间的有效依赖关系,为数据团队建立坚实的基础
Photo by Rodion Kutsaev on Unsplash
亲爱的读者朋友们,又是我。那个写自己生活经历和一点点数据的家伙。
就一点点。
文章在文章之后,我总是从数据在一个强大的组织中有多重要开始。大公司如何利用数据来影响他们的业务,影响我们的社会,进而为他们带来利润。数据可以用来拯救生命,看看这篇关于数据如何被用来预测癌细胞的文章就知道了。所以,请让我们跳过关于数据有多重要以及它如何总是正确的闲聊,就像你的妻子一样。
我们相信上帝。所有其他人必须带数据。爱德华·德明
在世界开始之前,只有黑暗。然后不知何故,有人说要有光,突然间所有的生命都活了过来。
同样,在没有任何数据之前,只有黑暗。然后,不知何故,数据工程师建立了惊人的管道将数据输入数据仓库,突然间,所有的数据科学家都提出了他们的模型。可用数据的基础很大程度上取决于工程师编写的管道结构。因此,我们使用正确的工具来优化我们的管道非常重要。
在我之前的文章中,我谈到了 CRONJOBS 在为适当的数据仓库调度管道时不再可行。相反,工程师应该研究记录良好的工作流管理系统,这些系统可以提供巨大的好处,如监控、设置依赖关系,更不用说可以使用良好的 UI 了。我选择的 WMS 是 Apache Airflow,因为在研究了所有可用的 WMS 后,我的公司认为 Apache Airflow 是目前最适合我们仓库的。
我有没有提到 twitter 也在使用 Apache Airflow 进行数据仓储?
我还引导读者建立他们的第一个管道,谈论 Apache Airflow 的基础以及它是如何工作的。这篇文章是对它的延伸,因为我将讨论设置管道之间的依赖关系,以及为什么它对您的数据仓库如此重要。
为什么重要?
每个数据仓库都各不相同。作为工程师,我们能做的最好的事情就是建立有效的管道来适应数据仓库本身的优点和缺点。每个数据仓库都从一个数据源获取数据,这个数据源可能是您的主数据库或它的克隆。根据您的公司,您可能会运行 ETL 管道将数据接收到您的数据仓库中。然而,使用 Google Bigquery 作为我公司的数据仓库,我们认为运行 ELT 管道速度更快,成本更低,因为 Google BQ 可以很好地处理转换。它还减轻了主数据库的从数据库的负担。我相信这不是我们公司独有的,现在在数据领域这是一种非常普遍的做法。通常的议程是从午夜开始的 X 个小时的原始表的纯数据提取,导致这些表的转换再持续 X 个小时,以完成整个流水线。这是我做的一个形象化的展示。
之所以这样设计管道,是因为第一级转换后的表来自并依赖于原始表提取的完成。然后,第二级转换表依赖于这些第一级转换表。因此,我们设置这些任务之间的依赖关系是很重要的。如果一个表的一个源表还没有被提取/转换,我们就不想执行这个表的转换。这将导致不正确的数据,而这正是数据工程师应该受到指责的地方。
传感器
如前所述,我们将使用阿帕奇气流作为我们的主要 WMS。通过这样做,我们可以有效地监控我们的工作流,能够跟踪失败的任务,如果有的话。如果你不知道如何操作气流,那么下面的内容对你来说就像是谜题,请先阅读阿帕奇气流的基础知识。
传感器预装在气流中。顾名思义,它们感知气流中任何任务的完成状态,就这么简单。我们将使用传感器来设置我们的 does 管道之间的依赖关系,以便在依赖关系完成之前不会运行。不需要为此编写任何自定义操作符。以下是传感器的默认格式:
check_dependency =
ExternalSensor.ExternalTaskSensor(
task_id='name of the sensor',
external_dag_id='name of dag to be checked',
external_task_id= 'name of task to be checked',
execution_delta = time difference between execution times,
timeout = maximum running time of sensors)
我们将此代码块作为 DAG 中的一项任务来编写。
需要注意的两件事:
- 执行增量可能很棘手,它取决于任务的执行时间,而不是运行时间。这里有一个例子。
这里,执行时间是 2019 年 8 月 30 日晚上 9 点(不要与运行时间混淆,运行时间在这里也称为“开始”:2019 年 8 月 31 日晚上 9 点)。如果我们将传感器的执行时间(传感器 DAG 中的’ start_date 的设置)设置为 2019-08-30 晚上 10 点,那么在这种情况下,执行增量将为 timedelta(小时=1)。
- 超时参数是必需的。当您的管道扩展时,将会有许多传感器运行来检查完井情况。如果没有设置超时,并且我们的一些依赖关系失败,传感器将无限期运行,并导致您的气流暂停。这是因为 airflow 只允许在一个实例上运行一定最大数量的任务,并且传感器被视为任务。如果你不知何故达到这个数字,气流将不会处理进一步的任务。因此,我们需要为传感器设置超时参数,这样,如果我们的依赖关系失败,我们的传感器就不会永远运行。
例子
在这个例子中,假设表 1 是来自原始数据源的一些连接的结果。在运行表 1 的转换之前,我们需要创建 4 个传感器来感知提取 Dag 的完成。
为了消除所有疑问,让我们假设所有提取 Dag:
- 每天运行
- 在晚上 9 点运行
我们将在表 1 的转换 DAG 中编写以下代码:
check_data_source_1 =
ExternalSensor.ExternalTaskSensor(
task_id='check_data_source_1',
external_dag_id='dag of data source 1',
external_task_id= 'last task of the dag',
execution_delta = timedelta(hours=1),
timeout = 300)check_data_source_2 =
ExternalSensor.ExternalTaskSensor(
task_id='check_data_source_2',
external_dag_id='dag of data source 2',
external_task_id= 'last task of the dag',
execution_delta = timedelta(hours=1),
timeout = 300)check_external_data_source_1 =
ExternalSensor.ExternalTaskSensor(
task_id='check_external_data_source_1',
external_dag_id='dag of external data source 1',
external_task_id= 'last task of the dag',
execution_delta = timedelta(hours=1),
timeout = 300)check_external_data_source_2 =
ExternalSensor.ExternalTaskSensor(
task_id='check_external_data_source_2',
external_dag_id='dag of external data source 2',
external_task_id= 'last task of the dag',
execution_delta = timedelta(hours=1),
timeout = 300)transform_table_1 = /* code for transformation of table 1 */check_data_source_1
check_data_source_2
check_external_data_source_1
check_external_data_source_2transform_table_1.set_upstream([check_data_source_1,check_data_source_2,check_external_data_source_1,check_external_data_source_2])
写完上面的代码后,在我们设置的四个依赖项完成之前,任务“transform_table_1”不应继续。一旦传感器启动,它们将在 5 分钟内感知依赖关系的完成。如果上述依赖关系未能完成,传感器将显示为故障,等待重试。
这是 DAG 的完整代码。
恭喜
您在实现干净数据方面又前进了一步。即使你不是数据工程师,这些知识对所有数据从业者都是有益的。此外,传感器可用于所有气流任务。
想在查询运行后发送电子邮件吗?使用传感器
想要在插入新文件后扫描某个共享的 google drive 吗?使用传感器
可能性是无限的。
结束注释:原谅我最近的缺席,我正在 Apache Beam 上实现流管道。有趣的东西!一旦完成,我会写下来的!
订阅我的时事通讯,保持联系。
感谢 的阅读!如果你想与我取得联系,请随时通过 nickmydata@gmail.com 或我的 LinkedIn 个人资料 联系我。也可以在我的Github中查看代码。
数据工程金块
介绍杂乱无章的轮胎火灾,这是我的数据驱动思维
Photo by Pedro Henrique Santos on Unsplash
编写有意义的数据工程内容时的一个挑战是,受众来自如此多样化的背景。一个拥有数据工程师头衔的人很可能在到达这个职位时戴着各种不同的帽子,却发现“数据工程师”是他们所有人的最佳绰号。当面对一群这样的人时,什么能被认为是“常识”,什么不能被认为是“常识”,这是非常复杂的考虑到这一点,我在这里开始为收集数据团队相关的知识奠定基础。对于数据团队,我通常指的是组成大多数组织知识结构的分析师、数据工程师、数据科学家和商业智能专家的集合(尽管我的观点通常会偏离重点)。我们从实践中学到的一些经验教训是非常有价值和相关的,不管我们如何去理解它们,这就是我在这里要阐述的观点。我的希望是,它为我对那些使数据团队在今天取得成功的事情的理解描绘了一幅广阔的底漆。
数据团队必须有一个使命
在您签署任何供应商合同、启动您的第一个数据库或键入单个git init
之前,您需要了解数据团队在您组织中的目的。像“成为一个数据驱动的组织”或可怕的“使用机器学习来减少辛劳”这样模糊的目标和令人恐惧的模糊指令,往好里说是毫无意义的,往坏里说是对你职业生涯的威胁。组织想要关注内部分析(围绕自身的准确报告)还是商业智能(围绕客户的准确报告)?预测(预测未来业务)或者趋势分析(寻找长期统计模式)?R 实时个性化(应用速度数据科学)或根本原因分析(数据取证)?一个定义良好的任务是你的工作范围和支持用例的基础。当你选择使用什么技术,雇佣谁,以及如何定义你的工作“完成”时,这些将作为你的最高要求。
**Meh 使命:**数据团队将支持组织变得更加数据驱动的目标,并使用机器学习将我们的业务提升到一个新的水平。
是啊!使命:数据团队将构建和维护我们的“单一真实来源”数据系统,为企业利益相关方提供绩效洞察、产品和客户分析以及内部预测。该团队将制作和认证用于内部绩效指标、产品路线图&决策、产品和效率问题根本原因分析以及费用和销售预测的资产。
现在我们知道了我们要实现的目标。例如,这项任务的所有组成部分要么属于决策支持,要么属于监测或预测——高度容忍延迟的活动。在这种情况下,我们希望从数据团队获得的商业价值可以通过每天甚至每周的批处理来实现,因此在流式 NRT 解决方案上投入巨资可能是错误的答案。尽早并经常更新你的任务。当有疑问时,迫切要求澄清,尤其是当那些变化无常的高管人物给你模糊的指示时。如果你不清楚成功意味着什么,你就不会成功。
把你所做的当作软件
我绝不是这种思想流派的先驱,你可以阅读很多由比我聪明得多的人写的关于数据工程即代码开发的文章。简而言之,我们生产的转换、提取负载、工件、模型和可视化是以编程方式应用业务逻辑的结果。这和驱动网站、商业软件、操作系统和 IOT 牙刷的代码是完全一样的功能。在其他应用业务逻辑所在的软件世界中,某些工具和技术(通常)被认为是该行业的基石,例如:
我们称之为“最佳实践”,现代软件开发人员已经将类似于git commit
和tox -e test
的命令深深地烙进了他们的记忆中。非常奇怪的是,数据团队经常被认为不受这些实践的约束,并且遵循一套完全不同的开发标准(或者根本没有标准)。这可能部分是由于这些不同的起源;沿着这条线的某个地方,一个业务用户变成了一个分析师,然后他变成了一个数据工程师,并且从来没有一个明确的时刻,软件团队的某个人觉得有必要说“你现在是工程软件,你需要开始使用 Git。”
所以这就是,毫不含糊地说。作为 2019 年现代数据团队的一员,你需要测试你的代码和你的数据工件。您需要使用源代码控制,并让您的工作接受同行评审。您需要学习如何以小增量提供价值,并在挖掘主题数据的细微差别时进行调整。你需要对真正的 SLA 负责。这些不是手动版本控制、单枪匹马的数据工程/科学、眼球问答和从 sql 终端直接对生产数据库运行代码的“替代方案”;在越野旅行中,骑马并不是飞机的“替代”交通方式。
当然,这个主题还有很多,在不久的将来,我将尽我所能在更多的文章中深入探讨如何最好地处理数据团队软件工作流。
数据不会告诉你它是错的
故事大概是这样的
善意的首席技术官(或首席执行官、首席信息官或其他人)决定公司需要数据驱动。“我们将不再在数据黑暗中运营!”这位高管英雄大声疾呼,于是他们召集了一支精锐的工程师团队,设计了一个包括数据湖、提取-加载管道、数据仓库和商业智能工具在内的架构。来自所有主要应用程序的原始数据被泵入湖中,一些SELECT * FROM
查询被用来生成扁平的“分析表”,然后砰!你有这些中的一个:
We have graphs so we must be data driven, right?
这个团队做了其中一件事:
We did it! This data stuff is so easy.
太好了!
除了在“发布”后不久,用户开始注意到数据与之前的报告不太匹配。他们如何理解数据或提供许多超出他们已知的真实见解也没有意义。几件事情都是以的方式进行的。很快各部门开始比较笔记,差异的积压建立起来。在短短的几个月内,用户的信心直线下降,你的商业智能解决方案的光荣的白衣骑士变成了另一个“真理”,伴随着它应该取代的资源大军。
简而言之,可视化中的数据不等于任务完成。从数据源→数据湖→数据仓库→可视化移动数据可能会让你走完 10%的路程;另外 90%是解密部落知识、神奇的数字、与用户理解(或需要理解)输出的方式相冲突的交易和操作结构,开发和实现质量测试,以及跨数据集整合结构。这项工作就是将数据转换成信息。这是数据团队的大部分价值所在,也是我们如何真正定义“完成”的。
我们可以使用一些不同的工具来解决另外 90%的问题(即取证、转换、质量测试和数据整合)。我是 Kimball 总线矩阵的忠实粉丝——它坚持下来是因为它有效。对于取证工作,我发现 DBA 伙伴关系和开发人员/利益相关者访谈是非常有价值的,但是没有什么比亲自阅读应用程序代码更有价值。事实是,你的数据产品交付在迭代框架中是最成功的,这就是为什么对数据团队使用 UAT 开发过程绝对是我最喜欢的内部分析解决方案之一。
无论您如何着手,请记住,您向组织提交的最早的数据产品将决定您的团队的信心水平。从长远来看,尽最大努力开发经过适当研究、测试和“强化”的数据产品将会获得回报。
数据现在非常热门
Everybody wants a piece of that data goodness
截至 2019 年秋季,数据是商业术语的南瓜调味品。公司想要它,消费者担心谁拥有它,内容创建者不知道如何处理所有这些数据,政府想要监管它,谷歌和脸书交易大量的数据……每个重要人物都以这样或那样的方式与数据有关,或者看起来是这样。对于数据团队成员来说,这既创造了一些惊人的机会,也带来了一些令人严重担忧的趋势。
首先,好消息是: 大家都喜欢你 。由于最近对数据的痴迷,我们正享受着来自商业同行的兴趣和支持的爆炸式增长。不是每天都有一个主要的成本中心能够在不被削减的情况下使他们的运营费用翻两三倍;然而,此时此刻,如果你说这是为了你一直在做的所有“机器学习”,有很多首席信息官会很乐意支付那个庞大的 AWS EMR 账单。由于这种数据狂欢的阴霾,我们从来没有像现在这样容易获得我们需要的东西,来构建能够以正确的方式影响业务的正确的东西。
现在是不太好的消息:所有的繁荣都会破灭。这种对数据的迷恋具备了 2005 年佛罗里达房地产泡沫的所有要素。如果你还记得很久以前,那是在英国《金融时报》做房地产经纪人的一段非常美好的时光。劳德代尔。到 2009 年末,就没那么多了。掌权的人,无论是首席执行官还是董事,甚至是董事会成员,他们都希望成为当今数据党的一员。因此,他们可能会参加数据团队会议,推动具有大量视觉 flash 的超大计划(通常没有与公司 okr 的关联),并关注技术而不是结果(特别是当它涉及到他们听到其他高管提到的工具时)。来自整个组织的风险承担者可能会指出数据团队似乎是每个问题的显而易见的解决方案,但通常没有相应的行动计划。最终,分析水晶球和人工智能推动的大规模增长的承诺将恶化为巨额资本投资的后遗症,而这些投资几乎没有有形回报。当另一只鞋最终掉下时,数据团队会感到手头拮据,而此时游客早已转向下一个商业时尚。
那么有哪些方法可以防范繁荣呢?一个是肯定要 掌握自己的命运 (后面会详细说明)。另一个警告你潜在危险情况的简单技巧是听这个单词:
That’s right. Beware the data.
奇怪的是,可操作的、有价值的数据团队工作很少在描述中包含“数据”这个词。请考虑以下情况:
可操作: 我们需要 salesforce 中的用户群组,通过我们新的 RFM 断点进行划分,这样我们就可以在假期到来之前重新调整我们发送的电子邮件。
绒毛: 我们的销量下降是因为我们没有 salesforce 的数据,所以我们没有任何见解。
可操作的工作有一个清晰的策略,说明数据(salesforce 用户群)如何变成信息(应用新的 RFM 断点)如何变成功能知识(更新电子邮件以提高转化率)。
试图用绒毛做出同样的价值路径要困难得多,因为它依赖“数据”来解决问题。数据不能解决问题或做出决策。人们做那些事情。如果有疑问的人没有数据可以告知的行动计划,这些数据对他们没有任何用处(你也一样)。
掌握你的命运
很多年前,我卖摩托车,在我工作的经销店,我们有一种说法:*“你是销售员,还是接单员?”*接单员只是简单地传达他们的想法,盲目地将顾客带到那周广告中的自行车前,读出价格标签,填写文件,然后送他们离开。另一方面,销售人员倾听顾客的意见,利用他们对机器和库存的了解,向顾客推荐最适合他们的自行车。接单员执行订单,销售人员 增值 。
同样的规则也适用于现代数据团队。人们很容易相信利益相关者的话,认为填充几个 Adwords 数据表将解决所有营销困境,并保证任何有股权的人都能提前退休,这是很危险的。鉴于我们工作的复杂性(创建 EL 流程、建模、部署、可视化等),我们可能会被一种虚假的安全感所迷惑——因为我们正在努力做一些很难做的事情,我们必须做得很好,对吗?
这是它分解的地方。**当你致力于交付数据产品时,毫无价值的工作通常感觉就像是超级有价值的工作。**这意味着您可以夜以继日地辛勤工作,应用最前沿的分析并深入研究数据质量,以交付一组壮观的工件,这些工件(不是您自己的错)可能对业务完全没有价值。毫无疑问,这个价值就是你和你的工作将如何被企业所评判。对于成功的现代数据团队来说,不仅要投资工作质量,还要投资工作价值,这种转变是关键的一步。
因此,一定要质疑你的利益相关者。恳求他们帮助你理解需要完成数据工作的原因,以及它如何让业务变得更好。我曾经共事过的一位杰出的数据科学家会将这种宝石用于分析/报告工作:
您能告诉我您将根据此请求的结果做出什么决定吗?了解这些决策将有助于我们确保我们为您构建的(报告/数据/模型)能够满足您的需求。
对于产品化的数据也可以提出同样的问题(“我们如何从这种产出中赚钱?”)和指标(“哪些组织 KPI 与这些指标相关联,如何相关联?”).最重要的是,如果答案不是你可以合理推后的,那就推后。没错——数据团队有责任确保他们在增加价值,即使这意味着(非常委婉地)告诉 CEO / CIO /总监你不同意的任何事情。有理由说,你的自我评估中的“胜利”一栏今年需要一些重大胜利,而“本小时发货的 10 大产品”仪表板不会让我们成为一个组织。你可能仍然需要制造一些无用的东西,偶尔运送一些低价值的工件来维持和平可能是很好的策略。但是,如果你发现自己在应该是“销售人员”的时候却一直扮演着“接单员”的角色,那么是时候开始寻找更好的工作了。在预算季节,没有人会急于为数据团队辩护,不管你在前一年按照要求成功完成了多少低价值的请求(这被称为高管健忘症)。
还有更多这是从哪里来的
到目前为止,我已经浏览了一些来之不易的现代数据课程;我的希望是在未来的几个月里,从过程和技术的角度进行更深入的探索,并分享一路上觉得有价值/有趣/值得的事情。
数据工程-熊猫 101
Pandas 是数据分析和工程的一个很好的工具。我已经使用它大约三年了——在那之前,它是 Python 库的大杂烩,有点令人生厌。
熊猫= Python 数据分析库
那么,熊猫是什么,它为什么伟大?
- 你可以很容易地从本地文件或连接到数据库远程加载数据。
- 你可以用探索的方式处理数据,很容易地总结和查看数据的统计数据;
- 你可以清理、操纵(切片、切块)重塑并组合数据,更轻松地沿着链条往下处理;
- 您可以更有效地处理大型数据集——减少使用它们时使用的内存,非初学者的深入文章在此。
- 您可以访问数据帧——一种类似表格的数据结构(我们在 R 语言中已经有很长时间了);
- 您可以对结果数据集进行基本的绘图——相当不错;
熊猫官方网站在这里:
[## Python 数据分析库- pandas: Python 数据分析库
pandas 是一个开源的、BSD 许可的库,提供高性能、易于使用的数据结构和数据…
pandas.pydata.org](https://pandas.pydata.org/)
安装熊猫非常简单:
mkdir panda-playground
cd panda-playground
pip install pandas
我们还可以访问大量样本数据集
数据集
您可以通过 URL 或本地文件以多种不同的方式在 Pandas 中加载数据集:
iris = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
来自 MySQL 等数据库,如下所示:
cn = MySQLdb.connect(host='localhost', port=3306,user='un', passwd='pass', db='zoo')
pd.read_sql('select * from animals;', con=cn)
我们将在以下示例中使用的数据集与视频游戏销售相关,可在此处找到:
[https://github.com/jph98/pandas-playground/blob/master/vgsales-12-4-2019.csv](https://github.com/jph98/pandas-playground/blob/master/vgsales-12-4-2019.csv)
注意:为了创建下面的表格,我最后从 Pandas 获取表格输出,并将其转换为 CSV 格式,格式为:
import pandas as pd
import numpy as nadf = pd.read_csv('vgsales-12-4-2019.csv')
overview = df.describe()
print(overview.to_csv())
然后作为 Github gist 上传,再嵌入到这里。非常好用。
汇总数据
开箱后,我们可以查看一些数据来了解我们正在处理的内容,前 n 名的结果集:
df.head()
Output of calling the head() function on the dataframe
注意:当你这样做的时候,你会注意到列会根据 Pandas 中的设置被截断,为了避免这个限制,你可以如下设置 display.max_columns:
pd.set_option('display.max_columns', None)
或者获取有用的数据摘要,以了解我们在做什么:
df.describe()
Summary statistics output from the describe() function
您还可以使用以下方法从数据集中获取一组随机的样本行:
df.sample(n=100)
或者看看数据框的一些特定属性:
# Get the number of rows
len(df.index)# Get column names, get number of columns
df.columns
len(df.columns)
好了,我们来看提取一些数据。注意:当您使用 Pandas 提取数据时,它将包含一个初始列号作为列以及所选数据。
子集数据(观察值和变量)
您可以通过以下方式提取一个特定游戏或游戏范围:
df.loc[0]
df.loc[0:3]
抓取第一个和第二个视频游戏的名称和流派栏
df.loc[0:1,['Name']]
或者实际上提取整个特定列,在本例中,游戏**流派,**但只有唯一值:
df['Genre'].unique()
使用表达式过滤数据
我们还可以在提取中包含表达式,这样我们就可以更加优雅和复杂地查询数据。
让我们显示由 vgchartz.com 计算的所有视频游戏评分。在这种情况下,我对所有得分在 9.2 或以上的精彩游戏感兴趣:
So, no surprises there, Super Mario Galaxy, Grand Theft Auto, Zelda, Metal Gear Solid and the truly excellent World of Goo (well done Kyle Gabler) all feature here in the results.
现在,我们可以使用以下内容按降序排列这些内容:
df[df.Vgchartzscore > 9.2].sort_values(['Vgchartzscore'])
并将结果数量限制为前五个游戏:
df[df.Vgchartzscore > 9.2].sort_values(['Vgchartzscore']).head(5)
注意,你可以修改我们加载到内存中的数据帧。然而,这个并不修改底层的 CSV 文件。如果我们想要将数据保存/持久保存到文件中,我们必须使用以下命令显式地将数据帧写入内存:
df.to_csv('outputfile.csv')
这将保存整个数据框。要将它限制到子集化的数据,只需用 to_csv 再次链接:
df[df.Vgchartzscore > 9.2].sort_values(['Vgchartzscore']).head(5).to_csv('outputfile.csv)
处理缺失数据
我们在数据工程中遇到的一件常见的事情是需要通过清理来修改传入的数据——毕竟我们不想接收坏数据,并希望在某种程度上使事情正常化。
删除空行或空列 删除空行(指定轴=0)或空列(指定轴=1),如下所示:
df.dropna(axis=**0**, how='any', thresh=None, subset=None, inplace=False)
您可以通过以下方式删除特定列:
df.drop(['Rank'], axis=1)
缺少值
上述数据集中的某些特定于行的列具有 NaN(非数字)值。要获得至少有一列为空的行的计数,我们可以使用:
df.isnull().sum().sum()
或按列细分,包括:
df.isnull().sum()
我们有几个选择:
- 我们可以排除包含空列的行
- 我们可以通过标准化到已知值来清理行
例如,对于 NaN 的 Vgchartzscore,我们可以使用以下公式将这些值归一化为 0.0:
df['Vgchartzscore'].fillna(0, inplace=True)
这应该会留下大约 799 行非 0.0 值。
分组数据
有很多方法可以重塑 Pandas 中的数据。我们来看看 groupby 函数。我们可以将此与按流派分类的视频游戏数据集一起使用,以了解符合该类别的视频游戏的数量:
df.groupby('Genre').first()
我们可以通过以下方式获得每个组别的游戏数量:
df.groupby('Genre').size()
然后,我们还可以应用 sum()或其他支持的函数,如下所示:
df.groupby('Genre').first().sum()
好了,接下来我们要按平台(PS4、XBox 等)对这一类型进行分类…)来理解游戏,所以:
df.groupby(['Genre', 'Platform']).first()
注意:如果您想遍历每个组,要做一些后处理,您可以执行以下操作:
by_genre = df.groupby(['Genre', 'Platform'])
for name, group in by_genre:
print(name)
最后,我们可以利用聚合函数对我们分组的数据进行一些计算。在下文中,我们将查看各类型平台中 Global_Sales 的平均值和总和:
g = df.groupby(['Genre', 'Platform'])
res = g['Global_Sales'].agg(["mean", "sum"])
结论
因此,Pandas 为您提供了丰富的功能来帮助您进行数据分析和操作。你不会想在 SQL 或原始 Python 中这样做,主要是因为它更复杂,你必须编写更多的代码,或者你受到所提供的功能的限制。聚集和分组是我选择熊猫的两个关键场景。
您可以在下面的 Github 示例库中找到本文提到的代码的 Python 3 示例:
我的媒体文章的熊猫乐园存储库- jph98/pandas-playground
github.com](https://github.com/jph98/pandas-playground/)
这是关于数据工程的一系列帖子中的第一篇,我将在后续的帖子中涉及以下内容(写好后从这里链接):
- 用 matplotlib 实现熊猫数据框的可视化
- 熊猫使用自动气象站的元素进行大型数据处理——SQS 进行协调,然后构建管道进行处理等…
不要脸的塞: )
- 我通过 hwintegral 运行关于 Python 和 Pandas 的教练会议;
- 我提供数据团队指导、数据架构审查和转换(团队和技术)。
如果您的公司需要帮助,请通过以下方式联系:
尽职调查和技术审计在 HW Integral,我们为风险投资和私募股权公司的投资提供尽职调查服务…
www.hwintegral.com](https://www.hwintegral.com/services)
数据工程——数据科学的表亲,很麻烦
如何让你的分析师意识到扩展他们工具包的重要性?我想我已经找到答案了。
我们一直认为数据科学是“21 世纪最性感的工作”。当谈到从传统公司到分析公司的转型时,无论是公司还是数据科学家都希望尽快进入分析的奇妙世界。但是,总是这样吗?
麻烦的开始
自从我们,一个来自加州大学戴维斯分校的实习团队,开始与电动工具和相关服务的领先制造公司 Hilti 合作以来,我们已经提供了几个精彩的蓝图:定价自动化,倾向模型…与这样一个伟大的公司合作对我们来说是如此宝贵的机会,我们迫不及待地利用我们的分析技能来创造商业价值。但当我们开始挖掘数据时,我们发现,与电子商务公司等数据驱动型公司相比,我们很难直接从传统公司获得干净和结构化的数据。
由于我主要负责该项目的数据清理和工程设计,我目睹了我们如何因未准备好的数据而阻碍了分析进度。
I witnessed how we were hindered in the analytical progress due to the unready data
我们直接与财务团队合作,但另一个团队——定价运营团队——实际上负责数据库。一开始,这个过程严重滞后,因为我们几乎不能及时请求和查询数据或人员。此外,由于喜利得的销售数据非常敏感,并且该公司缺乏安全的数据传输方式,因此每次请求数据时都需要执行耗时的屏蔽过程。第三,薄弱的数据工程导致了几个参考表之间的不一致,我们几乎不能得到一个可靠的模型或结论。最后,我们必须处理各种数据类型:csv、JSON、SQLite 等……尽管这是一个很好的学习机会。
大约两个月后,我们准备好了所有的数据,讨论并解决了每一个异常情况。
潜水时间!
我们开发良好的可视化框架和模型迫不及待地想要品尝新鲜的数据。然而,最尴尬的事情发生在我们拿出第一份提案的实际数字时。
你猜怎么着,大数字似乎不匹配。快速讨论后,我们意识到我们根本没有收到完整的数据。我们只关注数据的细节,如异常和数据源之间的关系,但我们忘记了做基本的检查,如总和和计数。这是我将终生铭记的一课。真的!
为什么数据工程如此重要
我从数据工程戏剧中学到的最重要的事情是,在幕后工作的角色,例如数据工程师,实际上掌握着创新的大门。当传统公司考虑利用他们的数据时,最有效的第一步行动应该是改进数据工程过程。有了优秀的数据工程师,公司可以建立一个健康、可扩展的数据管道,让数据分析师更容易进行数据挖掘和寻找商业见解。
我还了解到,除了 SQL 和 Excel 等分析工具之外,为什么许多公司要求他们的数据分析师具备 Python 和 Scala 等编程相关工具的知识。通常,我们不能指望一个“全栈”的分析师,但我们必须有一个既能与工程人员沟通又能与管理人员沟通的人。虽然明确的工作分配对高效率很重要,但一个精通每一种数据工具的人确实是有吸引力的。
Full-stack…makes sense!
我期望自己在未来学习的是正面和背面的知识,如 Java、JavaScript、Kafka、Spark 和 Hive,我相信最终它们将成为我经验中的闪光点。
使用 Python、Django 和 PostgreSQL 的数据工程
今天的帖子将讨论数据科学中最困难的方面之一,它不涉及分析,而只是试图让数据科学的后端工作。我所说的后端指的是大多数数据科学家在工作中会用到的数据库系统。
我将回顾以下内容:
- 用关系数据库管理系统(RDBMS)构建一个绝对的准系统 Django 应用程序
- 演示附加到 Django 应用程序的 PostgresSQL 数据库的使用
- 如何在不同格式和平台之间移入和移出数据
虽然阅读本文不需要任何 Django 知识,但我认为重要的是要认识到大量数据收集是通过 web 应用程序进行的。
对于不熟悉 Django 的数据科学家来说,可以把它看作是一个构建 web 应用程序的框架,同时坚持“控制反转”的哲学。这意味着 Django 负责 web 应用程序的框架,而您负责在框架上充实实际内容。
对于不喜欢 Django 的读者,你可以跳到这篇文章末尾的标题为*“回报:Django 的对象关系映射器”*的部分。
我们的 Django 应用程序:“DoubleBagger”
我感兴趣的应用程序将被称为“DoubleBagger”,这是一个投资博客,人们可以在这里自助发表对苹果(股票代码:AAPL)或微软(股票代码:MSFT)等上市公司的买入/卖出意见。
这次我们将主要使用命令行+一个像 Sublime Text 这样的文本编辑器,而不是像我以前的文章那样使用 Jupyter 笔记本。
因为这是针对数据科学家的,我们将使用 conda 环境:
# I like to do things on my desktop
# From the terminal:$ cd desktop && mkdir doublebagger && cd doublebagger$ conda create -n doublebagger
$ conda activate doublebagger# You should now have the (doublebagger) conda environment activated
现在我们安装两个主要的包:Django 和 psycopg2,用于连接 PostgreSQL 数据库。Django 已经发布了 SQLite,它实际上可能适合许多组织和爱好者,但是我们将使用 Postgres 来代替。此外,我们将使用 Django 的旧版本(当前版本是 Django 2.1)。
$ (doublebagger) conda install Django==1.9.6 psycopg2
在验证您拥有这些包及其依赖项之后,创建一个源目录,我们将所有与“Doublebagger”相关的源代码放在这个目录中。
$ (doublebagger) mkdir src && cd src
我们用相同的命令以几乎相同的方式启动每个 Django 项目:
# Inside of src:
# don't forget the space and period at the end$ (doublebagger) django-admin startproject doublebagger_blog .
django-admin startproject 命令为我们的项目创建了框架,现在如果您查看 src 文件夹中的内容,您应该会看到:
- doublebagger_blog:包含我们项目的项目配置,包括 settings.py 文件。
- manage.py:实用函数
现在我们可以在 Sublime Text 或您选择的任何其他编辑器中打开我们的 DoubleBagger 项目。您应该会看到完全相同的目录结构:
假设您的机器上已经安装了 postgres 数据库,我们实际上需要为 django 应用程序创建一个 postgres 数据库:
# from the command line:$ psql -d postgrespostgres=# CREATE DATABASE doublebagger;# That's it!
# quit by:postgres=# \q
*如果您没有 postgreSQL,您可以遵循这些指令。
然后在 settings.py(使用 Sublime Text)中,我们更改默认配置以考虑我们刚刚创建的数据库。改变这一点:
# settings.pyDATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
对此:
# Your 'User' is probably different depending on how you set up
# postgres. In many cases, it's just 'postgres'.
# Also depends if you set up a password with you postgres.DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'doublebagger',
'USER': 'WhoeverOwnsTheDatabase',
'PASSWORD': '',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
*确保在文本编辑器中保存您的更改
现在,如果你回到命令行,我们可以像这样连接应用程序和 postgres 数据库:
# Still inside of your src where manage.py lives:$ (doublebagger) python manage.py migrate
如果一切顺利,您应该会看到类似这样的内容:
现在从同一个命令行:
$ (doublebagger) python manage.py runserver
并将您的浏览器指向:
127.0.0.1:8000
您应该会看到类似这样的内容:
image sponsored by fakedoors.com
这实际上是从 Django 的本地开发服务器上显示的假想 web 应用程序的主页,旨在模拟真实的 web 服务器。你可以用退出开发服务器。
这几乎是这个应用程序的全部了——甚至没有基本框架,甚至没有 hello world。
那么,我们为什么要费这么大的劲来做这件事呢?
因为 Django Models 为其用户提供了一个对象关系映射器(ORM ),允许我们在连接到 postgresSQL 数据库时使用 python 操作模型对象。这只是构成 pythonic 数据科学生态系统的绝对动物园的一个更复杂的层次和意识。
此时,我们需要考虑数据的组织。
我们的 web 应用程序将主要有两个主要组件或模型类:
- 帖子:关于是否投资特定公司的博客帖子
- 公司:博客文章中提到的公司的信息
帖子将包含以下信息:
- 帖子的标题
- slug:基于标题的博客文章的唯一标识符)
- 文本:实际的博客文章文本
- 发布日期:文章发布的时间
公司将包含以下信息:
- 公司名称
- slug:公司的唯一标识符
- 描述:该公司做什么
- 市盈率:公司相对于市场价格的估值指标
在我们将其转化为 Django 模型代码之前,我们需要先创建一个 Django 应用程序。
# We're going to call our app 'post'
# Inside of src from terminal:$ (doublebagger) python manage.py startapp post
现在,您应该可以在文本编辑器中看到 post 应用程序:
之后,我们必须在 settings.py 中的 INSTALLED_APPS 下添加我们的“post”应用程序:
# settings.pyINSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'post',
]# Don't forget to save changes
现在,我们可以通过 post/models.py 为我们的数据编写组织代码:
# post/models.pyfrom __future__ import unicode_literalsfrom django.db import models# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
text = modelsle.TextField()
pub_date = models.DateField()class Company(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField()
description = models.TextField()
pe_ratio = models.DecimalField(max_digits=7, decimal_places=2)
在这一点上,我们需要考虑的模型的最重要的方面之一是这两件事是如何相互关联的。如果我们看看上面所做的,从 SQL 的角度来看,Post 是一个表,Company 是它自己的表,下面的字段如 title、slug 和 pub_date 代表两个表的列。
对于 SQL,我们需要考虑我们的两个模型之间的关系是否是:
- 一对多或多对一
- 多对多
如果你考虑一下,我们这里有一个岗位和公司之间的多对一关系:
“一篇博文只能是一篇关于一家公司的投资论文,但一家公司可以有很多篇关于它的博文。”
因此,我们的 Post 模型将有一个外键指向 Company。
Django 的美妙之处在于,它为我们处理了通常从零开始创建数据库模式的所有困难工作——不需要显式创建主键,不需要索引或多对多关系的连接表。
我们可以像这样添加外键:
# post/models.pyclass Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
text = modelsle.TextField()
pub_date = models.DateField()
company = models.ForeignKey('Company') # Here
添加一些额外的参数和字符串方法,允许我们的模型对象被字符串名称引用,这是我们最终更新的 post/models.py:
# post/models.pyfrom __future__ import unicode_literalsfrom django.db import models# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=50, unique_for_month='pub_date')
text = models.TextField()
pub_date = models.DateField('date_published', auto_now_add=True)
company = models.ForeignKey('Company')def __str__(self):
return "{} on {}".format(
self.title,
self.pub_date.strftime('%Y-%m-%m'))class Meta:
verbose_name = 'investment thesis'
ordering = ['-pub_date', 'title']
get_latest_by = 'pub_date'class Company(models.Model):
name = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(max_length=50, unique=True)
description = models.TextField()
pe_ratio = models.DecimalField(max_digits=7, decimal_places=2)def __str__(self):
return self.nameclass Meta:
ordering = ['name']# Don't forget to save your changes
现在神奇的部分来了,Django 为我们创建了一个 postgreSQL 数据库。
回到命令行:
$ (doublebagger) python manage.py makemigrations# Then $ (doublebagger) python manage.py migrate# That's it!
您应该会看到类似这样的内容:
回报是:Django 的对象关系映射器(ORM)
现在,我们可以像数据科学家一样,只使用 Python 与 PostgreSQL 数据库进行交互!
从命令行:
$ (doublebagger) python manage.py shell
您应该看到一些让您想起 Python 解释器的东西,除了这个允许您使用 Django 的数据库:
>>> from datetime import date
>>> from post.models import Post, Company
让我们创建一个公司对象:
>>> Company.objects.create(name='Apple', slug='Apple-incorporated-nasdaq', description='One of the greatest companies in the world created by the amazing Steve Jobs.', pe_ratio=14.43)
您应该会看到这样的内容:
<Company: Apple>
不需要:
INSERT INTO company
(name, slug, description, pe_ratio)
VALUES
('Apple', 'Apple-incorporated-nasdaq', description='...', pe_ration=14.43);
更多公司:
>>> Company.objects.create(name='Amazon', slug='amzn-nasdaq', description='AWS baby!', pe_ratio=81.48)>>> Company.objects.create(name='Microsoft', slug='msft-nasdaq', description='I love GitHub!', pe_ratio=26.02)>>> Company.objects.create(name='MongoDB', slug='mdb-nasdaq', description='JSON in the cloud', pe_ratio=100)>>> Company.objects.all()# Output:[<Company: Amazon>, <Company: Apple>, <Company: Microsoft>, <Company: MongoDB>]
我们还可以做一些很酷的查询:
>>> Company.objects.get(slug__contains='mdb')# Output:<Company: MongoDB>
谁喜欢元组:
>>> Company.objects.values_list()# Output:[(3, u'Amazon', u'amzn-nasdaq', u'AWS baby!', Decimal('81.48')), (1, u'Apple', u'Apple-incorporated-nasdaq', u'One of the greatest companies in the world created by the amazing Steve Jobs, not so currently under Tim Cook.', Decimal('14.43')), (2, u'Microsoft', u'msft-nasdaq', u'I love GitHub!', Decimal('26.02')), (4, u'MongoDB', u'mdb-nasdaq', u'JSON in the cloud', Decimal('100.00'))]
我们还可以创建一个 Post 对象:
>>> Post.objects.create(title='I heart Apple', slug='i-heart-apple', text='I heart Apple', company_id=1)>>> Post.objects.create(title='Buy more Microsoft', slug='buy-more-microsoft', text="Nadella leads the way", company_id=2)>>> Post.objects.create(title='Buy more Amazon', slug='buy-more-amazon', text="Jeff Bezos acquires Mars from Elon Musk", company_id=3)>>> Post.objects.create(title='Time to sell MongoDB', slug='time-to-sell-mongdb', text="MongoDB seems a little overvalued", company_id=4)
我们还可以验证这些对象确实存在于 postgreSQL 数据库中:
$ psql -d postgres
postgres=# \c doublebagger
doublebagger=# \dt
doublebagger=# SELECT * FROM post_company;
您应该会看到类似这样的内容:
和一个 SQL 连接:
doublebagger=# SELECT * FROM post_company
doublebagger=# JOIN post_post ON
doublebagger=# post_company.id = post_post.company_id;
从 postgreSQL 到熊猫
使用 sqlalchemy 我们可以直接从 pandas 访问 postgreSQL 对象:
如果你启动一台 Jupyter 笔记本:
import pandas as pd
from sqlalchemy import create_engineengine = create_engine('postgresql://sammylee@localhost:5432/doublebagger')posts = pd.read_sql('select * from post_post', engine)companies = pd.read_sql('select * from post_company', engine)posts_companies = pd.merge(companies, posts, left_on='id', right_on='company_id')posts_companies
现在,作为数据科学家,我们可以充分利用熊猫的力量和魔力做我们想做的任何事情。
虽然 web 开发框架的知识对于数据科学家来说不是必需的,但我认为退一步看看亚马逊森林是非常酷的,从 Django 到 postgreSQL 再到 pandas 都是数据科学。
还有一点
Django 有一个“包含电池”的理念,它提供了一个管理界面,基本上作为 postgreSQL 数据库的 GUI。我们所要做的就是在 post/admin.py 中添加一些行
# post/admin.pyfrom django.contrib import admin
from django.db import models# Register your models here.
from .models import Post, Companyclass MyCompanyAdmin(admin.ModelAdmin):
model = Company
list_display = ('name', 'slug', 'description', 'pe_ratio',)admin.site.register(Company, MyCompanyAdmin)
并在命令行上创建超级用户:
$ (doublebagger) python manage.py createsuperuser# Then create your credentials
# start up your local development server and head to your local host
# and append "/admin" to it
双重行囊者生活的代号在这里。
用对立的自动编码器进行数据探索
使用对立的自动编码器模型研究多元时间序列数据的非监督聚类的不同方法。
L 和许多人一样,我用自动编码器开始了我的深度学习之旅,因为它们是开发人工神经网络直觉的一个很好的切入点,并让你的头脑围绕你选择的深度学习框架。起初是一个没有多少相关用例的练习,如今已经找到了许多应用,结果是一把深度学习的瑞士军刀。自动编码器通常用于检测异常,学习可以输入到其他神经网络的低维表示,生成数据等等。在这篇文章中,我想向你介绍一种叫做对抗性自动编码器的特殊架构,以及随之而来的自动编码器的新应用,数据的无监督聚类,这将是我在这篇文章中主要关注的。我想讨论这样一个编码器的工作原理,并向您展示如何使用 Keras 轻松构建和训练它们,以及如何使用它们在一个涉及外汇市场数据的例子中聚类和探索时间序列。
引入对抗性自动编码器
当我第一次开始进入深度学习时,自动编码器让我着迷,我喜欢它的设置如此简单,以及用它们进行实验如何快速让你培养对人工神经网络的感觉。这个想法非常简单,训练一个神经网络模型,在网络的中间有一个信息瓶颈太小,数据无法通过的约束下,复制它的输入。这种限制要求自动编码器找到适合该瓶颈的输入数据的表示,以便随后尝试从该表示尽可能精确地再现它。它必须找到一个简洁的*代码——因此得名自动编码器——它通常也被称为潜在向量。虽然这听起来非常简单,*这种类型的神经网络允许你为任何类型的数据找到一个几乎任意低维的表示,同时你也获得了一个数据样本的不寻常或异常程度的度量,这取决于它的重建误差。
抽样问题
有一件事你不能用普通的自动编码器来做,那就是生成新数据。理论上,你可以把一些随机向量输入到解码器部分,得到新的猫图片或者你已经编码的任何东西。这不起作用的原因是,编码器产生的潜在表示不以任何方式分布,它可以通过简单的参数分布来表示,就像正态分布一样,您可以从中进行采样。相反,潜在空间经常出现分裂成代码空间中的不同域,如果你只是向解码器提供从像正态分布这样的随机变量中采样的随机向量,你很可能最终只生成垃圾。换句话说,你不知道如何为解码器选择随机值来产生高质量的猫图像。
为了解决这个问题,发明了变分自动编码器来训练编码器学习潜在分布的参数,然后可以从解码器采样并馈入解码器。问题仅仅在于它们往往难以训练,并且即使变型自动编码器在捕捉随机性质的数据的属性方面更好,并且在采样和生成数据方面具有更好的属性,但是它们产生的样本仍然经常包括较差的示例,主要是在输入数据的类别之间的边界上,如果存在的话。潜在空间仍然没有得到理想的分布,特别是如果数据不能被在变分推断过程中使用的高斯分布很好地近似。此外,有一件事你不能用变分编码器做,那就是让潜在的代表采取任何任意分布的性质,因为他们只学习多重高斯分布的性质。但是如果你想从贝塔分布或者均匀分布中取样呢?
规范代码
自从生成对抗网络和对抗训练方法的出现,神经网络不仅能够学习分类,还能够产生照片级的图像,现在甚至是视频。事实证明,在 GANs 中用于训练发电机的相同技术也可以用于调整你的神经网络的属性。敌对自动编码器背后的想法是,你训练编码器产生一个潜在的空间,看起来像你选择的先验分布。如果您的先验是正态高斯分布,那么编码器产生的潜在向量也将假定该分布,值的平均值为 0,标准偏差为 1,您可以轻松地从中进行采样。你基本上可以把任意的分布强加到潜在空间上,甚至是那些不能用参数化的方式表达的,只要你有一个从它们中取样的方法。
由于这是对抗训练中的传统,这是通过一个鉴别器实现的,这是一个不同的神经网络模型,它学习从目标的现实世界*示例中辨别网络的输出;*但是,鉴别器不是学习从真实的猫图片中辨别噪声,而是学习从先验分布中辨别潜在空间,并向编码器反馈潜在空间的分布有多错误。根据这种梯度形式的反馈,编码器学习按需要分配代码。
如何用它对数据进行聚类?
在关于对抗性自动编码器的原始论文的第 5 章和第 6 章中,作者概述了如何将他们的架构用于无监督聚类的方法。其思想是,除了潜在向量之外,编码器还将生成一个分类向量或所谓的一个热编码的向量,因此该向量的一个值为 1,所有其他值为 0。该向量也将被馈送到解码器中用于重建,使得它也可能携带关于输入数据的相关信息,基本上是用于重建的某种附加提示。这个想法是,这个提示对于相似的输入数据也是一样的,这些相似性是我们希望编码器找到并编码到类别中的。与经典的聚类算法相反,在经典的聚类算法中,预定义的参数决定了如何分离数据,编码器和解码器只在不同类别之间的界限上达成一致,这可能会导致有趣的结果。
为了让编码器产生一个分类向量,而不仅仅是另一个任意值的潜在向量,作者还使用了带有鉴别器的对抗训练,该鉴别器被教导来辨别向量是否是分类的。以与潜在向量相同的方式,鉴别器根据编码器产生的向量以及“先验分布”来训练,在这种情况下,先验分布是一束随机的独热向量。该鉴别器还将向编码器反馈向量遵循规则的程度,并通过使其成为编码器目标的一部分来满足鉴别器,它将学习创建分类向量。
Schematic of an Autoencoder that produces a regularized latent vector z and a categorical vector c with the help of two Discriminators
数据
因为 MNIST 手写数字数据集已经由作者在论文中完成了,并且在这一点上可能超出了理性的探索,所以我想尝试一些更有趣的东西。不,不是猫的照片,很不幸。我想在这里讨论的实验是我最近研究的,作为我个人探索建立算法交易系统的一部分,就像我之前的许多人一样,因为它提出了一个有趣的挑战。对于这个例子,我将使用外汇数据,特别是 2018 年的欧元兑美元汇率,以 5 分钟为间隔。你可以从互联网上的很多地方获得这种数据。我从一家名为 Oanda 的在线经纪商那里获得了我的 API,主要是因为我喜欢他们的 REST API,你可以通过一个免费的票据交易账户来使用它,以访问可用工具的所有历史市场数据。最后,无论您是使用外汇数据,还是将本文概述的相同策略应用于股票或加密或非金融时间序列数据,如物联网传感器或医疗数据,都无关紧要。你可以在文章末尾附上的笔记本中找到下载和预处理数据的代码。
One day of EUR-USD exchange data in 5-minute intervals with open, high, low and close prices.
The volume data for the above time period
我们将从原始交易数据中创建并最终提供给自动编码器的特征将是最高价、最低价和收盘价的对数回报、交易量,以及一些统计数据,如收盘价的滚动平均值、方差和偏斜度以及一些技术指标、相对强弱指数、平均真实范围和移动平均收敛发散信号线。除了包括包含关于趋势强度和方向、波动性和与平均值的偏差的指示的特征,以及具有编码器必须找到潜在相关性、模式和简洁表示的一些特征之外,没有做出选择的特定原因,并且仅在有噪声的回报数据上进行聚类不会产生最有意义的结果。当然,你还可以加入许多其他特性,或者添加信号和数据源。
An excerpt from one of the data frames with the raw features.
为了让编码器创建一个较低维度的表示,并将其重新创建为一个序列,我们需要处理固定长度的信号,因为时间分量在压缩中丢失,并且在构建编码器时需要明确定义序列长度,因此我决定将数据切割为 32 个时间步长的窗口。由于我们的数据特征在不同部分具有非常不同的值范围,如价格、交易量和指标,我们在每个窗口的基础上为每个通道执行 z 得分标准化,以将所有特征纳入相同的值范围,并保留局部模式,但不混合过去或未来的极值。这将是编码器将尝试聚类的数据,即以 5 分钟时间间隔的 32 个读数的序列中的局部运动,如下图所示。
A few frames of preprocessed data, as they will be fed to the autoencoder. The values are in a comfortable range for ANNs. We expect the encoder to find patterns in this mess of squiggly lines.
**注意:**我已经讨论了很多关于如何预处理数据的问题,通过对整个数据或每个窗口进行标准化或规范化。我发现这很大程度上取决于。如果你要建立一个算法交易系统,你想把编码器的结果输入到一个分类器中。那么您可能也会在每个窗口的基础上进行标准化。这意味着编码器将通过这些局部模式对数据进行聚类。如果您有一个从不更改的数据集,并且您不关心未来的值,并且希望按全局属性对数据进行聚类,那么对整个数据进行规范化或标准化可能会更有意义。在进行了一些实验之后,我可以说这两种方法对于这种类型的数据会产生非常不同的聚类类型。
构建对抗性自动编码器
因为我们处理的是时间序列数据,所以我们将主要从循环层构建编码器和解码器。简单的 LSTM 不适用于对时间序列数据进行编码的特定任务。经过一些试验后,我惊讶地发现,双向 LSTMs,另一方面,比我迄今为止尝试过的任何东西都要好,包括卷积网络。有些人还推荐卷积网络和递归网络的组合,无论如何,可能需要一些实验来找到适合您的数据类型的架构。
编码器和解码器都主要由两个堆叠的双向 LSTM 组成,其中编码器的第二 LSTM 不返回序列,而仅返回其最后状态作为潜在表示和分类向量的基础。解码器由一个类似的反向设置组成,输入潜在向量和分类向量的组合,并尝试将其解码为尽可能匹配输入的序列。
鉴别器被设计成简单的多层感知器,由几个密集连接的层组成,因为它们只需要区分相当低维的向量的分布,所以你不能把它们做得太好,否则编码器将不能欺骗鉴别器,也不能正确地收敛于任何任务。这也考虑到对每个任务的损失进行加权,输入的重建将不得不产生梯度的大部分,否则编码器将不会学习到任何有用的东西。另一方面,你也不能让他们太弱,否则他们不会学会区分样本,也不会发生正则化。
下面是为编码器/解码器和鉴别器创建网络的代码。你可以看到,正如论文作者所建议的,我们只在编码器部分使用了批量标准化。我也尝试在解码器部分使用它,对于无监督聚类应用程序,我可以确认它只会恶化性能。您可以看到,分类向量将 softmax 作为激活函数,这有助于形成分类分布,而潜在向量是用线性函数激活的,因为它需要能够输出未绑定范围内的值,以便能够满足指定的分布。然后,简单地将潜在向量和分类向量连接起来,并对输入序列的长度重复该结果,从而解码器部分可以再次将其重建为相同长度的序列。我还在输入后添加了一个线性变换,因为我发现当使用整流器和负值输入时,它在一定程度上加快了训练速度。
The code to create the autoencoder model.
The code to create the discriminator models.
当训练自动编码器时,两个鉴别器的输出成为自动编码器损耗的一部分。他们的目标只是简单地总是 1 ,对于实数,因为我们希望编码器学习一个表示,使鉴别器输出 1 ,基本上是说“啊,是的,这是来自先前分布的样本”。二进制交叉熵作为损失函数工作得很好,如果编码器产生不满足鉴别器的潜在向量或分类向量,损失将产生梯度,这将使编码器学习理论上遵循规则的潜在和分类表示。
The Encoder is updated with gradients from the Decoders reconstruction loss (Mean Squared Error) and the Discriminators loss (Binary-Crossentropy)
下面是用于将编码器和鉴别器粘合到模型中的代码,然后我们可以按照上面的示意图进行训练。请注意我们是如何将鉴别器权重设置为trainible = false的,这在此时是必要的,因为我们将它们连接到自动编码器中,并且在训练编码器时,我们不希望鉴别器的权重发生变化。稍后在训练鉴别器时,我们会更改这个设置,但你必须在给它们接线时进行,否则 Keras 或者更确切地说 TensorFlow 会抱怨说组可训练重量已经改变。
The code to wire the autoencoder together with the discriminators and create an adversarial autoencoder.
训练编码器
为了训练这种设置,我们首先从训练鉴别器开始。为此,让编码器创建一批潜在的和分类的向量,并创建第二批向量,从先前的分布中取样。接下来,使用各自的标签训练这些批次的鉴别器,编码器输出的标签为 fake (o) ,先前样本的标签为 real (1) 。然后,您冻结该训练迭代的鉴别器的权重,因为您不希望在训练编码器时更新鉴别器,因为误差将流经它们。接下来,您对一批数据训练编码器,目标是尽可能准确地再现输入,同时还有另外两个目标来满足两个鉴别器,也就是 aka。对于真实样本,使它们输出 1。在重复了大约几千次随机小批量训练迭代之后,自动编码器开始在所有三个任务上收敛。
在训练过程中,您可能会注意到,只要编码器仍在学习编码和解码,鉴别器的精度只会缓慢下降,只有当来自该目标的梯度变得较浅或平稳时,编码器才会学习重新分配潜在空间和分类向量,这反过来会再次恶化编码/解码性能,这将使梯度朝着较低的重建误差变陡。这意味着学习过程通常遵循某种反馈循环,这也是由于鉴别器随着时间的推移变得越来越好,随着训练的进行,这种反馈循环将变得不那么强烈。
现在,当我们让上面代码中所示的训练循环总共运行 10,000 次迭代时,您可能会得到类似下图中的损失图,这些图来自我用包含的代码为本文训练的示例运行,我想在下面进一步讨论。
在图像中,您可以看到测试和验证集的重建损失在适当减少,因此看起来我们并没有过度拟合。分类向量鉴别器的精度在 50%到 70%之间,其中 50%是非常理想的,因为在这一点上,鉴别器在区分向量方面的表现并不比随机猜测好,这意味着编码器能够成功地欺骗它。潜在向量鉴别器的精度看起来并不那么高,在下降到大约 60 之后,我们可以看到它再次上升,因此看起来鉴别器比编码器略胜一筹,但我们也可以看到它再次缓慢下降,因此随着更多的训练,它可能会收敛。不理想,但对我们的目的来说足够好了。
From left to Right: Loss of Discriminators for Prior and Category and the Encoder/Decoder, including validation loss, after 10.000 iterations, So far we cannot see any overfitting, but loss for the discriminator converges slowly.
尽管我们可以看到准确性和重建损失降低,但在训练完成后直观地确认结果仍然是一个好主意,并查看几个示例以了解自动编码器是否真正学会了以合理的方式再现输入,以及我们是否实现了生成实际分类向量的目标。
下面是编码器产生的输入和输出的几个例子,以及潜在和分类向量。在示例中,您可以看到重构是输入的强去噪版本,几乎就像编码器将捕获输入的主要频率成分,这似乎是在代码空间的约束下近似再现此类噪声数据的最佳方法。此外,我们还可以确认,我们成功地尝试了正则化编码器,以产生用于我们的聚类的分类向量;它们似乎有一个接近 1 的值,其余的值在 0 附近徘徊,更好的是,分类向量似乎对于大多数示例都不同,这意味着编码器确实为不同的输入分配了不同的类别。误差图主要是来自未通过的输入信号的噪声,尽管我们可以看到,当突发尖峰出现且未得到正确编码时,一个通道或通道组合的误差有时会特别高,因为这可能是一种不常见或异常的模式。
A few samples from the autoencoder model. From left to right: Input data, latent vector, categorical vector, reconstructed data, and error.
数据聚类
既然 autoencoder 已经被训练好了,我们就可以用它来为我们所有的数据生成类标签,我们终于可以看看我一直向您保证的这些聚类了。首先,让我们看看这些类是如何分布的。分配给分类向量的大小不一定对应于自动编码器将识别的分类数。我经常会上 6 到 7 节课,有时是全部 8 节,有时只有 4 节。在运行了几个实验之后,我可以报告,聚类的数量和聚类的属性高度依赖于自动编码器超参数和架构、小批量大小和所使用的优化器,并且还显著地依赖于与编码器相比的鉴别器的强度。它似乎更依赖于网络的超参数,而不是数据本身。
The Histogram of classes discovered by the encoder.
在这个例子中,编码器似乎使用了所有 8 个类别来对输入数据进行分类,并且被识别的类别似乎或多或少地均匀分布,尽管我们已经可以看到,在我们的数据集中,类别 0 有点过多,而类别 1 有点不足。现在,让我们看看当我们在 2D 平面上对输入数据执行 t-SNE 时,编码器发现的类是否实际上形成了某种聚类。下图显示了编码器分配的类别标签实际上形成了大部分一致的聚类,但是一些聚类看起来更加分散,并且具有远离其聚类中心的样本,这在一定程度上可能是所使用的嵌入算法的副作用。
t-SNE scatterplot of input data, labeled by categories. From left to right with Perplexity of 10, 30 and 50
这里有一个替代方案,在相同的网络设置下,使用了稍大的批量,并使用 Adam 代替 Nadam 作为优化器。它在训练中以非常相似的方式收敛,但结果却大不相同。编码器只将数据分为 6 类,而不是全部 8 类。下面是直方图,我们可以看到所有的类分布相当均匀。
我发现分类向量的鉴别器越强,编码器对数据进行分类的类别就越少,而鉴别器越松,分类就越分散。这两个结果本身都是有效且有趣的。
我将继续主要关注产生 8 个类的示例,因为我喜欢这些结果,但我想展示对超参数进行小的更改,结果会有怎样的不同。
The Histogram of classes discovered by the encoder with a slight variation to the hyperparameters.
t-SNE scatterplot of alternative clusters, labeled by categories. From left to right with Perplexity of 10, 30 and 50
所以,现在我们有了一些类别,它们形成了彩色的斑点,但是这些类别是什么意思呢?好问题!与许多无监督聚类算法一样,这些结果更像是一种启发,让你思考和困惑你的数据,以及该算法在这里可能发现了什么,以便你可以进一步研究它们。我只想快速浏览一下这些类的一些属性。如果我们在处理和标准化之前将类别映射回原始输入窗口,并查看一些统计属性,我们可能会发现类别之间有趣的差异。
每类值的分布
首先,我想看看每一类的值在该类的所有帧上的直方图,看看我们是否能够发现分布中一些有趣的差异。当我们为输入数据的最重要通道创建直方图时,就像我们计算的指标一样,我们可以看到分布、不同均值、标准差和偏斜的属性之间的一些差异。
取决于聚类的结果,有时在一些信号的分布中存在很大差异,而有时在其他信号中差异更大。在这个例子中,ATR 信号通常具有有趣的形状分布,其中许多看起来有点像高斯混合,并且似乎每一类都有不同的均值。MACD 信号线似乎是不同类别的强大驱动力,因为我们可以看到,大多数值位于一个狭窄的范围内,每个类别的均值完全不同,类似的情况也可以说是关于收盘价格回报的分布。RSI 信号的分布看起来非常像适当的高斯分布,模式和偏斜在类别之间也略有不同。
Histograms of some channels of the input data, each row representing one of the 8 classes.
平均信号形状
在本文的前面,当谈到预处理输入数据时,我提到了我们希望编码器找到并压缩的局部模式。考虑到上面的直方图,看看每一类是否真的出现了共同的模式会很有趣。所以基本上,我想看看每个类的单个通道的值是如何随时间发展的。
为此,我们只需计算一个类中所有信号在每个时间步长上每个通道的平均值。实际上,我希望得到的大多是没有明显方向的曲线,对于原始的高、低和收盘回报信号来说,大多数情况都是这样,尽管对于某些类别来说,这些信号似乎平均起来是某种“波动”运动。更有趣的是滚动统计的信号和我们添加到原始数据中的技术指标,我们可以看到每个类别的明显趋势。对于一些类,一些通道向相反的方向移动,而在另一些类中,它们一起移动。此外,我们可以看到,对于数据中发现的所有类别,MACD 信号线和收盘价的移动平均值似乎高度相关,并以某种方式一起移动,ATR 和收盘价收益的方差似乎也是如此,这是有意义的,因为在这两种情况下,这些统计数据和指标对相同的事情,波动性和趋势做出了略有不同的陈述。
一个错误胜过千言万语
不管你打算用你的自动编码器做什么,你总是可以免费得到一件东西,那就是异常检测。一旦编码器被成功训练,重建中的大多数误差应该是输入数据中的噪声的结果。如果观察每个通道的重构误差值的分布,可以看到分布以零为中心,大多数通道的标准偏差相当低,但我们可以看到某些部分也有一些极值。因为编码器在潜在空间的约束和限制值范围的强加分布的附加约束下,学会最好地重构出现在大多数样本中的模式。仅在少数样本中出现的模式可能没有适当的编码,因为根本没有用于它们的空间,这导致重建质量差。这种重构误差可以很好地检测这些不常见的事件,并将其归类为数据集中的异常值或异常值。
下面你可以看到每个通道的误差值直方图。我们可以看到,所有通道的误差都集中在 0 附近,但具有不同的标准差。如果您想要检测数据中的异常或识别异常事件,您可以为每个通道选择一个阈值,当重构误差的峰值超过该阈值时,就表示发生了异常事件。
Histograms of reconstruction error for each channel.
由于我们还尽了最大努力对我们的数据进行聚类,因此您可以在更细粒度的规模上这样做,并为每个类中的每个通道选择不同的阈值。当我们查看按类划分的每个通道的误差直方图时,我们可以看到误差的分布在类之间有轻微的差异。
结论
使用对立的自动编码器对数据进行聚类无疑是您可以采用的更奇特的方法之一,即使对于包括时间序列和表格数据在内的许多问题可能有更传统的算法,当然也有许多其他情况可能不是这样,例如在处理图像数据时。
通常对于传统算法,您必须试验某些参数,如邻域需要多少个点,它们应该有多远,或者您期望有多少个聚类,然后检查结果是否令人满意。使用这种方法,您必须对架构和超参数进行试验,找到合适的方法比使用更简单和优化的算法要耗时得多。
考虑到您在这里做一些深度学习,整个例程比常规的非工厂聚类算法花费更长的时间,消耗更多的计算能力,但这种方法肯定非常有趣。更有可能的是,您构建 autoencoder 是出于不同的原因,而不仅仅是为了聚类,但是现在您应该知道如何不仅可以正则化潜在的表示,还可以让您的 autoencoder 同时对您的数据进行聚类。
代码空间怎么了?
一开始,我谈了很多关于编码器产生的代码空间,以及我们需要如何正则化它们等等,但是在所有关于分类向量的争论中,我从来没有向你们展示过在所有这些训练之后代码空间实际上发生了什么。查看来自潜在空间的值的直方图,我们可以清楚地看到构造良好的高斯分布。看起来正规化运作得很好。看起来,即使歧视者并不十分满意,但它似乎变得太挑剔了。潜在空间的 t-SNE 看起来也有点像 2D 高斯分布,如果你将标签添加到代码空间,你可以看到这里的聚类不太一致。
The distribution of activation values of the latent space, after the training. It looks like the regularization worked just fine since we wanted a normal distribution.
t-SNE of latent vectors labeled with the discovered classes. Looks like a 2D Gaussian Distribution.
非常感谢您的阅读,下面是如约而至的 jupyter 笔记本。
以数据为中心的组织决策:DSI 案例研究
2018 年春末,我被选为 DSI (数据科学与信息学)的主席,这是佛罗里达大学的数据科学学生团体。我们教授研习班(Python、R、NLP、ML,你能想到的都有)并发展数据科学社区。我当选后不久,就发生了这样的事:
“如果我管理一个数据科学组织却不将数据科学应用于其中,我会是什么样的白痴呢?”
这篇文章的其余部分阐述了我们如何在整个 2018 年秋季,将组织从“我们只有很少的数据,我们确实拥有的数据无法使用”的状态带到“我们有一个有组织的有用的数据来源,并开始根据我们产生的见解采取行动。”在阅读数据科学相关帖子的这些年里,我经常感觉这种数据工程/收集/综合工作被低估了,所以我们开始吧!
数据来源
幸运的是,DSI 有为我们的研讨会创建签到表的历史,签到表上有参与者的详细信息,包括姓名、电子邮件、专业以及他们的编程经验。然而,我们在过去 3 年中保留的数据并没有考虑到分析,在数据清理过程之前,自动生成的 google sheets 看起来有点像这样。
有一年,DSI 以字符串形式跟踪参与者的班级(大一、大二等),另一年以整数形式(1、2 等)跟踪参与者在佛罗里达大学的年数,但无法区分一年级研究生和一年级本科生,甚至还有三分之一保持学术地位(本科生对研究生)。我们跟踪了电子邮件 5(!!!!)不同的方式:email、Email、e-mail、Contact(电子邮件)和 E-mail。这些差异显然是多年来随着执行委员会的更替和新人创建签到表而产生的,这是有道理的,并且来自良好的直觉!但是最终数据是部分不可用的,因为它不是分析优先。
这里的教训是:随着数据的增长,任何花费在数据意图上的时间都会以 10 倍的速度增长。 DSI 已经成为佛罗里达大学分析和教学的支柱,随着该组织的成熟,每年为一千多名学生提供服务,数据问题也随之增长。
标准化和自动化
标准化数据相当于问,在我们的例子中,我们想了解来我们工作室的人什么?要知道一个组织/公司关心什么,最简单的方法就是找出他们跟踪的内容。是用户增长吗?复读?人口特征?一旦您的组织走到一起并弄清楚了这一点,标准化就会自然而然地到来。
我们的解决方案?模板化表单和 R 包。该表单确保一次又一次地保存相同的数据,并且该包自动地抓取这些表并将数据拉在一起。新的执行委员会正在使用登录信息和数据库创建一个更好的解决方案,但 google sheets 和几个好的 R(或 Python)脚本应该可以在必要时使用。
最后,在这一点上,我们有了一个相对干净的数据集,其中包含了 DSI 多年来的历史,我们可以尝试使用这些数据来进行使命驱动的组织变革。在我看来,这是数据科学中最难的部分,因为你永远不知道你正在研究的东西是否有用。如果我们花了这么多时间,这么多努力,却一无所获呢?没有先验的方法知道数据的价值,只有后验的。这就是为什么讨论数据收集和清理如此重要,因为它占工作流程的 80%。DSI 没有业务端;我们教书和提供帮助是因为我们喜欢它,并发现它很有成就感,我们作为一个组织正在学习的这些课程,无论现在多么便宜,对工作中的年轻数据科学家来说都是无价的
探索性数据分析
回到分析:使用数据推进 DSI 的使命。这就引出了一个问题,DSI 的使命是什么?在 DSI 的最初几年,我们尽可能快地学习和教学。这种方式效果很好,因为在 DSI 的历史上,有大约 2500 名与会者。
这张图表是累计出席人数,但很明显,随着我们的内容和范围不断改善(由于反馈循环比佛罗里达大学几乎任何其他小组都短),学生们将希望学习编程技能。DSI 与会者的细分是预期的,多数是技术专业,但也有大量来自社会研究,工程(正规科学),商业等。
下一个可视化图是返回与会者的直方图,它真正打动了 DSI 执行委员会。很大一部分参加 DSI 的人只参加了一两次研讨会(总共 85%)。
这并不奇怪,因为没有足够的理由多次参加 Python 入门研讨会。作为一个在佛罗里达大学学习数据科学的地方,DSI 已经做了大量的工作,但还没有解决一个不同的问题:创建一个数据科学社区。这为用户保留创建了一个泄漏的用户桶,这不是我们的意图。
创建社区
创建一个社区是困难的,原因有几个,一个是只有好的度量标准的代理。拥有高回报率是一个社区所需要的全部证据吗?当然不是。对于社区来说,这似乎是一个必要但不充分的代理。
我们在 2018 年秋季采取了三项主要举措来尝试建立这个社区。首先,我们创建了 Data Gator ,这是用友与用友图书馆合作举办的第一次数据科学竞赛(如果你是用友学生,你应该参加!!).然后,每隔一周,我们想出了一个叫数据科学星期三的活动,我们的理论是:**社区=数据+咖啡+食物+时间。**我们会给学生提供食物和有趣的数据集,看看他们能想出什么。一个数据集专注于检测毒蘑菇,另一个数据集专注于玩堡垒之夜,其他数据集专注于自行车共享骑行,甚至还有一个数据集专注于口袋妖怪的统计数据,这产生了下图。
最后,在查看了我们研讨会的分类后,我们发现特定行业的研讨会首次参与者的比例更高(在我们的第一个自然语言处理研讨会中,我们有许多语言学博士学生,因为该部门没有教授 Python 课程)。然后,我们继续开发更多的利基研讨会,如数据科学的统计,一个精彩的 Tableau 研讨会,甚至一个精算师研讨会,以吸引校园的不同部分。
结果
在不到一个学期的时间里评估一个组织的变化是很困难的,而且可能是个坏主意。考虑到这一点,上学期出现了一些数字。【2018 年秋季是有史以来参加人数最多的 DSI 学期,参加两次以上研讨会的学生比例翻了一番。
我真的对这些结果感到兴奋,不仅因为这是一个在组织层面上以数据为中心的决策的潜在成功故事,而且因为在我的任期结束后,执行委员会必将把组织带向何方。
无论如何,这是一个更完整的故事,讲述了我们如何在一个学生组织中完成所有枯燥但最有效的数据工作,并通过查看一些漂亮的图表、明确定义我们想要的东西以及做出一些我们可以衡量的改变,看到了一些很好的初步结果。高管团队正在进行其他一些项目,包括为组织建立一个登录系统和适当的数据库,并尝试制作一个“我们应该订购多少披萨”模型来优化我们的预算。在用友没有比这更让我兴奋的群体了(在这里找到他们并在月底参加年度研讨会,请关注这个空间!作为一名推销员,如果你是一名招聘经理,并且已经做到了这一步,那么恭喜你!你的奖励是这条建议:早点雇用这些人,因为我相信很快就会有一场对他们所有人的竞购战。
特别感谢 Delaney Gomen,他在数据清理中发挥了重要作用,也是许多可视化工作的幕后推手。这篇文章的一些内容,以演示的形式,可以在这里找到,来自我 2018 年秋天在用友的一次演讲,部分代码可以在这里找到。
在我的网站上查看更多类似的分析工作,或者在 twitter 上关注我。
公益数据
利用数据促进社会和环境变化
首先,我将说明我所说的“公共利益的数据”是什么意思,因为这里有几个术语(例如#data4good ),没有一个能准确表达这个概念。这是一个正式的定义:
“公共利益数据:通过应用商业应用中常用的工具和技术,将数据用于公共利益”。
如果你对“公共利益”——一个在经济学中广泛使用的术语——感到好奇,这里有一个来自维基百科的定义:
“在经济学中,公益(……)是一种既不可排斥又不可竞争的商品,因为个人不能被排除在使用范围之外,也不能免费享用。”
公益数据一直都有,有什么新鲜的?随着最近大数据和数据科学的革命,在过去几年中,该领域发生了一些重大变化:
- 数据本身
- 方法和工具
- 政策应用
数据种类
公共部门组织大多是在特定的基础上收集和分析数据。只有指定的国家机构(如统计局)每年持续收集、主持和传播数据(如人口普查、家庭调查、农业普查等)。).通常,这些数据集的要素和观测值数量有限,并且通常是从大量人群中获取的小样本。
这些数据收集工作几乎完全是政府的努力。由于缺乏必要的资源和专业知识,非政府组织很少涉足这一领域。他们的商业决策通常依赖于准定量方法或政府报告。
最近情况发生了变化。正在改变商业领域的大数据、数据科学和机器学习领域也在冲击公共部门企业。现在,人们越来越意识到数据在决策过程中的力量。数据的性质也在发生变化——例如,现在可以在社会、经济和环境系统的许多方面获得免费的遥感数据集。然而,公共部门管理和分析这些大量数据的能力没有多大变化,主要是因为缺乏计算资源和人力。
方法和工具
公共部门正在发生的第二种转变是采用新的方法和技术来收集、存储、访问和分析数据。最近,政府机构收集的有价值的数据和信息没有得到充分利用。只有少数人,大部分是学术研究人员,能够获得这些数据并将其用于学术研究。
Photo by William Iven on Unsplash
应用的工具和技术也受到限制。数据分析师会做基本的分析(一些描述性统计、频率/计数表、柱状图、时间序列图或饼状图),并把它们放入年度报告中,然后就完事了!政策决定充其量是由数据告知的*,而不是由数据驱动的。*
公共服务中的应用案例
数据科学在公共服务中的应用目前非常广泛,并且每天都在扩大。这里只是许多例子中的几个:
**犯罪管理:**当地执法机构往往没有社区犯罪管理的必要资源。新颖的算法现在正被用于结合历史犯罪率、社会经济数据和其他数据源来预测犯罪热点。这些新工具正在帮助执法部门有效地分配有限的资源,以确保社区的公共安全。
**农业:**机器学习一直是农业领域的游戏规则改变者。通过自动化灌溉系统减少用水量、疾病检测、产量预测和杂草检测是改变农业的众多应用中的几个。
**医学:**斯坦福大学的生物医学数据科学计划总结了数据科学在医学领域的巨大潜力:
“从治愈单个患者到治愈整个人群,我们正在引领一个更健康的世界。在这个世界中,您的数据不仅会改变您的健康,还会改变世界各地人们的健康。在那里,医生可以立即搜索数百万份医疗记录,找到对像你这样的病人有效的方法。在那里,新药被快速开发出来,现有药物的新用途被发现。我们最终可以预测人类和人群中的疾病,并在疾病发生前预防它。通过利用大规模计算和数据分析的力量,我们将让这个世界成为现实。”
**人道主义项目:**从地震后重建海地,到在利比里亚抗击埃博拉病毒,数据科学工具已经帮助世界各地的弱势人群从危机中恢复过来。预警系统也正在接受测试,以主动应对人类面临的一些重大挑战。
**社会项目:**查看数据种类项目,找出数据科学可以帮助解决的广泛问题的巨大可能性。绘制贫困地图,预测人权侵犯,寻找失踪儿童,防止家庭火灾伤害,预测水需求…什么都不是!
**环境管理:**数据科学工具和技术正在为可持续环境管理带来巨大的潜力——从通过分析大型数据集获得洞察力,到预测下一场森林火灾将在哪里发生,到使用遥感和深度学习对土地使用系统进行分类。
**野生动物监控:**野生动物研究人员和管理人员正在野外安装自动相机,拍摄动物照片。使用机器学习和云计算技术,数百万张这些图像正在被处理和分析,用于分类学分类、测量多样性和监测野生动物运动。
**全球发展:**数据和技术不断改变我们对一些最大的全球问题以及如何解决这些问题的认识。衡量和监测可持续发展目标等全球议程的进展就是一个典型的例子。
结束注释
应对重大挑战需要付出巨大努力,但数据科学在公益领域的应用大多是由组织和个人资助的。但是有太多的问题等待解决。例如,联合国难民署的数据科学家概述了人道主义组织面临的 10 大数据科学挑战。这只是一个部门的 10 个大问题。社会各行各业还有很多人需要帮助。
使用 Pandas 处理数据:清理和处理
掌握熊猫处理“脏数据”
Keep calm, learn Pandas! (Source: Pixabay)
在为一些老的 Kaggle 项目实践时,我意识到在应用机器学习算法之前准备数据文件要花很多时间。这篇文章回顾了一些关于熊猫的初级到高级水平的数据处理技术,作为另一篇文章的前奏,在另一篇文章中,我使用了全球恐怖主义数据和熊猫的一些高级功能进行数据分析。这篇文章是关于数据清理和处理的。让我们立即开始吧!
在这篇文章中,我使用了 IMDB movie-dataset 来介绍最相关的数据清理和处理技术。我们可以从了解以下数据集开始
movies_df = pd.read_csv("movie_metadata.csv")
print "data-frame shape: ", movies_df.shape >>> data-frame shape: (5043, 28)
因此数据集有 5043 行,28 列,我们可以用
print "column names: ", movies_df.columns.values>>> column names:
['color' 'director_name' 'num_critic_for_reviews' 'duration'
'director_facebook_likes' 'actor_3_facebook_likes' 'actor_2_name'
'actor_1_facebook_likes' 'gross' 'genres' 'actor_1_name' 'movie_title'
'num_voted_users' 'cast_total_facebook_likes' 'actor_3_name'
'facenumber_in_poster' 'plot_keywords' 'movie_imdb_link'
'num_user_for_reviews' 'language' 'country' 'content_rating' 'budget'
'title_year' 'actor_2_facebook_likes' 'imdb_score' 'aspect_ratio'
'movie_facebook_likes']
在我们应用一些最大似然算法进行预测之前,比如说“imdb_score”,我们需要对数据集进行更多的调查,因为它不像波士顿大厦数据集那样得到很好的处理。首先,我将讨论如何处理丢失的数据。
处理缺失数据:DataFrame.isna(),DataFrame.fillna()
我们可以使用[pandas.DataFrame.isna](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isna.html)()
来检测数组类对象的缺失值。这将返回一个大小相同的布尔对象,其中 NA 值(如 None 或numpy.NaN
)被映射为 True,而其他所有值都被映射为 False。这与[pandas.DataFrame.isnull(](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isnull.html))
如出一辙。
print "null values: \n",
print movies_df.isna()
上述命令返回以下输出
Looking For Missing Data in data-frame
我们可以通过在前面的命令中添加一个.sum()
来提取相关信息,而不是打印出带有 True/False 条目的数据帧。这样我们就可以找到每一列缺失值的总数。
print movies_df.isna().sum()>>>color 19
director_name 104
num_critic_for_reviews 50
duration 15
director_facebook_likes 104
actor_3_facebook_likes 23
actor_2_name 13
actor_1_facebook_likes 7
gross 884
genres 0
actor_1_name 7
movie_title 0
num_voted_users 0
cast_total_facebook_likes 0
actor_3_name 23
facenumber_in_poster 13
plot_keywords 153
movie_imdb_link 0
num_user_for_reviews 21
language 12
country 5
content_rating 303
budget 492
title_year 108
actor_2_facebook_likes 13
imdb_score 0
aspect_ratio 329
movie_facebook_likes 0
dtype: int64
添加另一个。sum()返回数据集中空值的总数。
print "total null values: ", movies_df.isna().sum().sum()>> total null values: 2698
移除包含 NA 的行的最简单的方法之一是 删除 *它们,*当所有列都包含 NA 或任何列都包含 NA 时。让我们从删除任何列中包含 NA 值的行开始。
clean_movies_df = movies_df.dropna(how='any')print "new dataframe shape: ", clean_movies_df.shape
print "old dataframe shape: ">>> new dataframe shape: (3756, 28)
old dataframe shape: (5043, 28)
因此,删除任何列中包含 NA 值的行都会减少将近 1300 行。这对于行数较少的数据集非常重要,因为删除所有缺少值的行会导致我们丢失必要的信息。在这种情况下,我们可以使用指定的方法使用[pandas.DataFrame.fillna(](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html))
方法向 填充 NA/NaN 值 。用某个固定值(例如 0)填充所有 NA/nan 的最简单方法。我们可以简单地通过
movies_df.fillna(value=0, inplace = True)
我们可以选择一些特定的列,然后使用下面的DataFrame.fillna()
方法,而不是用零填充所有缺失的值
movies_df[['gross', 'budget']] = movies_df[['gross', 'budget']].fillna(value=0)
对于“object”数据类型的列,例如“language”列,我们可以使用“no info”这样的词来填充缺少的条目。
movies_df['language'].fillna("no info", inplace=True)
填充缺失值的另一个method
可以是**ffill**
方法,它将上一个有效的观察传播到下一个。类似地**bfill**
方法使用下一个观察来填补空白。
movies_df['language'].fillna(method='ffill', inplace=True)
另一个有效的方法是用 列的平均值来填充缺失值 如下
movies_df['budget'].fillna(movies_df[budget].mean(), inplace=True)
关于如何使用 Pandas 处理缺失值的更多细节,您可以查看 Pandas 用户指南中关于缺失数据的文档。
数据帧中的重复数据:DataFrame.duplicated()
除了丢失的数据,在一个数据帧中还可能有重复行。为了确定一个数据集是否包含重复的行,我们可以使用 Pandasdata frame . duplicated()来处理所有的列或一些选定的列。**pandas.Dataframe.duplicated()**
返回表示重复行的布尔序列。让我们首先找出这个电影数据集中有多少重复行。
duplicate_rows_df = movies_df[movies_df.duplicated()]print "number of duplicate rows: ", duplicate_rows_df.shape>>>
number of duplicate rows: (45, 28)
因此,每列中有 45 行存在重复的元素。我们也可以对单个列进行检查—
duplicated_rows_df_imdb_link= movies_df[movies_df.duplicated(['movie_imdb_link'])]print duplicate_rows_df_imdb_link.shape>>>
(124, 28)
所以有 124 种情况下 imdb 链接是相同的,检查相同的另一种方法是使用[**pandas.Series.unique()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.unique.html)
方法。让我们看看:
print len(movies_df.movie_imdb_link.unique())>>>
4919
因此,唯一链接的总数是 4919,如果您注意到重复链接是 124,将它们相加得到(4919 + 124 = 5043)总行数。为了更好地分析,有必要选择唯一的行,这样至少我们可以删除所有列中具有相同值的行。我们可以简单地使用下面的[**pandas.DataFrame.drop_duplicates()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.drop_duplicates.html)
来完成
print "shape of dataframe after dropping duplicates", movies_df.drop_duplicates().shape >>>
shape of dataframe after dropping duplicates (4998, 28)
宁滨数据:pandas.cut()
另一个非常重要的数据处理技术是 数据分桶或数据宁滨 。我们将在这里看到一个例子,宁滨·IMDb 使用[**pandas.cut()**](https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.cut.html)
方法得分。基于分数[0。,4., 7., 10.],我想把电影放在不同的桶里['shyyyte ',‘适中’,‘好’]。如你所知,得分在 0-4 之间的电影将被放入“shyyyte”桶中,以此类推。我们可以用下面几行代码做到这一点
op_labels = ['shyttte', 'moderate', 'good']
category = [0.,4.,7.,10.]movies_df['imdb_labels'] = pd.cut(movies_df['imdb_score'], labels=op_labels, bins=category, include_lowest=False)
这里创建了一个包含标签的新列“imdb_labels ”,让我们来看看——
print movies_df[['movie_title', 'imdb_score', 'imdb_labels']][209:220]>>> movie_title imdb_score imdb_labels209 Rio 2 6.4 moderate
210 X-Men 2 7.5 good
211 Fast Five 7.3 good
212 Sherlock Holmes:.. 7.5 good
213 Clash of the... 5.8 moderate
214 Total Recall 7.5 good
215 The 13th Warrior 6.6 moderate
216 The Bourne Legacy 6.7 moderate
217 Batman & Robin 3.7 shyttte
218 How the Grinch.. 6.0 moderate
219 The Day After T.. 6.4 moderate
为了充分利用**pandas.cut()**
方法,您可以查看文档。
检测数据集中的异常值:
大多数时候对于探索性数据分析(EDA), 离群点检测 是一个重要的环节,因为,特定特征的离群点可能会扭曲真实情况,所以我们需要忽略它们。具体来说,当我们想要应用机器学习算法进行预测时,离群值可能会造成严重破坏。同时异常值甚至可以帮助我们进行异常检测。因此,让我们看看如何使用熊猫来检测这个特定数据框架中的异常值。
海风盒子剧情:
*箱线图是一种基于中位数、四分位数和异常值的可视化数据分布的标准方法。*也许你已经知道这些量到底是什么,但我还是在下图中做了简短的回顾。
Figure 1: Schematic of Box Plot (Source: Author)
我们可以使用 python 数据可视化库 Seaborn 来绘制这样的箱线图。让我们用方框图来描绘电影海报中的演员数量分布。
sns.boxplot(x=movies_df['facenumber_in_poster'], color='lime')
plt.xlabel('No. of Actors Featured in Poster', fontsize=14)
plt.show()
上面的代码产生了下面的图
Figure 2: Too many outliers in number of faces featured in movie poster
让我们检查一下电影海报中演员(面孔)数量最多的电影。
print movies_df[['movie_title', 'facenumber_in_poster']].iloc[movies_df['facenumber_in_poster'].idxmax()]>>>
movie_title 500 Days of Summer
facenumber_in_poster 43
因此,电影’夏日 500 天’中出现了最多的面孔(43 张)。让我们用[**pandas.DataFrame.describe()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.describe.html)
的方法来看看这个专栏‘face number _ in _ poster’的一个基本统计细节。
print movies_df['facenumber_in_poster'].describe()>>>count 5030.000000
mean 1.371173
std 2.013576
min 0.000000
25% 0.000000
50% 1.000000
75% 2.000000
max 43.000000
有了这个,可能盒子的情节对你来说更有意义。
另一种检测异常值的方法是使用 Z 分数。让我们看看它是如何工作的。
Z 得分和离群值:
Figure 3: 1σ and 3σ Standard deviation on a normal distribution with 0 μ. (Source: Author)
Z 得分是一个数字(无量纲的),表示一个数据点相对于平均值的标准偏差。 Z 得分可以简单地定义为—
Z =(X-μ)/σ,其中μ为总体均值,σ为标准差,X 为总体中的一个元素。
为了绘制下图,我使用了正态分布[numpy.random.normal(](https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.normal.html))
,在正态分布中,几乎所有的值(约 99.7%)都落在平均值的 3 σ偏差范围内(此处的图μ = 0)。我们可以使用 Z 得分来拒绝异常值的方法是考虑 Z 得分 3 个单位以内的数据点。可以使用下面的scipy.stats
为所有包含“非对象”类型数据的列完成此操作。
1.检查数据框**(data frame . dtypes)中所有列的数据类型。**
print "data types: \n", movies_df.dtypes>>>
data types:
color object
director_name object
num_critic_for_reviews float64
duration float64
director_facebook_likes float64
actor_3_facebook_likes float64
actor_2_name object
actor_1_facebook_likes float64
gross float64
genres object
actor_1_name object
movie_title object
num_voted_users int64
cast_total_facebook_likes int64
actor_3_name object
facenumber_in_poster float64
plot_keywords object
movie_imdb_link object
num_user_for_reviews float64
language object
country object
content_rating object
budget float64
title_year float64
actor_2_facebook_likes float64
imdb_score float64
aspect_ratio float64
movie_facebook_likes int64
2.创建一个新的数据框,排除所有“对象”类型列data frame . select _ dtypes
print "shape before :", movies_df.shapemovies_df_num = movies_df.select_dtypes(exclude=['object'])print "shape after excluding object columns: ", movies_df_num.shape>>>shape before : (3756, 28)
shape after excluding object columns: (3756, 16)
3.从每列中选择位于 Z 得分 3 个单位内的元素
movies_df_Zscore = movies_df_num[(np.abs(stats.zscore(movies_df_num))<3).all(axis=1)]print "shape after rejecting outliers: ", movies_df_Zscore.shape>>>shape after rejecting outliers: (3113, 16)
Figure 4: Box plot of number of faces featured in a movie poster. After applying the Z score method.
我们可以通过再次绘制“facenumber_in_poster”的方框图来检查上述步骤的效果。这里我们可以看到与图 2 相比的不同之处,在图 2 中,我们有一个考虑了“facenumber_in_poster”列中所有元素的方框图。
这些是人们可以准备用于分析的数据和应用机器学习算法进行预测的一些方法。有效地准备数据集对全面分析有很大帮助,我希望这篇文章能帮助你更有条理地准备数据集以供进一步分析。根据问题和数据集的不同,你可能需要决定、选择和重复这些过程来解释什么是影响,所以,祝你好运探索你的数据集。
保持坚强,干杯!!
这篇文章使用的代码可以在我的 Github 上找到。
在Linkedin找我。
数据快乐
测量抽象
联合国可持续发展解决方案网络为他们的年度世界幸福报告积累了大量关于世界情感状态的数据。但是,谁在乎我们的感受呢?有的人只在乎事实;不是感情。那些资本主义猪可能有兴趣听听这些由咨询机构 happy Places to Work 的首席执行官西尔维娅·加西亚吹捧的事实,该机构向通过更快乐的员工寻求更高利润和增长的企业提供文化审计服务。
Hapine$$ is Profitable
量化一种情绪
许多研究都在努力衡量幸福,但如何衡量呢?情感是不可估量的,主观的,抽象的。幸福可以通过一个人的幸福状态、生活满意度,甚至是他们大脑中特定神经递质的水平来感知——T4、血清素和多巴胺。我读过的几乎所有报告都采用了最常见的方法,即总结自我报告的幸福度调查。谁比你自己更了解你的幸福状态?在 2017 年,盖洛普在全国范围内进行了 160,498 次电话采访,他们声称他们的数据反映了 95%的美国成年人口。
根据盖洛普的 2017 年美国福祉状况报告,幸福是可以衡量的(也是可以预测的?)具有 5 个属性:
目的:享受你的日常生活,并有动力去实现目标
社交:拥有支持和爱的关系
财务:管理预算以减轻压力
社区:感到安全、自豪,并喜欢你居住的地方
身体:健康、精力充沛
虽然这些措施可能是有效的,但从调查中收集的自我报告的信息可以预见是不可靠的。问题和答案都是主观的。Michael Argyle 等人(1999)解释说,从调查中获得的数据无法解释超过 15%的生活满意度变化。这意味着我们无法用调查数据预测个人的健康状况。更客观的衡量标准,如整个人口的健康状况,显示了预测未来福祉的能力。根据克拉克等人(2018 年)的说法,心理健康“比身体健康更能解释福祉的变化”,这一发现得到了《世界幸福报告》的证实。
尽管为了衡量幸福而对自我报告的调查提出了批评,Ortiz-Espina 和 Roser 的认为,“基于调查的幸福和生活满意度的测量确实提供了一个合理一致和可靠的主观幸福感的画面。”看看那篇文章。有一些豪华的可视化,和全球范围的数据。
Kahneman 和 Krueger (2006)的下表列出了研究人员发现的与自我报告的幸福和生活满意度有关的其他变量。
国家调查结果
我住在布鲁克林,所以这是从纽约的角度来看。查看完整的 报告 找到你所在州的排名。
盖洛普的结果将纽约市置于第二分位数的底部,总体排名第 75 位(满分 186 分)。纽约市的优势在于身体素质,在社会和社区方面做得相当好,但在财务和目标方面有困难。
More butta, more betta.
25 个最幸福社区中,有 17 个在五个州:加利福尼亚、科罗拉多、佛罗里达、北卡罗来纳和弗吉尼亚。
惊讶吗?
幸福感得分最低的社区是:史密斯堡、阿肯色州-俄克拉荷马州;俄亥俄州坎顿-马西隆;北卡罗莱纳州的山核桃树-雷诺尔-摩根顿;密西西比州格尔夫波特-比洛克西-帕斯卡古拉;密歇根州的弗林特。
并不奇怪。
你住在哪里不会导致你快乐或不快乐,但有一些不可否认的相关性。生活在人口高度密集的地区会让你在身体和财务方面的幸福感得分更高,但农村居民通常比城市居民的社区得分更高。
在盖洛普幸福评估的所有衡量指标中,佛罗里达州那不勒斯-伊莫卡利-马可岛排名前 2。该镇已团结起来,在学校和企业中推广更健康的饮食习惯,举办大型锻炼活动,城市健康计划已使医疗费用远低于全国报告的医疗通货膨胀率。他们发现了预防肥胖、阻止吸烟、减少孤独感、解决精神疾病和早期戒毒等先发制人的方法,这些方法比任何反应性治疗都更有效。
下图显示了墨西哥一段时间内的平均生活满意度。生活满意度的飙升可以归因于全国性的事件,如 2015 年与免费长途电话重合的幸福感急剧增加,以及 2017 年汽油价格飙升时生活满意度的下降。
用数据科学预测幸福
数据科学正在创新新的更客观的方法来衡量人类的情感和健康。新技术已经开发出通过测量与表情、步态和声音相关的面部特征来远距离检测身份和情绪状态的方法。一个名为 FaceReader 的新商业软件使用一种在超过 10,000 张脸上训练的人工神经网络算法来预测愤怒或快乐等情绪,准确率很高(这两种情绪的准确率超过 90%)。
情感分析也可以用来从书面文本中预测幸福感和情绪。对一篇文章中表达的观点进行计算机识别和分类,尤其是为了确定作者对特定主题或产品的态度是积极的、消极的还是中立的。情绪分析已被用于股票市场价格的预测建模,但也有可能被用于预测福祉。
我们的工作场所文化、我们居住的地方以及时事都对我们的整体幸福感有影响。但是许多人认为他们的快乐来自内心的控制。他们相信他们对自己的幸福负责。大卫·斯坦德尔·拉斯特在他的 TED 演讲中说,感恩是幸福的关键。“如果我们心存感激,我们就不会害怕。如果我们不恐惧,我们就不暴力。”他强调正念和总是活在当下是幸福的秘诀。丹尼尔·吉尔伯特说,“我们内心有我们一直在追逐的商品。”在他的演讲中,他比较了合成幸福和自然幸福,并揭示了两者之间没有太大的区别。他认为幸福可以自我制造。听听他的 TED 演讲,了解一些关于幸福和生活满意度的有趣事实。
不管你目前在世界幸福报告上的排名如何,我希望有一天你能发现自己带着微笑醒来,并让自己无条件地快乐。
Wednesday emerging from the Harmony Hut
m .阿盖尔、d .卡内曼、e .迪纳和 n .施瓦茨(1999 年)。快乐心理学的基础。拉塞尔·塞奇基金会。
克拉克、A. E .、弗雷什、莱亚德、r .和沃德(2018 年)。幸福的起源:生命过程中的幸福科学。普林斯顿大学出版社。
卡尼曼博士和克鲁格博士(2006 年)。主观幸福感测量的发展。《经济展望杂志》,第 20 卷第 1 期,第 3-24 页。
数据英雄:你对你的数据提出了正确的问题吗?
为什么问题比答案更重要
企业花费大量时间试图从数据中获得正确的答案。数字化转型和大规模数据收集的能力向他们承诺了可操作的见解,这将使他们更有利可图,更具竞争力,并且在流行词汇的土地上,有更多的未来证明。
如果你不知道问什么问题,你必须回到你正在解决的业务问题。您目前如何解决这个问题,是否需要任何数据?如果是,那么您需要确定数据驱动的方法是否可以增强您现有的解决方案。这可以通过机器学习模型来实现,但它们的价值取决于你对数据提出的问题。
问题比答案更重要,原因如下:
- 除非你理解或知道问题,否则答案是没有意义的。
- 只有当你想到问题时,你才能找到答案,因此,答案的价值与你的问题质量息息相关。
- 一个问题往往会引出更多的问题,如果你没有问第一个问题,你甚至不会想到这些问题。
出于这些原因,Mind Foundry 设计了其软件来帮助您解决问题,并帮助您从数据中找到更有意义的答案。然而,有时可能很难找到最初的问题,这就是为什么我们分享一些出发点。
为什么提问很难?这通常是因为我们不知道机器学习可以解决什么问题,或者可以实现什么。机器学习算法识别输入特征和目标变量之间的数据关系。在这个过程中,他们回答这个问题:我的数据中有关系吗?有结构吗?作为一个领域专家,你可能已经意识到或者有一些关系的直觉,但是你可能无法证明或者量化它们。机器学习可以有所帮助。
你也可以试着理解你为什么要收集这些数据。为什么对你有价值?你在找什么信息?机器学习将帮助你找到数据中丢失的信息。
回到你已经问过和回答过的问题,即使你没有使用数据,问问你自己是否真的没有可用的数据?或者你能找到一些数据来丰富你的答案吗?问你的同行他们在问什么问题,他们在用哪些数据?
想了解更多信息吗?你可以在这里找到的提问指南。
更新:我开了一家科技公司。你可以在这里找到更多
提高模型性能的数据插补
最终是小步骤产生巨大的影响
在执行任何机器学习项目时,数据插补是数据准备阶段的重要部分。用纯粹的统计学术语来说,它是一个用一些有意义的替代物代替缺失数据的过程。
例如,请看下面的样本数据,它是从 Kaggle 中选取的自动数据集的子集。
Source: https://www.kaggle.com/uciml/autompg-dataset
有 6 行缺少马力特性的数据。所以作为数据准备阶段的一部分,我们需要去掉缺失的数据。
有两种方法可以消除丢失的数据:
- 我们可以从实际数据集中删除所有 6 行。
- 为丢失的数据添加一些有意义的替代数据。
随便猜!!!哪种方法可以提高模型的准确性?保持你的好奇心,让我们来探索答案。
是时候让我们的手接触代码,并找出哪一个在模型准确性方面更好。
加载数据集:
auto_data = pd.read_csv('/kaggle/input/auto-mpg.data', delim_whitespace = True, header = None,
names = [
'mpg',
'cylinders',
'displacement',
'horsepower',
'weight',
'aceeleration',
'model',
'origin',
'car_name'
])
下面是数据集的样子:
auto_data.head()
Out[4]:
我们可以检查每一列的数据类型:
auto_data.info()
如您所见,马力列有数值,但数据类型为对象。所以稍微偏离一下主题,我们需要改变列的数据类型。
auto_data['horsepower'] = pd.to_numeric(auto_data['horsepower'], errors='coerce')auto_data.info()
此外,car_name 特性并没有增加多少价值,因为在 398 行数据集中有 305 个唯一值。因此,为了简单起见,我们将从数据集中删除特征 car_name。
auto_data = auto_data.drop(['car_name'], axis=1)
auto_data.head()
现在,我们都可以尝试这两种方法来处理缺失数据。
首先,我们将删除马力特性缺少值的行,并评估模型性能指标。
auto_data_final = auto_data.dropna(axis=0)
auto_data_final[auto_data_final.isnull().any(axis=1)]
执行上述步骤后,我们已经成功地从数据集中删除了所有丢失的值。
下一步是将数据集分成训练/测试集,并进行模型训练。
from sklearn.model_selection import train_test_split
from sklearn.svm import SVRX = auto_data_final.drop('mpg', axis=1)
y = auto_data_final['mpg']X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state =0)model = SVR(kernel='linear', C=1.0)
model.fit(X_train, y_train)
这是捕捉模型训练的一些重要性能指标的好时机。
获得预测的均方误差(MSE)。
model.coef_
获得对测试数据的预测:
y_predict = model.predict(X_test)
计算均方误差:
from sklearn.metrics import mean_squared_errormodel_mse = mean_squared_error(y_predict, y_test)
print(model_mse)
将数字记在某处,我们将对处理缺失数据的第二种方法(即数据插补)重复相同的步骤。
为清晰起见,让我们总结一下第一种方法中包含的所有步骤:
a.已加载数据集。
b.已将马力特征转换为数字。
c.已删除汽车名称功能。
d.删除所有丢失数据的行。
e.将数据集分成训练/测试集。
f.使用训练集训练模型。
g.评估训练集和测试集上模型性能度量。
对于方法 2(数据插补),除步骤(d)外,我们需要重复上述所有步骤。步骤(d)将由几个子步骤代替。
假设前 3 个步骤很容易重做,那么我们可以直接从步骤(d)替换开始。
数据插补有多种方式,下面是其中一种。我们需要考虑到解释的方式并不完美,只是试图传达数据插补的重要性。
正如我们所知,完整数据集中只有 6 行缺少马力特性的数据。
Source: https://www.kaggle.com/uciml/autompg-dataset
我们可以寻找相关矩阵,并检查是否可以从现有特征中导出马力值。
# Check the correlation matrix to derive horsepower feature by help of other feature
corr = auto_data.corr()
corr.style.background_gradient(cmap='coolwarm').set_precision(4)
相关矩阵表明,马力特征与气缸、排量和重量等特征有很强的相关性。
为简单起见,我们将考虑气缸特性来推导马力特性下的所有缺失值。
丢失的数据行有 4 列或 6 列。因此,计划将实际数据集中所有行分别分组为 4/6 缸,然后得出马力特性任何缺失值。
auto_data_4_cylinders = auto_data[auto_data['cylinders'] ==4]
print(len(auto_data_4_cylinders))
auto_data_4_cylinders.head()
绘制直方图以了解功能马力的数据分布:
%matplotlib inlineauto_data_4_cylinders['horsepower'].plot.hist(bins=10, alpha=0.5)
由于直方图似乎是正态分布,我们可以选择平均值作为我们的插补策略。
import numpy as np
from sklearn.impute import SimpleImputerimp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')auto_data_4_cylinders['horsepower'] = imp_mean.fit_transform(auto_data_4_cylinders[['horsepower']])
检查是否已移除所有 NaN:
auto_data_4_cylinders[auto_data_4_cylinders.isnull().any(axis=1)].head()
对 6 缸自动数据下的缺失数据重复相同的技术。
auto_data_6_cylinders = auto_data[auto_data['cylinders']==6]
auto_data_6_cylinders.head()
绘制直方图以了解功能马力的数据分布:
%matplotlib inline
auto_data_6_cylinders['horsepower'].plot.hist(bins=10, alpha=0.5)
似乎如果我们从我们的数据集中排除 160,那么其余直方图将看起来像正态分布,我们可以选择平均值作为插补策略。
打印插补的目标行:
auto_data_6_cylinders[auto_data_6_cylinders.isnull().any(axis=1)].head()
现在将插补策略应用于目标行:
import numpy as np
from sklearn.impute import SimpleImputermean_imp = SimpleImputer(missing_values=np.nan, strategy='mean')mean_imp.fit(auto_data_6_cylinders[auto_data_6_cylinders['horsepower'] < 160][['horsepower']])auto_data_6_cylinders['horsepower'] = mean_imp.transform(auto_data_6_cylinders[['horsepower']])
检查是否已移除所有 NaN:
auto_data_6_cylinders[auto_data_6_cylinders.isnull().any(axis=1)]
由于我们删除了所有 NaN,所以现在是时候将所有数据集合并在一起了。
auto_data_others = auto_data[~auto_data['cylinders'].isin((4,6))]
print(len(auto_data_others))auto_data_final = pd.concat([auto_data_others, auto_data_4_cylinders, auto_data_6_cylinders], axis=0)
print(len(auto_data_final))
下一步是将数据集分成训练/测试集,并进行模型训练。
from sklearn.model_selection import train_test_splitX = auto_data_final.drop('mpg', axis=1)
y = auto_data_final['mpg']X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state =0)from sklearn.svm import SVRmodel = SVR(kernel='linear', C=1.0)
model.fit(X_train, y_train)
现在,我们将使用插补策略准备的数据来捕获模型再训练的一些重要性能指标。
model.coef_
获得预测的均方误差(MSE)。
y_predict = model.predict(X_test)from sklearn.metrics import mean_squared_errormodel_mse = mean_squared_error(y_predict, y_test)
print(model_mse)
如我们所见,我们能够通过简单的数据插补技术最小化均方误差(MSE ),这是评估训练模型时的性能指标之一。
所以回到方法的问题,我们可以说数据插补方法在给定的数据集上效果更好。
你可以参考下面 kaggle 上的笔记本以获得完整的代码示例:
使用来自[私有数据集]的数据
www.kaggle.com](https://www.kaggle.com/shshankar1/svm-for-linear-regression-predict-automobile-mpg)
仓库中的数据或 Hadoop 中的数据:什么适合您的业务,为什么?
大数据是 IT 行业最受欢迎的创新,它席卷了整个世界。部分原因是由于 Hadoop 和相关的大数据技术正以指数速度增长。Hadoop 在大数据领域发展的一个主要原因是它能够为程序员提供并行处理的能力。但是最近像“Hadoop 会取代数据仓库吗?”或者“MapReduce 之死”已经在网络上浮出水面,从而为大数据程序员带来了不同轮的辩论。随着我们在 2019 年年中向前迈进,围绕 Hadoop 的宣传似乎仍在增加,许多期望和兴奋以物联网的形式出现。
为了消除那些支持 Hadoop 的人的任何困惑,我们将在这里调查一些事实,并回答一些在互联网上被问到的最受欢迎的问题,如:
- Hadoop 会取代数据仓库吗?
- 如果有了大数据,还需要仓库吗?
- 传统仓库时代现在死了吗?
但是,在我们深入研究上下文之前,让我们澄清对云的任何疑问,并正确了解这些术语。
什么是数据仓库?
数据仓库是一种数据存储或数据仓库的体系结构,它使用了不同于标准操作数据库的设计。与操作数据库不同,数据仓库旨在提供长期的数据。因此,数据聚合被触发,交易量成为一种权衡。
数据仓库是用来做什么的?
大多数企业利用数据仓库来分析他们的业务数据。当他们的分析需求与操作数据库性能发生冲突时,通常需要他们。大多数操作数据库不能运行复杂的查询,因为它需要数据库进入一个临时的固定状态。这就是数据仓库发挥作用的地方。数据仓库可以完成大部分分析工作,这使得事务数据库有足够的时间关注事务。
数据仓库的另一个最佳好处是它能够分析来自多个来源的数据。它能够通过利用 ETL(提取、传输和加载)过程来协商存储模式中的差异。ETL 被定义为从不同的 RDBMS 源系统中提取数据,然后转换数据(如应用计算、连接等)的过程。)并最终将数据加载到数据仓库系统中。
Hadoop 是什么?
Hadoop 拥有与 MPP 数据仓库相似的架构,但有一些明显的不同。与定义并行架构的数据仓库不同,hadoop 的架构由跨 Hadoop 集群松散耦合的处理器组成。每个集群可以处理不同的数据源。数据目录、数据操作引擎和存储引擎等组件可以独立工作,以 Hadoop 作为收集点。
Hadoop 服务于什么目的?
Hadoop 已经成为大数据技术的宠儿,因为它拥有处理大量半结构化和非结构化数据的能力。以下是 Hadoop 的一些使用案例示例:
- 大规模企业— Hadoop 可用于需要服务器集群的大规模企业项目,在这些项目中,编程技能和专业数据管理技能有限,实施成本高昂。
- 大型数据集— Hadoop 可用于建立高可扩展性并节省管理 Pb 或 TB 级数据集的资金和时间。
- 单独的数据源— 需要来自单独数据源的数据的大数据应用,往往要处理 Hadoop 集群;所以 Hadoop 在应用开发中起着非常重要的作用。
传统仓储的问题
传统的数据仓库无法控制复杂的层次数据类型和其他非结构化数据类型。随着可扩展性的需要,成本因素成为数据仓库无法解决的问题。
此外,DWH 不能保存缺少明确模式的数据,因为它遵循模式写入机制。这就是 Hadoop 发挥作用的地方,因为它更喜欢读模式。数据仓库通常需要花费大量时间对数据建模,考虑到业务模型,这是不可行的。
Hadoop 会取代数据仓库吗?
毫无疑问,Hadoop 生态系统一直在快速高效地进化。如果 Hadoop 很快能够处理所有类型的任务关键型工作负载,从而消除对数据仓库的需求,我们不会感到惊讶。然而,Hadoop 和数据仓库都将在业务中存在更长一段时间。组织可以依靠其现有的数据仓库,并引入 Hadoop 功能来满足业务需求并利用应用程序开发的力量。
基于数据的滚动预测
在初创企业中利用数据科学工具与财务部门合作,并推动以产品为导向的增长。
Credit: Periscope Data. BI dashboard with dynamic filters.
注:这篇文章最初发表在我的博客上,是我在 FloSports 担任产品副总裁时写的。目标是展示正确的数据科学工具和对基本业务驱动因素的理解如何支持产品和财务之间的协作,以加速产品导向的增长。在最初出版时,我们是一家 B 系列运动技术公司,在其生命周期的各个阶段拥有近 25 种不同的运动。
我在 FloSports 倡导的一项新举措是我所谓的“数据通知滚动预测”。在这篇文章中,我将从宏观层面介绍这是如何实现的,以及潜望镜数据如何在帮助我们实现调步仪表板方面发挥宝贵的作用——只需要有限的工程时间。
以下是我完成这项工作所必需的材料清单:
- 了解您的业务和经济模式的关键驱动因素
- 一个可查询的数据库(我们的报告仓库位于 Redshift 上)来进行历史基准测试
- 促进数据库查询和提取的商业智能工具
- 自下而上的财务模型模板,理想情况下基于场景和案例(例如,仅从现有业务相对于现有业务的增长加上完成业务的高概率),该模板基于#2 的历史实际情况,并预测下一季度的预期结果
- 商业智能工具,有助于创建进度控制面板
第 1 部分:了解关键驱动因素和基准测试
当我刚到 FloSports 的时候,我的第一个行动项目之一是了解我们现有的 KPIs 这包括从理解什么,为什么,以及如何跟踪度量的一切。我们从头构建了一个数据仓库,我们将 ETL 到新红移仓库中的初始数据源是我们的 Stripe 支付数据。为此,我们采访了一位数据科学顾问。鉴于他参与帮助我们准备 B 轮融资,他对我们的业务很熟悉。作为该流程的一部分,在不涉及太多细节的情况下,我们制定了所有现有订阅计划的内容,以及我们的订阅者展示的计划和运动。在此基础上,我们定义了我们的用户类型和计划间隔。例如,我们根据支付的类型,结合用户在我们公司的生命周期中所处的阶段,制定了不同的用户类型。例如:
- ***新功能:*用户首次为某项运动的订阅付费
- ***重新激活:*在先前取消之前已经是订户的订户返回并为特定运动的订阅付费
- ***循环:*用户为他/她的特定体育项目订阅支付循环费用
聚合事实表。鉴于我们的运动和计划产品的范围,查询可能会变得相当复杂,特别是对于有多年历史和来自新老用户的大量活动的运动。鉴于此,我们最常见的报告用例通常被转换成聚合事实表。这些通常结合了两个、三个或更多不同的数据源。我们为关键性能指标构建了聚合事实表,包括订阅者瀑布(月粒度)和支付(日粒度)。利用这些数据丰富的事实表和 Periscope Data 等灵活的 BI 工具,我们能够创建一个可按运动项目过滤的历史基准仪表板。我们将此提供给相关的业务涉众,他们可以基于选择的过滤器请求数据,并下载 CSV 以加载到财务模型中。
第 2 部分:构建自下而上的财务模型模板
鉴于我们有 25 个运动项目的现实,我为每个运动项目建立自下而上的财务预测模型的主要目标之一是使模型具有动态性和灵活性。这有助于有限的,如果有的话,为每个运动重新布线的模型,因为模型灵活的不同的发射日期和历史表现,例如,子保留,为每个运动。
一些运动已经存在好几年了,而另一些只有几个月的历史数据。我没有按照一项运动的历史来构建每一个模型,也没有每个季度都需要重新构建每一个模型,而是花了大量的前期时间来弄清楚如何最好地调整模型。我们通过所有 15+工作表动态反馈的示例包括:
- 订户群组保留瀑布
- 所有历史队列的加权平均保留曲线,根据衰减率预测未来流失
- 历史计划选择组合,例如,每月/每年%
- 随着时间的推移,订阅者螺旋上升—开始加上新的较少搅动等于结束(每月谷物);(也有助于 MRR 的计划提供和运动)
- 基于历史分组及其预计经常性付款的季度每周预测;我们将这些预测的经常性付款与预测的新的和重新激活的用户付款相结合
模型的灵活性通常是通过确定哪些输入驱动因素需要动态公式来实现的;在本例中,输入如垂直发布月、上个月的实际值和季度开始日期允许我将模型与每项运动的独特方面区分开来。这也让我可以根据每项运动的历史来定制模型,只需最少的手动重新布线。
Example Control Sheet with Dynamic Drivers by Business Unit (sport in our case).
对于那些熟悉金融建模的人来说,你知道你可以利用场景和案例来对各种潜在的结果敏感化。一个例子是,“如果我们在季度的第二个月完成一笔大的配股交易会怎么样”,而我们所有的关键输入,例如每月价格,保持不变。为了说明这种可能性,我们将使用 Excel 中的 offset 函数创建一个场景,允许我们选择是否希望这种潜在结果的影响改变某些输入,然后流过模型。除此之外,我们可以将“大型新活动”场景与“牛市”案例结合起来→“如果我们结束了大型活动,并且由于这项运动的现场活动时间表更加强劲,该季度的年度混合百分比比我们以往看到的高 500 个基点,会怎么样?”
虽然每项运动都有一个单独的模型,但我在每个模型中添加了一个工作表,该工作表以行(周)和列(指标)的形式汇总了各种工作表中的所有关键报告指标,然后可以作为一个可查询的平面表→将所有这些模型的表合并到一个 CSV 中,作为我们调整仪表板的数据源。通过这样做,我们实现了以下目标:
- 反映季度目标的可视化效果(可下载数据);业务用户更容易看到全面的目标和每个目标的驱动因素
- 一个进度控制面板,提供关于运动进度与预测进度的洞察,包括净收入、注册、订户和流失。
第 3 部分:利用正确的 BI 工具,即潜望镜数据 FTW
我以前写过关于潜望镜的数据缓存的文章,事实证明它在这种情况下非常有用。我们在几个方面使用了 Periscope 的数据缓存。例如,我们实现了跨数据库连接——一个数据源在 MySQL 中,另一个在 Postgres 中,第三个来自平面 CSV 文件。通过组合这些不同的来源,我们创建了一个强大的、不需要数据工程的仪表板。这个仪表板满足了我们的一个 sports 的用户属性报告请求,所需时间大约是整合我们专有的 ETL 工作流所需时间的 1/20。
Periscope 的缓存也有助于我们快速构建新数据源的概念证明(POC ),并接收来自业务利益相关者的反馈;我们总是在请求数据工程将新的数据源添加到我们的 ETL 工作流之前构建这些。此外,对于不太熟悉请求他们的当前状态数据流程成为我们的 ETL 和 BI 报告流程的一部分的业务用户,Periscope 的缓存为我们提供了一种低开销的方式来证明他们的报告想法。在对概念验证进行迭代,然后确保需求准备就绪之后,这提高了工程人员理解如何对数据建模以及如何将新的源合并到我们的整个仓库工作流和模式中的效率。
我们使用 Periscope 构建的季度仪表板是一个高度可定制的业务用户报告工具,可以显示每日、每周、每月和每季度的进度可视化和表格。这为版权收购团队、营销人员、管理层和数据分析师团队提供了关于我们在哪些方面超出或落后于季度绩效目标的可见性,此外,我们使用仪表板的报告来触发需要额外调查的领域。一些例子包括:
- 一个事件超出其注册预测 1.5 倍;我们是否通过现场活动漏斗看到了更好的转化?在影响访问者转化为付费用户方面,哪些内容看起来效果不错?
- 我们看到了比预期更高的保留率;这项运动做得好的地方是什么,它是否可以转移到其他运动中,我们如何做得更多?
Q2 2017 仪表板注册步调的净化图:
Example of Pacing Dashboard tracking overall signups relative to forecast and trend by week intra-quarter.
我喜欢这种工作,因为它结合了我的金融建模背景和数据分析。同样令人欣慰的是,在定义和验证业务逻辑以及获得正确的数据策略方面所做的努力确实可以支持产品导向的增长。Periscope Data 的工作人员是一路走来的好伙伴,最终是这种高度迭代、低开销方法成为可能的原因!
如果你喜欢这篇文章,如果你能点击“拍手”图标让我知道并帮助增加我的作品的发行量,那将是非常棒的。
你也可以在推特上联系我, @kevinboller ,我的个人博客可以在这里找到。感谢阅读!
数据不是新的石油
从类比到迷因再到教条的转变是持久的,也是有缺陷的。
Photo by Brandon Glass on Unsplash
走进任何与数据有关的会议,你可能会听到这样的话:“知识是最大的商品”,“最有价值的资源是数据”,“数据是新的石油。”
数据是新油。我们都听说过。可能会不假思索地点点头。但是是吗?数据是新的石油吗?这个比喻站得住脚吗,还是仅仅是人们说的一句话?就我个人而言,我认为这不是一个好的类比——这两者是截然不同的,而且最终是截然不同的。
其起源的类比可能意味着指出石油对其时代具有革命性的影响,同时代的数据也是如此。但是人们越来越自由地引用这个类比。即使是从未开采过自然资源的公司也可以毫无歉意地宣称他们的“数据是新的石油”。
道格拉斯·霍夫施塔特,著名的哲学家和《T4》一书的作者,称这个类比是一个天真的类比。这些是“非专业人员倾向于将其科学概念的概念建立在其上的那种类比”。[……]获得的[概念]得益于吸引人的、有益的、但往往过于简单的类比。”*
霍夫施塔特继续指出,它们可能很容易记住,但它们的弱点源于这样一个事实,即在特定的背景下,它们具有误导性。“天真的类比就像滑雪者优雅地滑下整洁的斜坡,但却完全迷失在粉末中。总之,天真的类比在许多情况下都很有效,但在其他情况下,它们可能会导致荒谬的结论或彻底的死胡同。”**这就是我们目前所目睹的:类比将我们引入歧途。这让我们相信,像“数据分析师”和“数据科学家”这样的职位只是数据的精炼厂,因为这也是我们处理石油的方式。这不是真的。一点也不。
数据无油
这种类比最明显的缺陷是,收集数字行为数据(几乎)是零成本的。对于油基产品,如汽油,57%以上的成本发生在提取原油的过程中。你在加油站支付的费用中,大约有 60%是在从地球表面提取石油时发生的。从来没有人投入这么多的整个项目预算来获取一些数据。
运输和分销也对石油的最终价格构成了巨大的成本。另一方面,数据可以自由传输,基本上可以免费无限期存储。
数据等同于石油等天然资源的想法导致我们大量投资于数据湖(理解为沼泽)并盲目收集信息。因为人们认为,如果我们有原始资源,创造最终产品是很容易的。这个类比让我们相信,在某种意义上,数据有内在的价值。
数据收集、获取和存储已经变得普遍和丰富;事实证明,创造价值要困难得多。事实证明,数据没有内在价值。当数据被应用于解决一个特定的问题时,价值就被创造出来了——这也是成本产生的地方——当一个原始资源变成有用的最终产品时。
值提取
问任何一个数据专家,他们都会同意 60%以上的工作都是与数据争论。从不同的来源获取正确的数据、清理、重组、工程特性等。行为本身除了为其所支持的任务增加价值之外,并没有增加额外的价值。
每个算法、每个模型和每个分析都需要精心准备和清理的数据。即使在考虑最小可行产品时,所有者也不得不在提取任何价值之前预先承担大量“成本”。被清除和未被使用的数据通常没有什么价值(同样,与石油不同,石油是一种副产品,可以用来制造柏油路面或塑料)。
因此,值提取是错误的术语;来自数据的价值需要被创造。
边际成本和 r 资源枯竭
数据的收集、存储和传输的边际成本为零。一个单位的增加不会带来很大的成本。分析的所有成本基本上都是前期的。这同样适用于生产就绪的数据产品:每一个额外的产品或客户评分都不是一项成本。
与越来越稀缺的典型资源不同,数据变得越来越丰富。稀缺资源的内在价值会增加。他们的需求超过了供给。在过去的几十年里,随着天然气和石油相关产品价格的不断上涨,我们已经见证了这一点。
数据不真实;数据过于丰富,并且不断增加。成本不在于找到或存储它的内容。事实上,成本在于提炼数据和从“原始资源”中创造价值。
另一个差异是数据需要验证和核实;每个管道都需要反复研究同样的问题。石油则不然,我们完善炼油厂和分销管道,使系统发挥最佳功能。
结论
“数据是新的石油”这个迷因的延续让我们无意识地得出更多关于相似性的推论,而不是严格意义上的。
坚持和传播相似性这一天真概念的问题在于,它与“数据科学”和“分析”是数据之上的简单功能(类似于从原油中制造汽油)这一普遍概念有关。然而,真正花费成本和时间的是产品的创造。不在于开采原始资源,而在于创造有意义的最终产品。
石油总是有用的。
数据不会。
*表面和本质:类比作为思维的燃料和火焰,道格拉斯·霍夫施塔特,第 31 页
**同上,第 389 页
数据不是新的石油
关于处理数据的现实
如果您在数据科学或相关领域工作,您可能以前听过这句话:
“数据是新的石油。”
这句话可以追溯到 2006 年,被数学家 Clive Humby归功于,但最近在《经济学人》发表了题为“世界上最有价值的资源不再是石油,而是数据”的 2017 年报告后,它得到了更多的关注。
Photo credit: Zbynek Burival, Unsplash
这听起来很令人兴奋。但真的是这样吗?
鉴于科技公司在数据驱动下取得的成功,将数据等同于石油乍一看可能有道理,但一旦你深入挖掘(这是一句双关语),这种类比就站不住脚了。
石油的问题是,一旦石油公司在地下找到它,他们或多或少知道要把石油转化为利润必须遵循哪些步骤:钻探、提炼、提炼、销售。这与你处理数据时面临的现实相去甚远:在处理数据时,如何将数据转化为利润还远未明朗。
处理数据
如果您在经营一家企业,并且想要对您的数据做任何事情,您需要做的第一件事就是创建存储和查询该数据所需的基础架构。数据不存在于电子表格中。
让我们假设你运行一个旅游预订网站。每当有人搜索、预订旅行、点击广告或以任何其他方式与网站上的内容互动时,就会产生数据。为了捕获所有这些数据,你需要雇用数据工程师,并建立类似于 Hadoop 集群 的东西,允许弹性数据存储和快速查询。这是你需要预先做的一笔大投资。
理解数据
让我们假设这些都是你做的。数据库会告诉你哪个用户什么时候点击了什么,他们预订了什么航班,他们预订了什么酒店,他们要去哪里旅行,以及他们什么时候去。也许您甚至有包含人口统计信息的用户配置文件:用户住在哪里,他们的年龄,等等。极其丰富的数据集。
但是你如何处理这些数据呢?
嗯,你需要雇用数据科学家来找出将数据转化为商业见解的方法,这反过来可能会产生利润。这样,你就有机会获得投资回报。
进入数据科学
数据非常嘈杂。数据科学家接受培训,通过从以下角度观察数据来理解有噪声的数据:
什么 假设 关于数据产生的过程我能做什么?我怎样才能 检验 那个假设对数据的影响?从我的假设检验中我能推断出什么样的 洞见 ?
注意工作流程是如何从一个关于业务流程的想法开始的,然后才是数据——这是因为数据噪音太大,无法提供内在价值。数据科学家的工作流程很少从数据本身开始。
Photo credit: Abigail Lynn, Unsplash
一个例子
下面是一个数据科学家可能会对上述旅游预订网站数据做些什么的例子。我的假设是,如果用户对自己的旅游偏好有所个性化,他们更有可能点击第三方广告。例如,我可以向之前预订了夏威夷之旅的千禧一代展示冲浪学校的广告。我如何检验我的假设?
首先,我需要在规模上实现这样一个个性化广告系统*,这将需要大量的工程工作。第二,一旦我有了这样一个系统并开始运行,我将需要进行类似于 A/B 测试 的测试,以确定新系统是否真的提高了广告点击率。只有在 A/B 测试成功的情况下,我才展示了利用数据为企业创造利润的方法。*
旅游预订网站还能通过其他方式从用户数据中获利吗?大概有几十种方法,但是你需要投入时间、研究、人力资源(数据科学家、数据工程师、软件工程师)、技术资源去找到它们。这一过程包含许多未知因素、研究和实验,因此从根本上不同于提炼、精炼和出售石油的过程,后者的步骤要清晰得多。
Photo credit: NASA, Unsplash
数据和恐怖
最后,当您构建任何利用您的数据资产的系统时,比如个性化系统,您必须非常小心,不要太令人毛骨悚然。令人毛骨悚然包括任何形式的让人感觉太侵扰的个性化。令人毛骨悚然的目标选择(双关语)的一个众所周知的例子是 Target 的怀孕检测模型。
塔吉特提出了以下假设:孕妇更有可能购买某些物品,如产前维生素和孕妇装。塔吉特的想法是这样的:如果我们可以建立一种算法来找到这些客户,并向他们发送婴儿用品的优惠券,如尿布,他们更有可能在婴儿出生后让塔吉特成为他们的一站式杂货店。
正如《纽约时报》报道的那样,在塔吉特百货开始使用这种模式一年后,一名男子走进明尼阿波利斯郊外的塔吉特百货,愤怒地要求与经理谈话。他是这样说的:
“我女儿收到了这封信!她还在上高中,你就给她寄婴儿服装和婴儿床的优惠券?你是想鼓励她怀孕吗?”
结果,他的女儿怀孕了,塔吉特比他先知道。数据驱动的个性化出现了令人毛骨悚然的错误。
Netflix has learned the importance of personalization. (Photo credit: Charles, Unsplash)
总结:数据不是新的石油
处理数据的过程是混乱的,需要仔细的计划、工程和研究,并且包含许多未知和陷阱。最重要的是,人们并不总是清楚如何利用数据,因为数据本身太嘈杂,无法提供价值。把数据等同于石油,就是忽略了这个杂乱而复杂的现实。
话虽如此,我们今天看到的最强大的数据应用之一可以说是个性化,它推动了亚马逊、脸书、谷歌、网飞、Spotify 等科技公司的成功。这些公司已经了解到个性化产品比通用产品更成功。其他行业,如银行业或保险业,也在学习:我们生活在一个越来越多的数字产品变得个性化的世界。
最后,石油的现实是,它的供应和使用都是有限的。有数据的现实恰恰相反:只要有人类在身边,我们总会创造出更多的数据。
数据是新的石油,即使在石油和天然气行业也是如此
来自 2019 年 SPE 数据科学大会的见解
数据科学和机器学习一直是互联网、金融、营销等行业重大转变的背后力量。石油和天然气行业也不例外,在 21 世纪初就很快熟悉了这一概念,并将其应用于上游、中游和下游行业,以获取宝贵的见解。因此,对业内公司来说,精确的数据仍然是一笔宝贵的资产。克莱夫·亨比(Clive Humby)曾著名地将数据比作新的石油,指出其内在价值在精炼后闪闪发光。
“数据是新的石油。它很有价值,但如果不提炼,就不能真正使用。它必须转化为气体、塑料、化学物质等,以创造一个有价值的实体,推动盈利活动;因此,必须对数据进行分解和分析,使其具有价值。”
—克莱夫·亨比
在德克萨斯州休斯顿石油工程师协会(SPE)数据分析小组组织的 2019 年数据科学大会上,精炼数据和精炼油之间的比较有了新的意义。数据科学大会于 2019 年 4 月 4 日举行,425 名专业人士满座,抓住了人工智能传播带来的兴奋感,并在整个 O&G 行业组织了数据分析。
SPE 数据分析小组负责人 Suri Bhat 介绍了第二届年度 DSC 的主题:*“用先进的数据科学解决方案改造 G 行业的上游”,*并强调了将人工智能融入石油和天然气行业的重要性,因为每个石油生产商都要处理数 Pb 的数据。根据 2017 年世界经济论坛报告,从 2016 年到 2025 年,数字化转型将产生价值 1.7 万亿美元的价值,从而减少 120 万吨碳排放。
“数字化转型给该行业带来的估计价值约为 1.7 万亿美元,从而减少 120 万吨碳排放。”
售罄的会议有一个良好的技术和商业演示的组合,学生/行业海报会议,公司展台展示他们的服务,以及大量的网络机会。
断层和测井解释中的深度学习
每个演讲者都单独展示了人工智能目前被广泛应用的项目。与上游石油工业相关的作业与资源勘探和评估、油田开发、钻井和完井、油藏管理以及生产和设施作业有关。地球科学和勘探领域正在积极利用机器学习进行自动测井解释和勘探。
Typical Log Data (obtained from source)
一个特定的行业项目使用贝叶斯状态空间模型和蒙特卡罗模拟处理实时地层解释。另一个项目利用人工智能通过神经网络进行故障解释。无监督学习以前也曾用于测井解释。地震测井中缺失的三维数据为进一步解释模拟合成数据带来了独特的挑战。利用真实数据和合成数据,从而减少实现地学结论所需的时间。粒度预测也正在使用卷积神经网络进行分析,该网络具有来自微电阻率测井和多个其他输入的数据。
使用神经网络的实时扭矩和阻力计算
在钻井中,需要分析上下文数据(以每日钻井日志报告的形式)和结构化视觉数据(通过测井获得并在电子钻井记录仪中捕获)。由于钻井作业的时间限制性质,需要做出实时决策。为此,公司正在使用神经网络,并分析钻机状态以实现实时数据可视化,并预测钻井关键性能指标。现在,通过估计钻柱和井筒之间的摩擦系数和法向接触力,可以使用人工智能实时计算任意给定井中钻柱上的扭矩和阻力。
另一个运营商正在利用泵冲洗的历史数据,并在冲洗发生时向钻机运营商实施智能手机警报系统。井底钻具组合(BHA)承受各种应力,尤其是在水平井段,在给定操作参数(钻井角度、方向和深度目标、预期钻进速度)、地层特性(岩石的磨损性和能力、井内压力状态)和钻井参数(钻柱重量、应用的 RPM 范围、扭矩和预期的冲击模式)的情况下,拥有正确的钻具组合非常重要。人工智能目前正被用来实时选择正确的 BHA。
预测油井生产剖面的特征提取模型
油气生产优化分析涉及时间序列预测和递归神经网络。主要的 KPI 包括石油产量和气油比的预测。一个特殊项目使用特征提取模型,使用计算井底压力,节流器,井口温度和邻近油井数据来预测每日石油产量。裂缝参数也被用于产量递减曲线预测。另一个项目利用深度学习和神经网络对抽油杆示功图进行模式识别。油井中断引起的产量变化也可以使用中断时间序列建模(ITS) 进行建模。
Dynamometer Cards (obtained from Sage Technologies, Inc.)
解决双头怪物:使用人工智能和数据民主化证明合理的投资回报
在主要石油生产商正在解决的主要问题中,说服高层管理人员相信人工智能的长期好处被证明是最具挑战性的。这部分是因为 O&G 行业的扩张性经营规模减缓了新技术的采用。每个部门内部产生的数据量是惊人的,而这还只是上游行业!在平面文件、非结构化数据、空间和时间数据、可视化地震和测井数据、四维和五维数据方面,数据类型也有很大差异。数据科学技术的引入将通过基准和统计分析、人工智能、机器学习、优化、空间和时间分析提高其价值。然而,让每个人都参与进来是一个挑战。高层管理需要更可靠的概念验证研究来增加业务价值。一位高管评论说,由于行业现状,80%的数据科学和机器学习项目最终都没有实施。剩下的 20%确实提供了商业价值,其中 85%的时间和资源花在正确定义问题上,剩下的是纯粹的数据科学。
数据使用和分析方面的企业标准的管理和传播已经开始,会议使最佳做法得以分享。
尽管在扭转石油和天然气行业的巨大趋势方面存在这些挑战,但是已经采取了许多战略计划来简化和标准化数据科学流程。一家特定的运营公司已经开始通过规范性指导和技术监督来支持公民数据科学家,并在公司内部更加关注人工智能技能的发展。企业标准的管理和传播已经开始,会议使最佳做法得以分享。然而,合作和创新是关键,需要促进来自更大行业和外部的公开对话。AlphaX Decision Sciences 的首席执行官萨米·哈伦(Sammy Haroon)对人工智能技术和 T2 产业进行了比较。他强调开源是人工智能成功和采用速度的关键,并谈到这个领域更需要数据民主化。
机会是广阔的
除了演讲嘉宾和专题小组成员的丰富内容,上游行业很少有数据公司展示他们的服务。互动海报展示环节不仅吸引了来自美国各地的学生和行业专业人士,还吸引了来自巴基斯坦和挪威的学生和专业人士!强调了人工智能在行业中的一些突出应用:使用计算机视觉和神经网络的崩落检测分析,使用机器学习的渗透率预测,工作流描述和数据争论程序,以应用数据分析改进钻井作业,时间序列压裂数据用于预测完井事件,以及使用人工智能从勘探和生产文件中提取和构建数据,等等。
人工智能在石油和天然气领域的发展是不可避免的,为这些工作雇用合适的人对公司的成功至关重要。2019 年 SPE 数据科学大会为与会者提供了一个宝贵的机会,让他们能够成功地交流和了解这些行业关注的问题,并相应地制定解决方案。跨职能的数据科学家需要接受这样的培训,机会是巨大的。套用一位高管在大会上的话:“这个领域的数据是一笔宝贵的资产,数据科学家和机器学习专家将留在这里。”