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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用开源 Prophet 包在 R

原文:https://towardsdatascience.com/using-open-source-prophet-package-to-make-future-predictions-in-r-ece585b73687?source=collection_archive---------2-----------------------

几乎每个公司都希望回答一周/一月/一年后他们会在哪里。在规划公司的基础设施、KPI(关键绩效指标)和员工目标时,这些问题的答案可能很有价值。
因此,使用数据预测工具是数据专业人员需要承担的常见任务之一。

最近作为开源发布的一个工具是脸书的时间序列预测包 Prophet 。R 和 Python 都可以使用,这是一个相对容易实现的模型,带有一些非常需要的定制选项。
在这篇文章中,我将回顾 Prophet,并接着介绍一个简单的 R 代码示例。这个代码流的灵感很大程度上来自于官方软件包用户指南

我们将使用从 wikishark 提取的开放数据集,保存勒布朗·詹姆斯维基百科文章页面的每日数据入口。接下来,我们将基于历史数据构建每日预测。

  • wikishark 在文章发布后被关闭。你可以使用另一个有用的网站获取数据

阶段 1 —安装和导入 prophet

**install.packages(‘prophet’)
library(prophet)
library(dplyr)**

阶段 2 —加载数据集

**stats <- read.csv(“lebron.csv”, header=FALSE, sep=”,”)
colnames(stats) <- c(“ds”, “y”)
head(stats)
#daily data points starting from 2014–01–0**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**stats$y <- log10(stats$y)**

对于我们的代码示例,我们将转换数据并使用入口日志。这将有助于我们理解预测可视化。

第 3 阶段—探索数据

**View(summary(stats))
plot(y ~ ds, stats, type = "l")**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到这些数据是从 2014 年 1 月 1 日到 2016 年 12 月 31 日,从 4 月到 6 月有一些年度季节性高峰。

第 4 阶段—基本预测

**m <- prophet(stats)
future <- make_future_dataframe(m, periods = 365)
forecast <- predict(m, future)**

像机器学习模型一样,第一个命令适合数据帧上的模型,接下来将使用 predict 命令部署模型,以便接收所需天数的预测。

**plot(m, forecast)**

prophet 软件包的开箱即用可视化非常好,具有预定义的刻度线、数据点和不确定性区间。这是这个开源包的优点之一,不需要额外的定制,第一个结果足够快和好,可以满足大多数需求。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

predicting one year of future data points

使用这个图表,我们可以更清楚地发现年度趋势和季节性,以及如何利用它们进行预测。

**tail(forecast[c(‘ds’, ‘yhat’, ‘yhat_lower’, ‘yhat_upper’)])**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

预测对象保存原始数据以及按天和不确定间隔的预测值。还可以通过以下方式访问预测趋势和季节性成分:

**tail(forecast)**

阶段 5-检查模型组件

**prophet_plot_components(m, forecast)**

为了保持简单性,查看模型的组件很容易。显示总体趋势、每周和每年的季节性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Model components

第 6 阶段—定制假期和活动

最后一个组件图显示了在 NBA 季后赛和 NBA 总决赛期间对勒布朗·詹姆斯的兴趣增加。此时,模型识别每年返回的年度季节性。另一方面,勒布朗·詹姆斯目前保持着连续 6 年参加 NBA 季后赛的记录,从迈阿密开始,继续在骑士队。所以我们应该期待年复一年的季节性。

增加假期和活动是该套餐的一大优势。首先,通过使预测更准确,并允许用户考虑已知的未来事件。开发人员已经使这种定制比以前的时间序列包更容易,在以前的时间序列包中,为了进行预测,应该手动更改或忽略事件和假日。设想一个电子商务网站,它可以添加所有重复出现的活动和促销,并根据已知的未来活动日期设定收入目标。

添加事件和假日是通过创建一个新的数据帧来完成的,在该数据帧中,我们传递事件的开始或结束日期以及天数。在这个例子中,我们将添加 NBA 季后赛和 NBA 总决赛作为事件

**playoff_brackets <- data_frame(
 holiday = ‘playoffs’,
 ds = as.Date(c(‘2017–04–16’ ,’2016–04–17', ‘2015–04–19’, ‘2014–04–19’)),
 lower_window = 0,
 upper_window = 45
)****playoff_finals <- data_frame(
 holiday = ‘playoff_finals’,
 ds = as.Date(c(‘2016–06–02’, ‘2015–06–04’, ‘2014–06–05’)),
 lower_window = 0,
 upper_window = 20
)**

使用较低和较高的窗口参数,用户可以设置假期的长度。这些映射将被行绑定到单个对象,并在 holidays 参数中传递。

**holidays <- bind_rows(playoff_brackets, playoff_finals)
m <- prophet(stats, holidays = playoff_brackets)
forecast <- predict(m, future)
plot(m, forecast)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,该模型可以更好地预测峰值期间的值。再次打印出组件将显示增加的假日行对预测的影响。从理论上讲,您可以绘制许多对业务至关重要的事件,并获得更好的预测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第 7 阶段—去除异常值

构建预测时,从历史数据中移除异常值非常重要。尽管这些数据点是单次事件或者只是错误的事件日志,但是模型使用这些数据点将它们的影响添加到预测中。与其他包不同,当传递安娜值和历史数据时会崩溃,Prophet 将忽略这些日期。

在本例中,我们将删除一系列单次事件,其中 NBA 球员宣布他将离开迈阿密前往克利夫兰,这可能会引起人们对他的维基百科页面的注意。

**outliers <- (as.Date(stats$ds) > as.Date(‘2014–07–09’)
 & as.Date(stats$ds) < as.Date(‘2014–07–12’))
stats$y[outliers] = NA**

第 8 阶段—更多功能

此时,我们可以看到开发人员在创建这个包时所考虑的简单性和健壮性。一些我没有展示但应该使用的额外功能:

  • 变化的季节性和假日效应量表
  • 绘制关键趋势变化点
  • 编辑不确定性区间

使用 Prophet 进行异常检测

我希望开发人员的下一步是使用这个包,并利用它对时间序列数据进行异常检测。先前的软件包提供了这样的功能,但是严重依赖于数据结构和严格的季节性。

让我们使用现有的模型来映射数据中的异常。我们将原始值(y)与预测模型值(yhat)进行比较,并创建一个名为 diff_values 的新列。

**combined_data <- cbind(head(forecast, nrow(stats)), stats[order(stats$ds),])
combined_data$diff_values <- (combined_data$y - combined_data$yhat)
summary(combined_data$diff_values)**Min. 1st Qu. Median Mean 3rd Qu. Max. 
0.05269 0.07326 0.10780 0.13490 0.16520 0.29480

为了更好地概括异常检测,我们还将添加标准化的 diff 值,表示与实际值的百分比差异。

**combined_data$diff_values_normalized <-
(combined_data$y - combined_data$yhat) / combined_data$y**

让我们继续观察随时间变化的标准化 diff 值。

**plot(diff_values_normalized ~ ds, combined_data, type = “l”)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Normalized difference prediction to actual values

大多数预测值都非常接近实际值,因为图表倾向于在 0 值附近移动。我们还可以通过过滤 **diff_values_normalized 列的绝对值来询问异常数据点的百分比。**设置一个数据点被视为异常的阈值是一种观察方法。在这个例子中是 10%

**nrow(combined_data[abs(combined_data$diff_values_normalized) > 0.1
& !is.na(combined_data$y),]) / nrow(combined_data)**

我们得到 0.02,这表明基于给定的阈值,2%的数据点是异常的。

结束语

做预测是数据专业人员的一项重要技能。感谢像 Prophet 这样的开源项目,这不需要太困难。这个软件包平衡了简单性、计算速度和适当的定制量,因此初学者和高级用户都可以使用它。

感谢阅读,
Harel Rechavia
Viber 的数据分析师

如何使用 pix2pix 创建 SnapChat 镜头

原文:https://towardsdatascience.com/using-pix2pix-to-create-snapchat-lenses-e9520f17bad1?source=collection_archive---------12-----------------------

我们都喜欢 SnapChat 镜头/滤镜,但有没有想过如何自己制作?

是的,我知道副标题来自我的上一篇文章,在那里我展示了如何使用 dlib 和 openCV 使 SnapChat 像 live filters 一样。但今天我想展示我们如何使用名为 pix2pix 的深度学习网络来创建相同的过滤器。这种方法有助于从以前的方法中消除手动特征工程步骤,并且仅通过神经网络的一次推理就可以直接输出目标图像。那么,我们开始吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Demo

pix2pix 是什么?

它发表在论文用条件对抗网络进行图像到图像的翻译(俗称 pix2pix)。

名称“pix2pix”来自于网络被训练成从输入像素映射到输出像素,其中输出是输入的某种转换。你可以在下图中看到一些例子,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source Paper

pix2pix 真正吸引人的地方在于它是一种通用的图像到图像的转换。它不是为上面的每个任务设计定制的网络,而是处理所有任务的同一模型——只是在每个任务的不同数据集上进行训练。Pix2pix 可以用更少的训练图像和更少的训练时间产生有效的结果。给定一个只有 400 个(外观,图像)对的训练集,并且在单个 Pascal Titan X GPU 上进行不到两个小时的训练,pix2pix 可以做到这一点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source Paper

pix2pix 网络如何工作?

pix2pix 网络使用 2 个网络进行训练。

  1. 发电机
  2. 鉴别器

这里,生成器将尝试从输入训练数据生成输出图像,鉴别器将尝试识别输出是假还是真。因此,两个网络都将努力提高精度,最终形成一个真正优秀的发电机。所以,你可以把网络的基本结构想象成编码器-解码器。

例如,生成器被输入一个实际的图像(输入),我们想把它“翻译”成另一个结构相似的图像(实际输出)。我们的生成器现在产生假输出,我们希望它与真实输出无法区分。因此,我们简单地收集大量“真实事物”的例子,并要求网络生成无法与它们区分的图像。

方法

今天,我们将使用上述模型来创建 SnapChat 过滤器。我将使用下面的图像来显示结果。所有的图像都是 256x256 因为我是在同样的尺寸上训练的(是的,我没有足够的 GPU 能力来训练高清)

现在,让我们收集训练数据!为此我将使用我以前的 教程代码 **。**我下载了一堆人脸图像数据集,还用谷歌下载了人脸图像。

我将**“暴徒生活眼镜”**应用到所有的图像上,并将它们并排放置,因为训练数据需要这种格式。我使用下面的 pix2pix 训练库,它使用 tensorflow 来训练和显示结果。

[## affini layer/pix2pix-tensor flow

有条件对抗网络的图像到图像翻译的张量流端口 https://phillipi.github.io/pix2pix/…

github.com](https://github.com/affinelayer/pix2pix-tensorflow)

一旦您完成生成训练数据,它将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们开始训练。为了训练,我们应该在 pix2pix-tensorflow 存储库中使用以下命令

python pix2pix.py --mode train --output_dir dir_to_save_checkpoint --max_epochs 200 --input_dir dir_with_training_data --which_direction AtoB

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里,AtoB 定义了训练模型的方向。例如,在上面的图像中,AtoB 表示模型将学习将正常的脸转换为戴眼镜的脸。

您可以在 tensorboard 中的训练数据和图形上看到结果,您可以通过以下命令启动 tensor board:

tensorboard --logdir=dir_to_save_checkpoint

一旦你开始看到你的模型有不错的结果,就停止训练,用评估数据来检查实时表现。如果您认为结果对于实时性能来说不够好,可以从最后一个检查点开始训练。

python pix2pix.py --mode train --output_dir dir_to_save_checkpoint --max_epochs 200 --input_dir dir_with_training_data --which_direction AtoB --checkpoint dir_of_saved_checkpoint

结论

条件对抗网络是许多图像到图像翻译任务的有前途的方法。你需要适当地训练,请使用一个好的 GPU,因为我得到了以下输出,训练较少,没有太多的训练数据差异。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你喜欢这篇文章请在 上关注我或者Github或者订阅我的 YouTube 频道**

在本地计算机上使用 pyspark 和 Jupyter

原文:https://towardsdatascience.com/using-pyspark-with-jupyter-on-a-local-computer-edca6ae64bb6?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image orogin: LinkedIn

在版本 2.0 发布之后,随着许多新特性和改进的 SQL 功能的出现, Apache Spark 成为我所掌握的更强大的工具之一。
因此,我想通过添加从 Jupyter notebook / IPython 控制台使用它的功能来增加这一强大工具的易用性。由于能够添加自定义内核,我创建了一组非常简单的指令(在 Ubuntu / CentOS 上测试)来在本地机器上安装带有 Jupyter 内核的 Spark。

在 Linux 上安装 Spark

本手册在 2.2.0 版上进行了测试,但应该适用于所有版本。我假设您已经安装了 Python 和 Java。为了在您的机器上安装 Spark,请遵循以下步骤:

  1. 从 Apache 网站下载 tar.gz 文件(我假设你是下载到 /opt ):
    wget [https://www.apache.org/dyn/closer.lua/spark/spark-2.2.1/spark-2.2.1-bin-hadoop2.7.tgz](https://www.apache.org/dyn/closer.lua/spark/spark-2.2.1/spark-2.2.1-bin-hadoop2.7.tgz)
  2. 提取文件并创建一个软链接到文件夹:
    tar -xvzf spark-2.2.1-bin-hadoop2.7.tgz ln -s spark-2.2.1-bin-hadoop2.7 spark
  3. 验证 py4j 版本(我们将需要它来连接 Spark 和 Jupyter):
    ls -1 /opt/spark/python/lib/py4j* | awk -F "-" '{print $2}' 我得到的输出是 0.10.4,我们稍后将使用它作为*<>*
  4. 验证你使用的 Python 路径:
    which python 我得到的输出是*/HOME/Nimrod/miniconda/envs/compass/bin/Python 2,*我们将此作为<<Python _ HOME>>

完成以上操作后,创建一个内核 json 文件:
mkdir -p ~/.local/share/jupyter/kernels/spark2-local

编辑文件:
vim ~/.local/share/jupyter/kernels/spark2-local/kernel.json ,添加以下内容(不要忘记替换两个占位符):

{
 "display_name": "spark2-local-compass",
 "language": "python",
 "argv": [
  "*<<PYTHON_HOME>>*",
  "-m",
  "IPython.kernel",
  "-f",
  "{connection_file}"
 ],
 "env": {
  "SPARK_HOME": "/opt/spark/",
  "PYTHONPATH": "/home/Nimrod/dev/theGarage/:/opt/spark/python/:/opt/spark/python/lib/py4j-*<<PY4J_VERSION>>*-src.zip",
  "PYTHONSTARTUP": "/opt/spark/python/pyspark/shell.py",
  "PYSPARK_SUBMIT_ARGS": "--master local[*] --driver-memory 3g --executor-memory 2g pyspark-shell",
  "PYSPARK_PYTHON": "*<<PYTHON_HOME>>*"
 }
}

现在,您应该能够观察到在jupyter kernelspec list中列出的新内核,或者在 jupyter UI 中的新笔记本类型下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Example of The new kernel in the Jupyter UI

上面提到的当前问题是,使用--master local[*]参数是将 Derby 作为本地 DB 使用,这导致无法在同一个目录下打开多个笔记本。

对于大多数用户来说,论文并不是一个真正的大问题,但是自从我们开始使用数据科学 Cookiecutter 以来,文件系统的逻辑结构将所有笔记本放在同一个目录下。每当我们想要在多台笔记本电脑上同时工作时,这会导致一个问题。

我花了很长时间寻找解决方案,最终在很长时间后,Amit Wolfenfeld 很快找到了解决方案。第一步是安装 postgresql 并确保其运行!

为了让 pySpark 使用 postgresql,我们需要 JDBC 驱动程序,从这里的下载它们并保存到 /opt/spark/jars/中。

接下来,将用户更改为 postgres ( sudo su postgres)并运行psql :
CREATE USER hive; ALTER ROLE hive WITH PASSWORD 'mypassword'; CREATE DATABASE hive_metastore; GRANT ALL PRIVILEGES ON DATABASE hive_metastore TO hive; \q

运行该命令后,确保重启 postgreql 服务。最后一步是在 Spark 的 config 目录下创建一个文件(假设您遵循了我上面建议的路径,命令应该是:vim /opt/spark/conf/hive-site.xml

将以下内容添加到文件中:

<configuration>
<property>
  <name>javax.jdo.option.ConnectionURL</name>
  <value>jdbc:postgresql://localhost:5432/hive_metastore</value>
</property><property>
  <name>javax.jdo.option.ConnectionDriverName</name>
  <value>org.postgresql.Driver</value>
</property><property>
<name>javax.jdo.option.ConnectionUserName</name>
  <value>hive</value>
</property><property>
  <name>javax.jdo.option.ConnectionPassword</name>
  <value>mypassword</value>
</property></configuration>

就是这样!现在,您可以开始尽可能多的 pyspark 笔记本。

在 Power BI 中使用 Python

原文:https://towardsdatascience.com/using-python-in-power-bi-ee95a6b71443?source=collection_archive---------3-----------------------

自【2019 年 4 月 Python 集成已经在 Power BI 中普遍可用。就像 R 支持一样,现在您可以使用 Python 来导入数据、数据转换和数据可视化。在本文中,我们将一步一步地准备 Python 环境,在 Power BI 中启用 Python,导入数据并将聚类应用于数据,并使用 Python 在 Power BI 中创建自定义的可视化效果。复制该示例所需的所有材料都可以在 GitHub 中找到。本文假设您有一个工作的 Python 环境,并且安装了 Power BI。

在 Python 中创建数据导入脚本

我们将使用的数据集是波士顿住房数据集,可在 scikit-learn 中获得。数据集最常用于回归示例,但我们将采用不同的方法,并将其用于聚类。我们将使用主成分分析来降低维度,以便在二维空间中可视化数据。在此之后,我们将应用 k 均值聚类来尝试识别数据中的任何同质组。

由于本文的主要重点是展示如何在 Power BI 中使用 Python,所以我不会详细介绍创建导入代码的步骤。数据准备阶段可以作为 Jupyter 笔记本提供给那些有兴趣了解它是如何创建的人。我建议创建您将要使用的代码的独立脚本,以便在 Power BI 中使用它之前测试和调试任何问题。Power BI 提供的错误消息并不总是那么有用。

在 Power BI 中启用 Python

使用所需的库设置 Python 虚拟环境

有几种方法可以管理您的 Python(虚拟)环境。除了virtualenvpipenv你也可以使用conda分布。

在这个例子中,我使用 pipenv 来管理 Power BI 将使用的 Python 环境。为了开始,打开一个Command PromptPower Shell控制台,导航到您想要用作 Python 代码工作目录的文件夹。如果您正在使用我的 GitHub 库,请转到您克隆/下载示例代码的位置。我们将运行以下命令来创建 Python 环境并安装所需的库。

pipenv install numpy pandas matplotlib seaborn scikit-learn

如果你用的是我从 GitHub 下载的代码,运行pipenv install就足够了,因为它会自动从现有的Pipfile安装所需的库。

最后,我们希望检查这个虚拟环境的实际 Python 路径,因为我们需要引用 Power BI 中的路径。

pipenv --venv

我的虚拟环境的位置是C:\Users\tomra\.virtualenvs\python_and_powerbi-0r4DNLn9,所以我把路径复制到剪贴板。

**注意:**您可以使用conda来管理 Power BI 的虚拟环境。如果你和我使用过类似的 conda 安装/配置,conda 环境安装在 Windows %userprofile%\AppData的一个系统文件夹中。默认情况下,您不能从 Power BI 导航到该文件夹来选择您的 Python 主目录。解决方法是在 Windows 资源管理器中显示隐藏文件。请注意,在常规的 Windows 使用中,不要意外删除任何系统文件。另一种选择是将 conda 环境放在非系统文件夹中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置 Power BI 以使用 Python

启动电源 BI 并转到Options处,您应该会看到左侧的Python scripting部分。点击该按钮打开Python script options。默认情况下,Power BI 列出了能够在系统中检测到的 Python 环境。我们需要更改这些设置,因为我们为 Power BI 创建了单独的虚拟环境。从Detected Python home directories中选择Other选项。将 Python 主目录设置为虚拟环境所在路径中的Scripts文件夹。我的情况是C:\Users\tomra\.virtualenvs\python_and_powerbi-0r4DNLn9\Scripts

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们已经准备好在 Power BI 中使用 Python 代码,所以准备好吧!

功率 BI

使用 Python 脚本导入数据

我们转到功能区中的Home选项卡,单击Get data并选择More选项开始我们的数据导入。转到Other面板,在那里你会找到Python script选项。选择并点击Connect。将打开一个 Python 脚本对话框,您可以在其中添加自己的代码。将以下代码复制并粘贴到Script文本区,然后点击OK

import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans# utilize the sklearn.datasets package to load the Boston Housing dataset
boston = load_boston()# scale the data to same value range first since PCA
# is sensitive to the scaling of data
sc = StandardScaler()
X = sc.fit_transform(boston.data)# create PCA with n_components=2 to allow visualization in 2 dimensions
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)# divide data into 5 clusters (refer to .ipynb for motivation)
kmeans = KMeans(n_clusters=5, init='k-means++', max_iter=300, n_init=10)
y_kmeans = kmeans.fit_predict(X_pca)# create pandas dataframe of the housing data for Power BI
columns = np.append(boston.feature_names, ['MEDV', 'PC1', 'PC2', 'CLUSTER'])
data = np.concatenate((boston.data,
                       boston.target.reshape(-1, 1),
                       X_pca,
                       y_kmeans.reshape(-1, 1)),
                      axis=1)
df_housing = pd.DataFrame(data=data, columns=columns)
# we need to convert all columns as string because of different
# decimal separator in Python (.) and Finnish locale (,) that Power BI uses.
# comment out below line if Power BI uses dot as a decimal separator.
df_housing = df_housing.astype('str')# create pandas dataframe of the pca data for Power BI
columns = np.append(boston.feature_names, ['VARRATIO'])
data = np.concatenate((pca.components_,
                       pca.explained_variance_ratio_.reshape(-1, 1)),
                      axis=1)
df_pca = pd.DataFrame(data=data, columns=columns, index=['PC1', 'PC2'])
df_pca = df_pca.astype('str')

在下一个窗口中,我们可以选择要导入的数据集。选择df_housingdf_pca数据集,并点击Load。接下来,我们将对导入数据进行最后的调整。点击功能区中的Edit Queries

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于 Python 和 Power BI 中的区域设置可能存在差异,我选择在 Python 脚本中将所有列保存为字符串。需要设置正确的数据类型,根据您的地区/设置,我们可能需要采取不同的路线。目标是将每一列转换成数字。

带小数点的幂 BI

虽然我还没有测试过,但是您应该能够移除Changed Type步骤,选择所有列,并从功能区的Transform选项卡中选择 Power BI Detect Data Type,以便获得正确的数据类型。对两个数据集重复上述步骤。

另一个选项是修改导入脚本,删除/注释我们将数据类型设置为字符串df_housing = df_housing.astype('str')df_pca = df_pca.astype('str')的行。Power BI 应该在导入过程中正确识别数据类型。

带十进制逗号的幂 BI

我们需要替换点(.)改为逗号(,),以便设置正确的数据类型。选择所有列,并从功能区的Transform选项卡中单击Replace Values。用逗号替换点,点击OK

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

之后,点击Detect Data Type,让 Power BI 检测正确的数据类型。对两个数据集重复这些步骤。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后一步是将一个Index Column添加到df_housing数据集。这可以通过功能区中的Add Column选项卡来完成。完成后,转到Home选项卡并点击Close & Apply

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 Python 创建自定义可视化

我们回到Reports视图,开始我们的可视化工作。计划是使用主成分作为轴在图表上可视化聚类。散点图是这种可视化的一个很好的替代方案。点击Scatter chart将其添加到页面中。按照以下方式将df_housing列拖动到可视化效果窗格:

  • PC1拖至X Axis
  • PC2拖至Y Axis处。
  • CLUSTER拖到Legend上,以可视化集群的分组方式。
  • Index拖至Details,因为这将删除图表中的聚合。

最终结果应该类似于下图。由于 k-means 聚类中初始质心的随机选择,您可能会有不同的聚类顺序(着色)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我们将想象每个特征如何影响每个主要成分。该信息可在df_pca数据集中获得。我们将通过热图展示这些信息。Seaborn Python 库提供了一种创建热图的简单方法,因此我们将向页面添加一个Python visual。Power BI 可能会警告您脚本视觉效果,请单击Enable继续。每个特征需要单独拖到Data fields区域。从数据集中拖动除VARRATIO之外的每一列。将下面的代码片段复制到代码区,点击Run script

import matplotlib.pyplot as plt
import seaborn as snsdataset.index = ['PC1', 'PC2']
plt.figure(figsize=(8, 2))
plt.xticks(rotation=45)
data = dataset.loc['PC1', :].to_frame().sort_values(by='PC1').transpose()
sns.heatmap(data,
            cmap='plasma',
            square=True,
            annot=True,
            cbar=False,
            yticklabels='')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您现在应该会看到类似下图的热图。根据您的屏幕分辨率,您可能需要隐藏脚本窗格才能看到视觉效果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

重复相同的步骤为第二个主成分创建热图,但使用下面的代码片段来使用来自第二个主成分的数据,并制作可放置在散点图左侧的垂直可视化效果。

import matplotlib.pyplot as plt
import seaborn as snsdataset.index = ['PC1', 'PC2']
plt.figure(figsize=(2, 8))
data = dataset.loc['PC2', :].to_frame().sort_values(by='PC2', ascending=False)
sns.heatmap(data,
            cmap='plasma',
            square=True,
            annot=True,
            cbar=False,
            xticklabels='')
plt.show()

我建议在其他工具中测试你的 Python 可视化,例如使用 Jupyter Notebook,特别是在可视化很复杂或者你想微调可视化的所有小细节的情况下。还值得考虑在 Python 可视化中使用与 Power BI 报告中相同的字体,以获得统一的外观和感觉。这很容易用 Matplotlib 和它的兄弟实现。

**注意:**有些 python 包只生成 HTML,为了克服这个限制,绘图被保存为图像,然后使用 matplotlib 显示。要写入 png 文件,你需要安装 chrome 驱动程序,例如将 exe 文件放在C:\chromedriver中。一旦你这样做了,你应该把这个文件夹放在PATH环境变量中。在我们的情况下,不需要这一步。

我们现在已经可视化了关于两个主成分的已识别数据簇,这两个主成分一起解释了数据中的大部分差异。热点图显示了哪些要素以积极或消极的方式影响主成分值的每个主成分。让我们做一些最后的润色,使报告看起来更好一点:

  • 将其中一种灰色聚类颜色更改为紫色。
  • 为数据添加标题和引用。
  • 添加显示每个分类的平均中值价格的可视化效果。
  • 添加解释功能的文本框。
  • 添加一个可视化,说明每个主成分解释的差异。

这就是我的版本最后的样子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最重要的是,我们只需再创建一个报告,在该报告中,我们将仔细查看所选要素、中值住房价值(目标)和已识别的聚类之间的关系。通过观察可视化,我们可以得出结论,仅第一主成分就解释了数据中几乎一半的差异。此外,我们可以从图表中看到,较低的主成分值平均转化为较高的中值房价。Distance功能对小幅降低 PC1 值的影响最大,因此让我们更仔细地看看它在不同集群中的表现。我们创建了一个新页面,并进行了以下更改:

  • 添加描述性标题。
  • 添加一个Scatter chart,其中X Axis值为DIS列,Y Axis值为MEDV,并且LegendDetails字段的设置与之前的散点图类似。
  • 右键单击DIS列,选择New group,创建尺寸为 1 的箱子。
  • 添加一个Stacked column chart,通过使用DIS新创建的装箱列显示距离值的分布。按轴而不是计数对图表进行升序排序。

这就是我对这份报告的看法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

摘要

在本文中,我们建立了一个 Python 虚拟环境,并安装了数据转换和可视化所需的库。如果您想利用一些 Python 库,可以在环境中安装额外的库。接下来,我们设置 Power BI 来利用 Python 脚本。这是一次性设置,这意味着您不必在下一个报告中重复这些相同的步骤。最后,我们利用 Python 脚本来导入数据和创建定制的视觉效果。还可以使用 Python 脚本对已经导入 Power BI 的数据集进行数据清理和转换。相对于在 Power BI 之外准备数据并导入可用于可视化的数据集,在哪些用例中利用 Python 脚本更有意义还有待观察。Python 视觉效果的表现也可以更好。但是请记住,这仍然是一个预览功能,它看起来非常有前途!您认为在 Power BI 中使用 Python 有哪些用例?加入讨论,分享你的想法。

用 Python、Pandas 和 Plotly 生成 NBA 投篮图表

原文:https://towardsdatascience.com/using-python-pandas-and-plotly-to-generate-nba-shot-charts-e28f873a99cb?source=collection_archive---------4-----------------------

自从我在阅读 Kirk gold berry court vision 关于 Grantland.com 的一篇文章时偶然发现 NBA 投篮图表可视化以来,我就对体育数据可视化着迷,并对它们如何能够增强球队和球员的决策产生兴趣。因此,当我最近开始学习数据科学时,我很自然地知道,我的第一个兼职项目之一将是试图重建一个 NBA 球员的投篮图表。

收集数据

我的第一步是收集每个镜头的位置数据。随着体育分析发展到几乎每个球队都有专门的分析部门,职业联盟也纷纷效仿,加强了他们的统计部门。NBA 在其网站上提供了一系列详细的统计数据,这些数据是使用安装在每个赛场的第二光谱摄像机收集的,这些摄像机跟踪球员和球的实时运动。从第二光谱收集的数据示例包括速度、行驶距离、油漆接触等。

不幸的是,NBA 不允许在其统计页面上访问 API,所以我不得不深入挖掘以找到我想要的东西——每个球员的详细投篮数据。在每个球员的击球细节页面上,如下所示,你可以查看各种击球情节,并筛选出每个击球的基本细节的电子表格,只需点击播放按钮,就可以看到每个击球的视频。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Kristaps Porzingis Shot Detail Page — https://stats.nba.com/events/?flag=3&CFID=33&CFPARAMS=2017-18&PlayerID=204001&ContextMeasure=FGA&Season=2017-18&section=player&sct=hex

尽管网页上有大量的数据,但这些数据的结构无法让我对其进行正确的分析,我也无法获得我所寻求的全部数据。然而,使用谷歌 Chrome 开发工具,特别是 XHR (XMLHttpRequest),我能够获得一个 json 文件,可以使用 Pandas 轻松读取和转换。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Chrome XHR tab and resulting json linked by url

虽然这正是我在寻找的数据,但我渴望有一种方法来收集任何玩家或一组玩家的数据,而不必重复这些繁琐的步骤。在注意到 725 个字符的 url 字符串只有一个条件值——player _ ID——需要更改才能调出其他人的击球数据后,我编写了一个 python 脚本来收集给定了 nba.com ID 的任何球员的数据。使用 Requests python 库,我能够获取 json 数据,而不必实际访问网站。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Code to grab json data from stats.nba.com and transform into Pandas DataFrame

清理数据

一个不可思议的 python 库中的 Pandas,除了其他特性之外,它还允许我将 json 转换成 DataFrame,并清理数据,只显示我想要的值和列。Pandas 不费吹灰之力就将难看的 json 结构转换成了一种干净、易读的格式。Pandas 还提供了一些简洁的功能,比如。describe()方法,该方法自动计算并输出相关统计数据的样本,例如所有数值列的平均值、中值和标准偏差。如下图所示,这一行代码让我立即了解了纽约尼克斯队的明星前锋克里斯塔普斯·波尔津吉斯的投篮选择。例如,波尔津吉斯的平均投篮距离是 14.28 英尺,他的典型投篮距离篮筐左侧非常近。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sampling of data from Pandas DataFrame

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

.describe() method for Kristaps Porzingis’ DataFrame

策划拍摄

现在,我已经以正确的格式获得了我需要的所有数据,我可以使用 Plotly(一个图表和可视化库)绘制每个镜头了。首先,我用 Savvas Tjortjoglou 的惊人的模板画出一个精确尺寸的球场轮廓。接下来,我将所有的镜头分为两类——成功和失败——然后我可以用不同的颜色绘制出来。使用 Plotly graph objects 模块,我能够将所有的得分和失误绘制为球场轮廓上的散点图,将 X 和 Y 值分别设置为 X_LOC 和 Y_LOC,这表示每次击球尝试的坐标。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Code for creating scatter plot for all shots.

从那里,我需要做的就是运行我的程序,就像变魔术一样,每一个镜头都按照设计的那样被绘制出来。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

对我来说,这是一个非常有趣和充实的兼职项目。它将我对体育的热情与我开始编程后一个月左右学到的各种技能结合了起来。在未来,我想让我的拍摄情节互动,并润色它们,使它们在视觉上更具吸引力,并增强可读性。我还打算引入一些变化,比如用代表每个投篮位置的频率和效率的六边形代替重叠的单个投篮数据点,或者增加一个与联盟平均水平的比较。

用 Python 给自己找了个出租房

原文:https://towardsdatascience.com/using-python-to-find-myself-a-rental-home-a0b1bf6f02e?source=collection_archive---------8-----------------------

通过网络抓取、网络地图和数据可视化缩小我对房屋的搜索范围

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HDB flats in Singapore

“你好,世界!”

随着我在欧洲的冬季交流项目接近尾声,我意识到了现实:我需要在新加坡找到一个新的公寓。

这个简单!我所要做的就是登录这些网站,输入一些搜索参数来找到我的理想公寓。以前租过房子,这个过程相当熟悉和舒适。然而,在快速浏览 Python 一段时间后,我认为这将是创建一个更加高效的搜索过程的好方法,并通过处理一个真实世界的问题来测试我的技能。

在我们深入研究这个项目之前,先花些时间浏览一下 iProperty 的robot . txt文件。虽然他们确实允许机器人抓取他们的网站,但保持谨慎和不滥用赋予我们的这一特权总是很重要的。

语境

现在,当我找到一个出租公寓时,我寻找什么?简单地说,我的最优出租公寓可以描述为这两个变量的函数:

  • 靠近捷运(地铁)站,方便随时随地通勤。
  • 价格合理(因为我是一个破产的学生)。

通常,我会采取以下步骤来找到最佳公寓:

  1. 在房产网站上搜索,找到一个价格合适的单位。
  2. 在谷歌地图上查找地址,看看它是否位于捷运站附近。
  3. 如果位置是我想要的,太好了!不管怎样,我会把它记在某个地方。
  4. 如果位置不是我想要的,那么我会再次重复步骤 1 到 3。

如果重复 3 到 4 次,上面的步骤看起来很容易。然而,对于任何潜在的租户来说,我们知道这种情况很少发生。我们通常必须运行许多迭代来创建足够大的单元池,以便我们进行比较并做出决定。此外,在上面提到的过程之后,接下来是与代理人交谈的过程,根据我的喜好找到单位都是循规蹈矩的,等等。如果在任何时间点出了问题,那么将再次回到步骤 1 到 4。

必须有一种方法,我可以在一个工作空间中编辑所有我想要的搜索结果,只需点击一个按钮就可以进行更有效的比较。

我已经下定决心要在一个叫 Ang Mo Kio 的地方找到一套三居室公寓,这个地方位于新加坡的 20 区。至于网站,我将主要关注 iProperty记住这些参数,因为它们会在这篇文章中反复出现:地区= 20,卧室= 3。

考虑到这一点,我想到了可以帮助我做出这样一个决定的视觉辅助形式。它们是:

  • 一个交互式地图,它可以显示我在一个地区的所有出租屋的位置。
  • 描绘该地区价格分布的图表,这样我就知道会发生什么。

让我用 Python 来做这件事吧!这个项目回购的链接可以在这里找到。现在让我们开始吧。

第 1 部分:数据源

我需要的数据可以从房地产网站上获得。问题是,这不是我习惯的通常的 excel 或 csv 文件。数据以 HTML 的形式出现,看起来有点不同…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为此,我可以使用 Python 漂亮的 Soup 4 包。它允许我从网站上删除 HTML 数据。不过在刮之前,需要增加一些手续:

我需要什么信息?也许是公寓的价格、地址和大小。让我从抓取地址的数据开始。我不是 HTML 专家,但我知道一些元素类型中包含各种形式的信息。图 1 将演示这一点。通过检查源代码,我们可以看到,对于这个特定的单元,关于它的地址的信息包含在这个元素< a >中,在类‘fsKEtj’的 main < div >下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1: Inspecting the source code

提取信息并将其存储在空的“地址”列表中的代码如下:

Figure 2

地址输出?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 3: First five rows of the addresses scraped from the website

太好了!现在已经完成了,我们只需重复同样的过程来查找包含价格大小信息的元素,并通过调整图 2 中的代码来提取这些信息。

这是 iProperty 搜索页面的第一页,显示了 10 套公寓。我需要更多的信息来进行适当的比较。在这篇文章中,我会选择从 5 页搜索结果中提取数据,给自己一个可供选择的公寓池。如何做到这一点?幸运的是,iProperty 的 URL 相当简单:

[https://www.iproperty.com.sg/rent/district-20/hdb/?bedroom=3&page=1](https://www.iproperty.com.sg/rent/district-20/hdb/?bedroom=3&page=1)

如您所见,它只包含三个部分:地区、卧室数量和页码。这让生活变得容易多了,因为我现在可以循环浏览第 1 页到第 5 页。在每个循环之间,我还植入了一个 time.sleep 函数,只是为了让我的网页抓取器表现得有点像人类,并防止我自己被阻止访问网站。

有了这个,我现在有了一个合理大小的公寓池,有三个变量:价格、地址和大小。在使用 pandas 将它们组合成一个数据框之后(还要注意,没有错误显示行数不同,这意味着显示的每个单元都有地址、价格和大小),我现在需要清理数据。让我们看一下数据集的前五行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 4: First five rows of the full data set

在球棒的右边,你可以看到数据的各个方面需要调整。首先,我希望价格尺寸列是数字。因此,SGD、build-up 和必须删除。此外,仔细检查 size 列,有几个单位用“sq”表示。m 而不是 sq。英尺。。这些也需要清洗。所有采取的数据清理步骤都可以在我的项目报告中的脚本中看到。请看一下图 5 中清理过的数据集!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 5: The cleaned data set

快到了!注意到单元有什么问题吗?似乎有一个“流氓”公寓(指数 1),面积很小(100 平方英尺),但非常昂贵(2400 美元/月)。作为一项预防措施,我检查了移除这些单元。

现在我有了 iProperty 上列出的所有公寓的完整数据集,参数区= 20,卧室= 3,让我们开始创建一个交互式地图。

第 2 部分:创建交互式地图

诚然,这部分是项目中最具挑战性的方面。为了在地图上绘制我的数据集中的公寓,我需要上述公寓的坐标。在这里,我将使用 Geopy 包根据我的数据集中的地址检索坐标,并使用 follow 利用这些坐标来创建地图及其交互功能。

首先,我们遍历数据集中包含的所有地址,并提取出每个公寓的纬度和经度。然后,这两个变量将被添加到主数据集中。

Figure 6

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 7: Full data set with new latitude and longitude columns

在获得每个公寓的坐标后,我们现在准备将它们全部标绘在新加坡地图上!让我们创建基本地图:

location = [1.3521,103.8198]
sgmap = folium.Map(location,zoom_start = 12)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 8: Base map of Singapore

现在该添加标记了!对于我的记号笔,我包含了两个可以帮助我更有效地整合信息的特性。

  • 每个标记都根据其价格进行了颜色编码。所有租赁价格都是有序的,并计算它们各自的百分位数。绿色标记表示公寓的租金在 0-30%之间,橙色标记表示 30-70%之间,红色标记表示 70%以上的租金价格。
  • 每个标记处都会弹出一个窗口,显示公寓的地址和价格。

最终产品看起来像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 9: Interactive map with all rental units in the Ang Mo Kio area

从地图上,我可以看到大约有 5 个单位靠近捷运站。有两个相对昂贵的单位(红色),两个价格适中的单位(橙色)和一个相对便宜的单位(绿色)。如果我点击这些单位的标记,将会出现一个如地图所示的弹出窗口。

第 3 部分:显示租金价格分布

这部分相当简单,因为我有我们需要的所有数据。我现在需要做的就是使用 Matplotlib 和 plot charts 来帮助我更好地理解这个地区的价格分布。我更喜欢使用箱线图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

箱线图显示了价格的分布和平均价格。它让我推断出,在 Ang Mo Kio 的大多数三居室单元每月花费大约 2300 美元到 2600 美元。

结论和未来的改进

这个项目有许多方面可以改进。我将来非常想探索的一个领域是在展示公寓时加入一个排名系统。例如,可以使用诸如到 MRT(地铁)的距离、到超市的距离、到学校的距离等因素来给特定公寓分配分数,并且具有较高分数的公寓将更有利地显示在地图上。现在,我的空闲时间到了,我不得不满足于现有的模式。

另一个方面是,所有这些都是在笔记本 IDE 上完成的。如果我想让其他人使用这个工具,他们首先需要访问一个笔记本环境。在未来,我一定会把这变成一个基于网络的应用程序!

通过这个项目,我创造了一个简单的工具,可以帮助我更有效地找到未来的家。摆弄 Python 和它的库是一次愉快的旅程,我一定会回来学习更多!

参考

https://towards data science . com/master-python-through-building-real-world-applications-part-2-60d 707955 aa3—一份精彩的使用 real 的指南

使用 Python 的多重处理模块高效地评估一组算法。

原文:https://towardsdatascience.com/using-pythons-multiprocessing-module-to-evaluate-a-set-of-algorithms-efficiently-1412d29ff849?source=collection_archive---------9-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Power.

有时,在看到数据集后,您的第一直觉是想到可能对其有效的多种算法。然后,您自然会想尝试所有这些方法,看看它们在基线结果上的表现如何。但是有一个因素总是让你重新考虑这个决定。时间的因素。那么,我们如何绕过它呢?让我们试试多重处理。

进程是计算机中的一个工作单元。就 python 而言,您可以将流程视为程序的实例(例如 Jupyter notebook、Python 解释器、独立脚本)。您的操作系统能够同时运行多个进程,您可以将进程映射到系统中的内核数量。如果您有多个内核(这种情况很常见),您可以在不同的内核上同时并行运行多个进程。

我们面临的问题是在同一个数据集上评估多种算法,获取它们的指标,并查看哪种算法的性能最好。这非常适合在分布式内核上轻松运行。这是因为它们彼此独立。也就是说,随机森林训练和测试运行不关心 SVM 训练测试评估的中间结果。因此,我们可以在不同的内核上同时运行它们,并更快地获得结果,而不是在一个内核上逐个运行它们。

不幸的是,python 代码默认作为单个进程在单个内核上运行。幸运的是,使用内置的多处理模块可以很容易地使代码并行运行,并利用所有的 CPU 内核。现在让我们开始研究代码,看看它是如何工作的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Use them all! (Image Source:Vindictus)

假设我们已经将我们的训练和测试数据分开,并准备好像在常规机器学习管道中一样使用。我们还有一个函数 find_rmse(reg ),它接受 sklearn 的回归算法函数,并使用它来训练,然后在数据集上进行测试,并提供我们获得的平均均方根误差。该问题是一个监督回归问题,我们希望在同一数据集上看到四种算法的结果,即随机森林、nuSVM、岭回归和 ElasticNet。

首先,我们将从多处理模块中导入池函数。Pool 对象提供了一种方便的方法,可以跨多个输入值并行执行一个函数,并将输入数据分布到多个进程中。它需要一个参数,这个参数等于您想要生成的工作进程的数量。为了最大限度地利用资源,您可以将其保持为 CPU 中的核心数。但是,请记住,因为所有这些都将主要由这个 python 程序使用,所以在程序执行时,您可能无法在系统上执行另一个处理器繁重的工作。

然后,让我们创建一个我们想要比较结果的回归变量列表。我们的工作非常方便,因为 python 可以将函数作为函数的参数。

现在,让我们将使用回归器训练模型并对其进行测试后计算 rmse 的函数映射到我们的回归器列表。这将把这些回归函数列表并行传递给我们的父函数 find_rmse(reg )!

最后,让我们埋葬我们的池对象的遗骸。

瞧啊。我们只是大大减少了比较这么多回归算法所需的时间。如果你大规模地这样做,这是我目前正在做的研究项目的一部分,这是我们正在谈论的几天和几个月的差异。我的系统有 64 个 CPU 内核,使用它们可以帮助我以指数级的速度实现这一目标。但是如果不使用这种技术,这 64 个内核将会被浪费掉。即使您的个人计算机通常也有 4 个以上的内核,因此您也可以使用这种技术来大幅提高速度。祝您愉快地并行学习!

用 R 将代码点打开的 CSV 文件合并成一个大文件

原文:https://towardsdatascience.com/using-r-to-merge-the-csv-files-in-code-point-open-into-one-massive-file-933b1808106?source=collection_archive---------0-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Map courtesy Trafford Innovation and Intelligence Lab

如果你有一个有邮政编码的数据集,例如客户数据或资产信息,你可以做的最有用的事情之一就是把数据放到地图上。为此,需要对每条记录进行地理参考。英国国家测绘局有一个开放的数据集,叫做 Code-Point Open ,你可以从他们的开放数据网站上获得。该数据集允许您在自己的数据中查找邮政编码,以找到它们的坐标,这样您就可以将它们放在地图上。

英国国家测绘局的数据集包含在一个 zip 文件中,当您提取它时,它由 120 个 csv 文件组成。这可能是一个棘手的问题,所以我将展示如何使用 R(实际上是 R Studio)将所有这些 csv 文件合并成一个文件。还有其他方法可以做到这一点——手动(😱)、编写批处理文件、MS Visual Basic 等,但这是一种优雅而快速的完成方式。

首先,打开 R Studio,创建一个新项目。在项目文件夹中新建一个文件夹,命名为‘temp’。你现在需要从英国测绘局复制 120 个 csv 文件到这个文件夹。

之后,在 R Studio 控制台中,我们需要将这个项目的工作目录设置为 temp 文件夹:

setwd(‘temp/’)

然后,我们需要将该文件夹中所有内容的文件名传递到一个变量中:

filenames <- list.files(full.names=TRUE)

这将遍历该文件夹中的文件,挑选出文件名,并将它们传递到变量‘filenames’中。我们现在将使用这些文件名来遍历文件,从每个 csv 文件中提取数据,并将其合并到一个列表中(注意,这将需要几秒钟的时间来完成):

All <- lapply(filenames,function(i){
read.csv(i, header=FALSE, skip=4)
})

这会将数据推入变量“All”中。如果我们查看“环境”选项卡,我们可以看到这是一个包含 120 个元素的“大列表”,大小为 156Mb。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了使用数据集,或者在 R 中进行匹配,或者保存为它自己的 csv 文件,我们需要将它转换为 dataframe。为此,我们可以运行以下命令:

df <- do.call(rbind.data.frame, All)

为了检查数据帧的内容,我们可以使用 head 函数显示前几行数据:

head(df)

这给了我们这个:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这看起来不错(尽管将列重命名为更有意义的名称可能是个好习惯)。V1 有邮政编码,V3 和 V4 是英国坐标系参考。最后,要将这个大的邮政编码列表保存为一个新的 csv 文件,我们可以使用 write.csv:

write.csv(df,”all_postcodes.csv”, row.names=FALSE)

这将在 R Studio 项目文件夹的 temp 文件夹中创建一个新的(大量的)csv 文件。从这里,您可以将邮政编码文件与您自己的数据合并,以便在 R 中进行地理参考,或者您可以在 Excel 中进行 vlookups。

请注意,本练习之所以有效,是因为每个 csv 文件在数据列数方面具有相同的形状。对于不同的数据集,这种过程变得更加复杂。

下面是一次性完成的所有代码:

setwd(‘temp/’)
filenames <- list.files(full.names=TRUE)
All <- lapply(filenames,function(i){
read.csv(i, header=FALSE, skip=4)
})
df <- do.call(rbind.data.frame, All)
write.csv(df,”all_postcodes.csv”, row.names=FALSE)

用递归神经网络进行噪声中的轨迹检测

原文:https://towardsdatascience.com/using-recurrent-neural-networks-for-track-detection-in-noise-5e6395c8afae?source=collection_archive---------9-----------------------

动机

通过观察声纳雷达屏幕,人类可以很容易地探测到轨迹,这些轨迹是由通常距离很远且只能作为点来观察的物体形成的。即使在有噪声的图像中,也可以在视觉上检测到相应的点图案。此外,当轨迹在噪音中不断出现和消失时,训练有素的操作员可以快速判断不相关的轨迹本身是否形成了可能与同一物体相关的轨迹模式。

需要上述观察来做出关于物体存在或不存在的决定。例如,如果物体与噪声相比非常亮,那么可以通过观察(或检测)单个亮点来做出这样的决定。然而,如果与噪声相关的点表现出与感兴趣的对象相当的亮度,我们最终会得到许多错误的检测。作为对象检测的下一步,我们假设噪声是均匀的,因此与噪声相关的点不会形成轨迹。然而,如果噪声分布不均匀,与噪声相关的点也会形成短轨迹。因此,我们以错误的轨迹检测结束。当由于噪声,感兴趣对象的轨迹很短,使得它们出现和消失,表现出噪声轨迹间歇性时,就会出现这种情况。在这种情况下,人类观察者会寻找与单个物体相关的轨迹模式。一旦发现这种轨迹模式,就可以宣布感兴趣的物体的存在。

另一方面,随着噪声水平的增加和要跟踪的对象数量的增加,现有的基于对象运动建模的跟踪算法必须处理指数级增加的计算复杂度。还应该注意,执行各自的计算增加了数据处理功耗,同时需要强大的处理器和增加的存储器。

最近在机器学习(例如深度学习, DL )的各种应用中取得的重大进展已经证明了匹配甚至超过人类能力的结果(例如在下棋或下围棋方面)。在 Raspberry Pi 等小型单板计算机上成功实现训练好的 DL 表明,使用廉价的自主、低功耗机器人解决目标检测、跟踪和定位问题可能是 DL 应用的新方向。

方法

在这项工作中,我将研究二进制(即黑白)图像中轨迹检测的玩具问题。各自的 Python 代码,写为 Jupyter notebook,使用 Keras 框架,可在这里获得。下面,我展示了这段代码的主要模块和计算的输出。

下面显示的问题不是一个小问题,它的成功保证了在这个领域的进一步研究。下面我实现了一种循环神经网络( RNN ),叫做长短期记忆( LSTM )网络。想法是应用可以同时使用空间和时间信息的算法,以便能够捕获在噪声中呈现间歇出现和消失的对象的模式。

在开始具体示例之前,我导入了这项工作所需的所有 Python 模块。

现在我加载 LSTM 训练和测试所需的预先生成的人工数据。注意,我分别使用了 3000 和 300 幅图像进行训练和测试。这些图像被堆叠成 3D 矩阵,每个图像具有 10×30 像素的尺寸。每个图像被标记为噪声( y[i] = 0 )或包含轨迹( y[i]=1 )。

接下来,为了展示数据的结构,我们看几个示例图像。

例子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上图中,左图显示了由黑色矩形标记的典型噪波分布。在右边,三个图像被连接在一起。从左到右,第一个图像对应于左侧显示的噪声,接下来的两个图像显示了一个线性轨迹,看起来像一个由黑色小矩形框组成的楼梯,向下穿过中间和最右侧的图像。

为了 LSTM 处理的目的,在这项工作中,图像按 10 的顺序进行处理。下面,我只展示了前三个,以强调数据的 3D 排列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

利用长短时记忆模型学习检测轨迹

我在带有 Tensorflow 后端的 Keras 框架中使用 LSTM 模型架构。下面,如果“keras_model_load”设置为 True,将使用预训练模型。如果“keras_model_load”设置为 False,则从头开始训练模型。

现在,我们使用经过训练的模型来预测用于训练和测试的输入图像的标签。

为了估计每个图像的一个标签,我们需要对每个图像的 10 个时间步长生成的 10 个标签进行平均。

由于预测输出是实值,使用阈值 0.5,我将输出分为两类:对应于轨道存在的输出( y =1),以及对应于轨道不存在的输出( y =0)。下面的 y 对应于 Y_estim_testY_estim_train

结果

下面显示了训练和测试结果的子集。在每个连接图像的顶部,绘制了平均标签的分布。蓝色和红色分别显示真实和估计的标签。请注意,对于下面显示的训练子集,这两种标签类型完全匹配。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,我估计了应用于测试和训练数据的检测概率(Pd)和虚警概率(Pfa)。该指标通常用于接收器操作特性估计。

讨论

查看上面显示的输出,可以看到训练的模型倾向于过度拟合(比较训练的 Pd=0.988 和测试数据的 Pd=0.629)。我对大量测试运行的经验(此处未显示)表明,对于该数据集,过度拟合往往会随着训练数据大小的增加而减少,这是意料之中的。

通过寻找更好的 RNN 结构和微调超参数来提高精度是未来潜在的研究课题之一。

尽管所呈现的数据生成算法简单,但是数据生成模型输出非常类似于活动声纳的真实场景。

在这项工作中分析的情况,在任何给定的时间,仅限于检测一个单一的轨道。轨迹检测是在没有对象运动建模算法的帮助下进行的。后者不需要任何训练(除了一些微调),但在操作上需要更昂贵的计算。

这项研究是基于 LSTM 神经网络的第一步,旨在通过发现和检测属于同一物体的轨迹(或轨迹拼接)模式来提高物体检测的可信度,这些轨迹由于噪声而在声纳或雷达屏幕上出现和消失。

用递归神经网络预测明天的比特币(BTC)价格

原文:https://towardsdatascience.com/using-recurrent-neural-networks-to-predict-bitcoin-btc-prices-c4ff70f9f3e4?source=collection_archive---------5-----------------------

深度学习案例研究

利用 TensorFlow 和 Keras |监督深度学习,使用递归神经网络预测第二天的加密货币价格

如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过 Linkedin 来连线吧!请不要犹豫发送联系请求!Orhan g . yaln—Linkedin

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Andre Francois on Unsplash

如果你能以某种方式预测明天的比特币(BTC)价格,这不是很棒吗?众所周知,加密货币市场在过去一年经历了巨大的波动。比特币的价值在 2017 年 12 月 16 日达到顶峰,攀升至近 2 万美元,然后在 2018 年初出现了急剧下降。然而不久前,确切地说是一年前,它的价值几乎是现在的一半。因此,如果我们看看每年的 BTC 价格图表,我们可以很容易地看到,价格仍然很高。仅在两年前,BTC 的价值仅为其当前价值的十分之一,这一事实更令人震惊。您可以使用下图亲自探索 BTC 的历史价格:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Historical Bitcoin (BTC) Prices by CoinDesk

关于这种波动背后的确切原因有几个阴谋,这些理论也被用来支持加密价格的预测推理,特别是 BTC。这些主观论点对预测加密货币的未来很有价值。另一方面,我们的方法评估历史数据,从算法交易的角度预测加密货币的价格。我们计划使用数值历史数据来训练一个递归神经网络( RNN )来预测 BTC 价格。

获取历史比特币价格

我们可以使用相当多的资源来获取历史比特币价格数据。虽然其中一些资源允许用户手动下载 CSV 文件,但其他资源提供了一个 API,用户可以将其与自己的代码挂钩。因为当我们使用时间序列数据训练模型时,我们希望它做出最新的预测,所以每当我们运行程序时,我更喜欢使用 API 来获得最新的数字。经过快速搜索,我决定使用 CoinRanking.com 的 API,它提供了我们可以在任何平台上使用的最新硬币价格。

递归神经网络

由于我们使用的是时间序列数据集,使用前馈神经网络是不可行的,因为明天的 BTC 价格与今天的最相关,而不是一个月前的。

递归神经网络(RNN)是一类人工神经网络,其中节点之间的连接沿着序列形成有向图。— 维基百科

RNN 显示时间序列的时间动态行为,它可以使用其内部状态来处理序列。实际上,这可以通过 LSTMs 和 GRUs 层来实现。

这里您可以看到常规的仅前馈神经网络和递归神经网络(RNN)之间的区别:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RNN vs. Regular Nets by Niklas Donges on TowardsDataScience

我们的路线图

为了能够创建一个根据历史 BTC 价格进行训练并预测明天 BTC 价格的程序,我们需要完成如下几个任务:

1-获取、清理和规范化历史 BTC 价格

2 —与 LSTM 共建 RNN

3-训练 RNN 并保存训练好的模型

4 —预测明天的 BTC 价格,并将其“反序列化”

**奖励:**反序列化 X_Test 预测并创建 Plot.ly 图表

获取、清理和规范化历史 BTC 价格

获取 BTC 数据

正如我上面提到的,我们将使用 CoinRanking.com 的 API 来处理 BTC 数据集,并使用以下代码将其转换为熊猫数据框架:

Obtaining the BTC Prices with CoinRanking API

默认情况下,该函数针对 5 年期 BTC/美元价格进行调整。但是,您可以通过传入不同的参数值来更改这些值。

使用自定义函数清理数据

在获得数据并将其转换为 pandas 数据框架后,我们可以定义自定义函数来清理我们的数据,对神经网络进行标准化,因为这是获得准确结果的必要条件,并应用自定义训练-测试分割。我们创建了一个定制的训练测试分割函数(不是 scikit-learn 的),因为我们需要保持时间序列,以便正确地训练我们的 RNN。我们可以通过下面的代码实现这一点,您可以在下面的代码片段中找到进一步的函数解释:

Defining custom functions for matrix creation, normalizing, and train-test split

定义这些函数后,我们可以用下面的代码调用它们:

Calling the defined functions for data cleaning, preparation, and splitting

与 LSTM 共建 RNN

在准备好我们的数据之后,是时候构建模型了,我们稍后将使用清理和规范化的数据来训练该模型。我们将从导入我们的 Keras 组件开始,并使用以下代码设置一些参数:

Setting the RNN Parameters in Advance

然后,我们将使用以下代码创建具有两个 LSTM 和两个密集层的顺序模型:

Creating a Sequential Model and Filling it with LSTM and Dense Layers

训练 RNN 并保存训练好的模型

现在是时候用清理后的数据训练我们的模型了。您还可以测量训练过程中花费的时间。遵循这些代码:

Training the RNN Model using the Prepared Data

不要忘记保存它:

Saving the Trained Model

我热衷于保存模型并在以后加载它,因为知道您实际上可以保存一个训练好的模型并在下次使用时重新加载它,这是非常令人满意的。这基本上是 web 或移动集成机器学习应用的第一步。

预测明天的 BTC 价格并将其“反序列化”

在我们定型模型之后,我们需要获取用于预测的当前数据,因为我们对数据进行了规范化,所以预测也将被规范化。因此,我们需要反规范化回它们的原始值。首先,我们将使用以下代码以类似的、部分不同的方式获取数据:

Loading the last 30 days’ BTC Prices

我们将只有用于预测的标准化数据:没有训练测试分割。我们还将手动重塑数据,以便能够在我们保存的模型中使用它。

在清理和准备我们的数据后,我们将加载训练好的 RNN 模型进行预测,并预测明天的价格。

Loading the Trained Model and Making the Prediction

但是,我们的结果将在-1 和 1 之间变化,这没有太大意义。因此,我们需要将它们反规范化回它们的初始值。我们可以通过一个自定义函数来实现这一点:

We need a deserializer for Original BTC Prediction Value in USD

定义自定义函数后,我们将调用这些函数,并用以下代码提取明天的 BTC 价格:

Calling the deserializer and extracting the Price in USD

使用上面的代码,您实际上可以获得模型对明天 BTC 价格的预测。

反序列化 X_Test 预测并创建 Plot.ly 图表

你也可能对 RNN 模型的总体结果感兴趣,更喜欢把它作为一个图表来看。我们也可以通过使用本教程培训部分的 X_test 数据来实现这些。

我们将首先加载我们的模型(将其视为单一预测案例的替代方案)并对 X_test 数据进行预测,以便我们可以使用以下代码对适当的绘图天数进行预测:

Loading the Trained Model and Making Prediction Using the X_test Values

接下来,我们将导入 Plotly 并设置属性以获得良好的打印体验。我们将通过以下代码实现这一点:

Importing Plotly and Setting the Parameters

设置完所有属性后,我们最终可以用下面的代码来绘制我们的预测和观察值:

Creating a Dataframe and Using it in Plotly’s iPlot

当您运行此代码时,您将得到以下图形的最新版本:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Plot.ly Chart for BTC Price Predictions

这些结果有多可靠?

如你所见,它看起来一点也不差。但是,您需要知道,即使模式非常匹配,如果您每天都检查结果,结果仍然彼此相差很大。因此,必须进一步开发代码以获得更好的结果。

恭喜

您已经成功创建并训练了一个可以预测 BTC 价格的 RNN 模型,甚至还保存了训练好的模型以备后用。通过切换到面向对象编程,您可以在 web 或移动应用程序上使用这种经过训练的模型。为自己成功开发了一个与人工智能、区块链和金融相关的模型而沾沾自喜。我认为用这个简单的项目同时触及这些领域听起来很酷。

订阅邮件列表获取完整代码

如果你想在 Google Colab 上获得完整的代码,并获得我的最新内容,可以考虑订阅邮件列表:✉️

立即订阅

喜欢这篇文章

如果你喜欢这篇文章,可以考虑看看我的其他类似文章:

[## 使用卷积自动编码器在 10 分钟内降低图像噪声

在时尚 MNIST 的帮助下,使用深度卷积自动编码器清洁(或去噪)有噪声的图像

towardsdatascience.com](/image-noise-reduction-in-10-minutes-with-convolutional-autoencoders-d16219d2956a) [## 使用 MNIST 数据集在 10 分钟内完成图像分类

利用 TensorFlow 和 Keras |监督深度学习使用卷积神经网络来分类手写数字

towardsdatascience.com](/image-classification-in-10-minutes-with-mnist-dataset-54c35b77a38d) [## 利用生成性对抗网络在 10 分钟内生成图像

使用无监督深度学习生成手写数字与深度卷积甘斯使用张量流和…

towardsdatascience.com](/image-generation-in-10-minutes-with-generative-adversarial-networks-c2afc56bfa3b) [## TensorFlow Hub & Magenta 在 5 分钟内实现快速神经风格转换

利用 Magenta 的任意图像风格化网络和深度学习,将梵高的独特风格转移到照片中

towardsdatascience.com](/fast-neural-style-transfer-in-5-minutes-with-tensorflow-hub-magenta-110b60431dcc)

一般建议警告

本网站发布的信息仅供一般参考,并不作为对任何特定人士的具体建议。本文包含的任何建议都是一般性建议,不考虑任何人的特定投资目标、财务状况和特殊需求。

在根据本建议做出投资决定之前,无论是否有合格顾问的帮助,您都应该考虑本建议是否适合您的特定投资需求、目标和财务状况。金融产品过去的表现并不能保证未来的表现。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

使用 sci kit-学会发现恶霸

原文:https://towardsdatascience.com/using-scikit-learn-to-find-bullies-c47a1045d92f?source=collection_archive---------14-----------------------

到目前为止,我所做的大部分工作都是关于神经网络的。然而,这些有一个明显的缺点:它们需要大量的数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The loss of my Quora NLP neural network. The fact that validation loss is much greater than training loss is indicative of overfitting, and this happens quite early in the training.

当我训练一个自然语言处理神经网络来识别相似的 Quora 问题时,这一点非常清楚。即使有 300,000 个数据点可用于训练网络,它仍然没有花很长时间就开始过度拟合。

在本文中,我将使用一个小得多的数据集来练习分类。我将使用各种工具来完成这项工作,包括 SpaCy (一种自然语言处理工具),以及不同的 scikit-learn 算法。

在这个过程中,我将探索我所使用的算法到底是做什么的。

内容:

  1. 问题定义和设置
  2. 用 scikit-learn 算法求解
    a. 逻辑回归
    b. 随机森林
    c. 支持向量机
  3. 结论

问题定义和设置

链接到代码

为了找到一个小数据集来玩,我找到了一个很久以前的 Kaggle 比赛:检测社会评论中的侮辱。训练集有 3000 个数据点,比我上次解决的自然语言处理挑战小 100 倍。

**挑战:**确定一条评论是否会被认为是对对话中另一位参与者的侮辱。

这些评论来自评论网站、留言板等,以 csv 文件的形式提供。

下面是一个非侮辱性评论的例子:

"Celebrity Big Brother IS a mistake."

和一个侮辱性的评论:

"You are stuck on stupid obviously...give me a break and don\'t vote.\\nmoron"

清理数据

正如上面的例子所示,清理句子是必要的。我将使用单词嵌入来量化单词,所以我想在句子中分离出单词,没有任何诸如换行符或撇号之类的无用信息。

为了做到这一点,我把注释中的换行符都去掉了('\\n'在数据中特别常见,所以我专门做了一点去掉),只保留字母。

这样做将上面的注释更改为:

You are stuck on stupid obviously give me a break and don t vote  moron

符号化

SpaCy 非常擅长文字处理,尤其是非常擅长将数据符号化。这意味着它善于识别不同单词在句子中的位置(这很有用,因为它们不总是由空格分隔)。

SpaCy 的另一个非常酷的部分是,它根据手套词嵌入(我在这里探索)自动为这些令牌分配 300 维向量。因此,对我来说,获取一个句子,并从中生成一个嵌入矩阵非常容易。

然而,使用嵌入从句子创建矩阵的直观方法不适用于小数据集。如果我在训练一个神经网络,我的方法只是将所有嵌入向量附加在一起:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The intuitive approach to generating a matrix using word embeddings. Each word has its own 300 dimensional embedding. They are all appended together to create a ‘sentence matrix’.

这样做的问题是,随着句子长度的增加,特征的数量(即矩阵的大小)会激增。该数据集中的平均句子长度为33个单词;这将产生一个大小为(33, 300)的矩阵,有 9900 个元素。

鉴于我的 3000 训练点,这是乞求超负荷。

我的解决方案是找到矩阵中每个元素的平均值,因此我最终得到了每个句子的 300 维“平均值”向量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这意味着每个输入将有 300 个特征;这要合理得多。

使用 scikit 求解-学习

链接至代码

本次竞赛的指标是 AUC ROC 。粗略地说,AUC ROC 分数可以解释为积极分类项目实际上是积极的可能性有多大,以及消极分类项目是消极的可能性有多大。

这比简单的准确性要好,因为它也考虑了数据集中的偏差。例如,如果我的评论中有 95%是侮辱性的,那么一个将每个评论都归类为侮辱性的分类器将有 95%的准确率,但它将是一个无用的分类器。AUC ROC 避免了这一点。

考虑到这一点,现在让我们分别研究每一种算法。

逻辑回归

**它是如何工作的?**该分类器将为我的输入特征中的每个变量定义系数(因此,因为我的输入是 300 维变量,所以定义了 300 个系数)。这就定义了一个函数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

This relationship does not have to be linear; different x terms could be multiplied together, for instance. However, LIBLINEAR, the library used by scikit-learn, does assume a linear relationship.

然后训练这些系数,使得如果输入特征是侮辱,则输出为 1,否则输出为 0。通常使用 sigmoid 函数来简化最后一步:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

This function is called the sigmoid function, and restricts the output to between 1 and 0, which is ideal for classification, where something either is an insult (1) or is not (0). Particularly, it allows f(X) to get very large or small if it is confident in a classification, as the function is asymptotic.

它做得怎么样?微调这个模型非常容易,因为它只有一个真正可以改变的参数:C,或者正则化强度的倒数(基本上,C 控制系数可以变化的程度。这防止了数据的过度拟合)。

逻辑回归得出以下训练曲线:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

These plots show the success of the models on a training set and cross validation set (the cross validation set was made with 20% of the data) as the training set grew from just 100 samples to all the training data available (to 80% of the data). The size of the cross validation set remains fixed. Making these plots of model success against training set size is useful to uncover the performance of the model, and to identify under/overfitting.

这种算法的简单性解释了为什么它训练起来如此之快。它的成功表明,取句子中单词向量的平均值是捕捉句子中情感的高效方式,因为它线性地映射到一个句子是否令人不快。

随机森林

它是如何工作的?为了理解随机森林,理解决策树是有帮助的。这篇文章在这方面做得很好,我不会试图重复,但非常广泛:给定一些数据集(即下面的一些工作机会),信息被用来将数据分成越来越小的子集,直到它被分类为“接受”或“拒绝”(在我的例子中,或者是“侮辱”或“不侮辱”)。更好的数据被用在树的更高层——所以在下面的例子中,薪水将是关于一份工作是否应该被接受或拒绝的最具指示性的指标。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Credit: http://dataaspirant.com/2017/01/30/how-decision-tree-algorithm-works/

随机森林(直观地)通过将数据随机分成(许多)子集来使用许多决策树。然后,在组合结果以生成结论之前,它对每个子集训练决策树。

怎么办到的?训练随机森林时要调整的重要参数是决策树的数量(大约 100 是一个好的起点)和每个数据子集中的特征数量(这里,建议使用特征数量的平方根-大约 17,300 个特征)。

这对我来说证明是最成功的,产生了下面的训练曲线:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里发生了一些严重的过度拟合。训练集的 AUC-ROC 得分接近 1,而交叉验证集的最终得分为 0.87。

当考虑随机森林如何工作时,这确实是有意义的;绝大多数决策树将会是垃圾(并且将会过拟合)。然而,它们应该互相抵消,留下几棵树,这些树可以归纳到交叉验证集(然后是未来的数据)。

支持向量机

**它是如何工作的?**逻辑回归使用线性系数来定义函数,然后使用该函数来预测数据的类别。

支持向量机不是线性系数,而是将数据的每个维度的距离与某个标志进行比较。这定义了一个新的特征空间,然后可以用它来预测数据的类别。

这有点令人困惑,所以让我们考虑一维数据(想象一下,如果不是长度为 300 的输入向量,而是长度为 1):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The sigma defines L1’s ‘circle of influence’. If it is larger, then F1 will be big even if D is large (if X1 and L1 are further apart). If it is smaller, then F1 will vanish if D gets large.

我的特征 X1 现在已经转换为一个特征,然后我可以在一个方程中使用它,就像逻辑回归一样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这使我能够以比简单的线性逻辑回归更复杂的方式分离数据,从而获得更好的性能。

它是怎么做的?与逻辑回归一样,最重要的训练超参数是正则化常数 c。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Note: SVC stand for support vector classification

最终 AUC ROC 为 0.89,是迄今为止最好的分类器。然而,因为它需要定义一个全新的特征空间来进行分类,所以它也比其他算法慢得多,在这个数据集上训练需要 14.8 秒(相比之下,逻辑回归需要 421 毫秒)。

算法对比

这些都是怎么做的?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SVM 是最好的,但是定义新的特征空间导致显著的计算成本,并且它比逻辑回归花费 35 倍的时间来训练(对于 0.01 AUC ROC 的相对小的改进)。

结论

从这里可以得到一些启示:

  1. 我一直惊讶于单词嵌入有多棒,尤其是考虑到它们是如何产生的。2012 年在 Kaggle 上发起这个比赛的时候(单词嵌入之前),获胜分数是 0.84249。单词嵌入让我不费吹灰之力就把这个分数提高到了 0.89。
  2. 除了准确性,还有其他指标需要考虑。SVM 和逻辑回归之间的训练时间差异的重要性给我留下了深刻的印象,尽管 SVM 最终更好,但它可能不是最好的算法。
  3. 所有这些算法都被设计用来处理扔给它们的任何东西,因此相当健壮。考虑到这些算法处理问题的不同,它们的表现非常相似;AUC ROC 评分最大差距只有 0.019——ka ggle 比赛第 1 名和第 10 名的差距。

使用 Scrapy 构建自己的数据集

原文:https://towardsdatascience.com/using-scrapy-to-build-your-own-dataset-64ea2d7d4673?source=collection_archive---------0-----------------------

Web Scraping (Scrapy) using Python

当我刚开始在工业界工作时,我很快意识到的一件事是,有时你必须收集、组织和清理你自己的数据。在本教程中,我们将从一个名为 FundRazr 的众筹网站收集数据。像许多网站一样,该网站有自己的结构、形式,并有大量可访问的有用数据,但很难从该网站获得数据,因为它没有结构化的 API。因此,我们将从网站上抓取非结构化的网站数据,并以有序的形式构建我们自己的数据集。

为了抓取网站,我们将使用 Scrapy 。简而言之,Scrapy 是一个框架,旨在更容易地构建 web 抓取工具,并减轻维护它们的痛苦。基本上,它允许您专注于使用 CSS 选择器和选择 XPath 表达式的数据提取,而不是蜘蛛应该如何工作的复杂内部。这篇博客文章超越了来自 scrapy 文档的伟大的官方教程,希望如果你需要更难的东西,你可以自己做。就这样,让我们开始吧。如果你迷路了,我建议在一个单独的标签中打开视频

入门(先决条件)

如果你已经有了 anaconda 和 google chrome(或者 Firefox),跳到创建一个新的 Scrapy 项目。

1。在你的操作系统上安装 Anaconda (Python)。您可以从官方网站下载 anaconda 并自行安装,也可以遵循下面的 anaconda 安装教程。

Installing Anaconda

**2。**安装 Scrapy (anaconda 自带,只是以防万一)。您也可以在终端(mac/linux)或命令行(windows)上安装。您可以键入以下内容:

conda install -c conda-forge scrapy

3.确保你有谷歌浏览器或火狐浏览器。在本教程中,我使用的是谷歌浏览器。如果你没有谷歌浏览器,你可以使用这个链接在这里安装。

创建一个新的 Scrapy 项目

1.打开终端(mac/linux)或命令行(windows)。导航到所需的文件夹(如果需要帮助,请参见下图)并键入

scrapy startproject fundrazr

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

scrapy startproject fundrazr

这将创建一个包含以下内容的 fundrazr 目录:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

fundrazr project directory

在 Google Chrome(或 Firefox)上使用 Inspect 寻找好的开始网址

在蜘蛛框架中, start_urls 是一个 URL 列表,当没有指定特定的 URL 时,蜘蛛将从该列表开始爬行。我们将使用 start_urls 列表中的每个元素作为获取单个活动链接的手段。

1.下图显示,根据您选择的类别,您会得到不同的起始 url。黑色突出显示的部分是可能要刮除的 fundrazrs 类别。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Finding a good first start_url

对于本教程,列表中的第一个 start_urls 是:

https://fundrazr.com/find?category=Health

2.这一部分是关于获取额外的元素放入 start_urls 列表。我们正在寻找如何转到下一页,这样我们就可以获得更多的 URL 放入 start_urls

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Getting additional elements to put in start_urls list by inspecting Next button

第二个开始网址是:https://fundrazr.com/find?category=Health&page = 2

下面的代码将在本教程后面的蜘蛛代码中使用。它所做的就是创建一个 start_urls 列表。变量 npages 就是我们希望从多少个附加页面(在第一页之后)获得活动链接。

Code to generate additional start urls based on current structure of website

Scrapy 外壳用于查找个人活动链接

学习如何用 Scrapy 提取数据的最好方法是使用 Scrapy shell。我们将使用 XPaths,它可以用来从 HTML 文档中选择元素。

我们将尝试获取 xpaths 的第一件事是单独的活动链接。首先,我们检查一下 HTML 中的活动的大致位置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Finding links to individual campaigns

我们将使用 XPath 提取下面红色矩形中包含的部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The enclosed part is a partial url we will isolate

在终端类型(mac/linux)中:

scrapy shell '[https://fundrazr.com/find?category=Health'](https://fundrazr.com/find?category=Health')

在命令行中键入(windows):

scrapy shell “[https://fundrazr.com/find?category=Health](https://fundrazr.com/find?category=Health)"

在 scrapy shell 中键入以下内容(为了帮助理解代码,请查看视频):

response.xpath("//h2[contains([@class](http://twitter.com/class), 'title headline-font')]/a[contains([@class](http://twitter.com/class), 'campaign-link')]//@href").extract()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

There is a good chance you will get different partial urls as websites update over time

下面的代码用于获取给定起始 url 的所有活动链接(稍后在第一个蜘蛛部分会有更多)

通过键入 exit() 退出 Scrapy Shell。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

exit scrapy shell

检查单个活动

虽然我们应该先了解各个活动链接的结构,但本节将介绍各个活动的位置。

  1. 接下来,我们转到一个单独的活动页面(见下面的链接)进行搜集(我应该注意到,有些活动很难查看)

https://fundrazr.com/savemyarm

2.使用与前面相同的检查过程,我们检查页面上的标题

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Inspect Campaign Title

3.现在,我们将再次使用 scrapy shell,但这一次是一个单独的活动。我们这样做是因为我们想了解各个活动是如何格式化的(包括了解如何从网页中提取标题)。

在终端类型(mac/linux)中:

scrapy shell '[https://fundrazr.com/savemyarm](https://fundrazr.com/savemyarm')'

在命令行中键入(windows):

scrapy shell “[https://fundrazr.com/savemyarm](https://fundrazr.com/savemyarm)"

获取活动标题的代码是

response.xpath("//div[contains([@id](http://twitter.com/id), 'campaign-title')]/descendant::text()").extract()[0]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.我们可以对页面的其他部分做同样的事情。

筹集的金额:

response.xpath("//span[contains([@class](http://twitter.com/class),'stat')]/span[contains([@class](http://twitter.com/class), 'amount-raised')]/descendant::text()").extract()

目标:

response.xpath("//div[contains([@class](http://twitter.com/class), 'stats-primary with-goal')]//span[contains([@class](http://twitter.com/class), 'stats-label hidden-phone')]/text()").extract()

货币类型:

response.xpath("//div[contains([@class](http://twitter.com/class), 'stats-primary with-goal')]/@title").extract()

活动结束日期:

response.xpath("//div[contains([@id](http://twitter.com/id), 'campaign-stats')]//span[contains([@class](http://twitter.com/class),'stats-label hidden-phone')]/span[[@class](http://twitter.com/class)='nowrap']/text()").extract()

贡献者人数:

response.xpath("//div[contains([@class](http://twitter.com/class), 'stats-secondary with-goal')]//span[contains([@class](http://twitter.com/class), 'donation-count stat')]/text()").extract()

故事:

response.xpath("//div[contains([@id](http://twitter.com/id), 'full-story')]/descendant::text()").extract()

网址:

response.xpath("//meta[[@property](http://twitter.com/property)='og:url']/@content").extract()

5.键入以下命令退出 scrapy shell:

exit()

项目

抓取的主要目标是从非结构化的源(通常是网页)中提取结构化数据。Scrapy 蜘蛛可以将提取的数据作为 Python 字典返回。虽然方便和熟悉,但 Python 字典缺乏结构:很容易在字段名中打错字或返回不一致的数据,尤其是在有许多蜘蛛的大型项目中(几乎逐字逐句地复制自伟大的 scrapy 官方文档!).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

File we will be modifying

items.py 的代码在这里是。

将其保存在 fundrazr/fundrazr 目录下(覆盖原来的 items.py 文件)。

本教程中使用的 item 类(基本上是我们在输出数据之前存储数据的方式)如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

items.py code

蜘蛛

蜘蛛是你定义的类,Scrapy 用它从一个网站(或一组网站)抓取信息。我们蜘蛛的代码如下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fundrazr Scrapy Code

在这里下载的代码

将其保存在 fundrazr/spiders 目录下的一个名为的文件中。

当前项目现在应该有以下内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

File we will be creating/adding

运行蜘蛛

  1. 转到 fundrazr/fundrazr 目录并键入:
scrapy crawl my_scraper -o MonthDay_Year.csv

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

scrapy crawl my_scraper -o MonthDay_Year.csv

2.数据应该输出到 fundrazr/fundrazr 目录中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Data Output Location

我们的数据

  1. 本教程中输出的数据应该大致如下图所示。随着网站的不断更新,单个广告活动也会有所不同。此外,在 excel 解释 csv 文件时,每个活动之间可能会有空格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The data should roughly be in this format.

2.如果你想下载一个更大的文件(它是通过将 npages = 2 改为 npages = 450 并添加 download_delay = 2)你可以通过从我的 github 下载文件来下载一个更大的文件,其中大约有 6000 个战役。该文件名为 MiniMorningScrape.csv(这是一个大文件)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Roughly 6000 Campaigns Scraped

结束语

创建数据集可能需要大量的工作,这通常是学习数据科学时被忽略的一部分。有一点我们没有注意到,虽然我们收集了大量数据,但我们仍然没有清理足够的数据来进行分析。不过这是另一篇博文的内容。如果你对本教程有任何问题或想法,欢迎通过 YouTubeTwitter 发表评论。如果你想学习如何使用 Pandas、Matplotlib 或 Seaborn 库,请考虑参加我的数据可视化 LinkedIn 学习课程

利用信号处理提取 Python 中的神经事件——锋电位排序

原文:https://towardsdatascience.com/using-signal-processing-to-extract-neural-events-in-python-964437dc7c0?source=collection_archive---------13-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生物神经网络,如人脑,由称为神经元的特殊细胞组成。有各种类型的神经元,但它们都基于相同的概念。被称为神经递质的信号分子在突触(两个神经元之间的连接点)释放。神经递质通过与细胞膜内的离子通道相互作用来改变突触后细胞的膜电位。如果突触后细胞的去极化足够强,就会在轴突小丘产生动作电位。动作电位将沿着轴突传播,并触发神经递质释放到突触间隙中,这将影响下一个神经元的膜电位。通过这种方式,信号可以通过(整个)网络从一个细胞传递到下一个细胞,动作电位是突触释放神经递质的触发器。神经通信本质上是电化学的,知道何时以及在何种条件下产生动作电位可以对大脑的工作提供有价值的见解。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

By BruceBlaus [CC BY 3.0 (https://creativecommons.org/licenses/by/3.0)], from Wikimedia Commons

但是研究活体大脑中单个神经元的活动是一项具有挑战性的任务。没有一种非侵入性的方法可以在单细胞水平上实时监测神经活动。通常在大脑中插入一个电极来记录其附近的电活动。在这些类型的电生理记录中,动作电位表现为快速高振幅尖峰。但是由于神经元在大脑中密集分布,记录电极通常一次会从不止一个神经元上获得尖峰信号。因此,如果我们想了解单个神经元的行为,我们需要从记录中提取尖峰信号,并检查它们是由一个还是潜在的几个神经元产生的。从数据中提取尖峰并对其进行聚类被称为尖峰排序。在下文中,我们将概述从原始数据中提取单个尖峰并将它们准备用于尖峰排序的过程。

入门指南

所以首先我们需要数据。Matlab 有一个流行的尖峰排序算法叫做波簇。在其网页的数据部分,他们提供了一个测试数据集,我们将在这里使用。根据网页上提供的信息,该录音长约 30 分钟,来自一名癫痫患者。数据存储在。 ncs 文件,这是制造记录系统的公司的数据格式。因此,如果我们想将记录读入 Python,我们需要了解数据是如何存储的。关于有详细的描述。公司网页上的 ncs 文件格式,我们可以用它来导入文件:

>>> # Define data path
>>> data_file = './UCLA_data/CSC4.Ncs'>>> # Header has 16 kilobytes length
>>> header_size   = 16 * 1024>>> # Open file
>>> fid = open(data_file, 'rb')>>> # Skip header by shifting position by header size
>>> fid.seek(header_size)>>> # Read data according to Neuralynx information
>>> data_format = np.dtype([('TimeStamp', np.uint64),
>>>                         ('ChannelNumber', np.uint32),
>>>                         ('SampleFreq', np.uint32),
>>>                         ('NumValidSamples', np.uint32),
>>>                         ('Samples', np.int16, 512)])>>> raw = np.fromfile(fid, dtype=data_format)>>> # Close file
>>> fid.close()>>> # Get sampling frequency
>>> sf = raw['SampleFreq'][0]>>> # Create data vector
>>> data = raw['Samples'].ravel()

在上面的代码中我们可以看到*。ncs* 文件还包含一些关于录音的附加信息。最重要的是,采样频率告诉我们每秒记录了多少数据点。有了采样频率和数据中的样本数,我们现在可以创建一个时间向量,以便绘制信号随时间的变化图。下面的代码将做到这一点,并绘制信号的第一秒。

>>> # Determine duration of recording in seconds
>>> dur_sec = data.shape[0]/sf>>> # Create time vector
>>> time = np.linspace(0, dur_sec,data.shape[0])>>> # Plot first second of data
>>> fig, ax = plt.subplots(figsize=(15, 5))
>>> ax.plot(time[0:sf], data[0:sf])
>>> ax.set_title('Broadband; Sampling Frequency: {}Hz'.format(sf), >>>               fontsize=23)
>>> ax.set_xlim(0, time[sf])
>>> ax.set_xlabel('time [s]', fontsize=20)
>>> ax.set_ylabel('amplitude [uV]', fontsize=20)
>>> plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

好吧,我们看到尖峰了吗?…不,我们没有。但是我们确实在数据中看到了某种有节奏的活动。那么这是一个有意义的信号吗?同样,答案是否定的。如果我们要计算第一秒数据中的峰值数量,我们最终会得到 60 个峰值,这意味着我们看到的是 60 Hz 的振荡。我们可以通过绘制信号的功率谱来进一步证实这一点,该功率谱在 60 Hz 处显示出清晰的峰值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们在看什么?在我们获得数据的网页上说录音来自伊扎克·弗里德在美国加州大学洛杉矶分校的实验室。美国的供电频率是 60 Hz。因此,我们看到的实际上是数据收集期间房间内电子设备发出的电噪声。

找到信号中的尖峰

即使数据中有 60 Hz 噪声,我们仍然可以处理它。幸运的是,动作电位是只持续 1 到 2 毫秒的快速事件。因此,我们可以在排除 60 Hz 噪声的范围内对原始宽带信号进行滤波。典型的滤波器设置为 500 至 9000 Hz,我们的 Python 实现如下所示:

>>> # Import libarys
>>> from scipy.signal import butter, lfilter>>> def filter_data(data, low=500, high=9000, sf, order=2):
>>>     # Determine Nyquist frequency
>>>     nyq = sf/2>>>     # Set bands
>>>     low = low/nyq
>>>     high = high/nyq>>>     # Calculate coefficients
>>>     b, a = butter(order, [low, high], btype='band')>>>     # Filter signal
>>>     filtered_data = lfilter(b, a, data)
>>>    
>>>     return filtered_data

用上述函数处理数据将得到信号的高频带或尖峰通道。我们的期望是,该棘波通道包含动作电位,并且不再有 60 Hz 噪声。让我们看看滤波后的尖峰通道,并将其与原始宽带信号进行比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如所料,尖峰通道不再显示 60 赫兹的振荡。最重要的是,我们终于可以看到记录中的第一个尖峰。在记录开始大约 0.5 秒时,它在过滤数据中清晰可见。同样,既然我们现在看哪里,我们可以在未过滤的数据中看到它。然而,由于 60 赫兹的噪音,它更难被发现。

从信号中提取尖峰信号

既然我们已经将高频尖峰信号带从噪声低频带中分离出来,我们就可以提取单个尖峰信号。为此,我们将编写一个简单的函数来执行以下操作:

  1. 找到信号中高于特定阈值的数据点
  2. 围绕这些事件定义一个窗口,并“将它们剔除”
  3. 将它们对准它们的峰值振幅

此外,我们还将定义一个上限。高于该阈值的数据点将被拒绝,因为它们可能是高频伪影。这种伪影可能是由于患者的移动而产生的,或者可能反映了电气事件,如打开或关闭房间中的灯泡。可以详细看看 Jupyter 笔记本里的尖刺提取功能。这里我们只看一下用我们的函数从信号中提取的 100 个随机尖峰。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在上图中,我们可以看到数据中至少有两种类型的波形。一组尖峰具有尖锐的高振幅峰值,第二组具有较宽的初始峰值。所以这些尖峰信号很可能是由不止一个神经元产生的。因此,下一个任务是找到一种将波形分组到不同簇的方法。但是因为这不能用两三行来编码或解释,我们将在下一篇文章中看到尖峰排序的主题。

同时,你可以在这里查看完整的代码,在 Twitter 上关注我或者通过 LinkedIn 联系我。

这个项目的代码可以在 Github 上找到。

[## akcarsten/spike _ 排序

在 GitHub 上创建一个帐户,为 akcarsten/spike_sorting 开发做贡献。

github.com](https://github.com/akcarsten/spike_sorting)

使用星巴克应用程序用户数据预测有效优惠

原文:https://towardsdatascience.com/using-starbucks-app-user-data-to-predict-effective-offers-20b799f3a6d5?source=collection_archive---------11-----------------------

对于我的 Udacity 数据科学家 Capstone 项目,我使用星巴克奖励应用程序的模拟数据来预测用户接受要约的倾向

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image cropped from Kaique Rocha

项目概述

在我的顶点项目中,我的目标是回答两个主要的业务问题:

  1. 星巴克应用程序上有效报价的主要驱动因素是什么?
  2. 提供的数据,即要约特征和用户人口统计数据,能否预测用户是否会接受要约?

这两个问题背后的商业动机是双重的:首先,从商业角度来看,星巴克可以更好地将他们的优惠瞄准更有接受优惠倾向的顾客。通过这样做,他们有可能最大限度地提高从正确客户的报价中获得的收入,并通过发送更相关的报价来节省营销和促销成本。

其次,从顾客的角度来看,顾客在星巴克和应用程序上获得了更好的体验,因为他们将收到个性化的、符合他们口味的相关优惠。

这个顶点项目使用 Udacity 提供的数据作为数据科学家纳米学位课程的一部分。它包含模拟星巴克奖励移动应用程序上的客户行为的模拟数据。

手机 app 上提供的背景信息是,每隔几天,星巴克就向手机 app 的用户发出一次优惠。有些用户可能在特定的几周内收不到任何优惠,而且并非所有用户都收到相同的优惠。

问题陈述

如上所述,我要回答的问题陈述是(1)发现要约有效性的主要驱动因素,以及(2)探索我们是否可以预测用户是否会接受要约。

提供的数据由 3 个数据集组成:

  • 优惠组合,由每个优惠的属性组成
  • 每个客户的人口统计数据
  • 应用程序上发生的事件的交易记录

使用提供的数据,我使用 3 个分类监督机器学习模型回答了上述两个问题,输入了来自三种不同报价类型的数据。

我使用该模型来揭示特征的重要性,以确定要约有效性的驱动因素,同时探索该模型本身是否可以用来预测用户是否会接受要约。

最后,我还探索了接受或不接受要约的用户的特征。

我的项目旨在回答上面的两个问题,但我最后还添加了两个额外的模型作为探索点,这将在第 4 部分中阐述——第一个,评估是否可以使用一体化模型代替 3 个不同的模型,优惠类型作为分类变量。其次,我还建立了一个回归模型,看看我们是否可以预测用户将花费的金额,假设优惠有效地影响了他们。

如果我能够成功实现上述模型,我的预期解决方案将是找到有效报价的驱动因素,这可能是用户的人口统计属性,例如用户的会员资格。

理想情况下,一个成功的模型还能够预测用户接受要约的倾向,准确率至少为 75%。这将是我计划实现的 3 个模型的基准精度。

为了评估我的模型的性能,我将使用的指标是准确性,并与 F1 分数进行比较,因为这些是分类模型。

与纯粹的准确性相比,F1 分数提供了更好的模型性能感觉,因为在计算中同时考虑了假阳性和假阴性。对于不均匀的类别分布,F1 通常比准确性更有用。

在这种情况下,值得注意的是,F1 分数是基于精确度和召回率的调和平均值,并且侧重于正面案例。对于这里的星巴克应用程序来说,这很好,因为我们会更优先考虑优惠是否有效,而不是为什么优惠无效。

同时,准确性提供了一个很好的总体指标来评估我的模型性能,并且足以用于预测用户接受要约的倾向,因为我们不会太担心负面分类的情况。事实上,出于商业目的,我们可能会允许一些错误分类的负面案例,因为我们可能会通过优惠的激励抓住可能的产品销售,而不是允许错过机会。

至此,我将在以下几个部分解释我的项目:

  1. 数据探索 —我探索所提供数据的属性,并决定用于建模的数据预处理方法
  2. 数据预处理 —我在这部分做了大量的数据清理和特征工程,为建模准备数据
  3. 模型实现 —我实现了我的 3 个模型,并对模型实现进行了细化,考虑了每个版本中的模型性能,并根据结果决定了最佳模型。
  4. 侧面探索 —在实现了模型之后,我探索了一些用于建模数据的替代方法,以及上面提到的一些额外的模型。我还执行了一些进一步的探索性数据分析,以从提供的数据中提取进一步的见解。
  5. 结论 —我对该项目的最终想法,以及我对如何进一步改进数据分析和建模实现的一些思考。

虽然如果需要了解我是如何实现这个项目的,我会深入研究我的代码输出,但我不会深入研究每一步的细节。关于这方面的更多细节,你可以查看我的 Github repo,其中包含了这个项目的 Jupyter 笔记本。

第一部分。数据探索

a.报价组合数据

根据 Udacity 提供的信息,模式如下:

portfolio.json

  • id(字符串)—优惠 id
  • offer_type (string) —优惠的类型,如 BOGO、折扣、信息
  • 难度(int) —完成报价所需的最低花费
  • 奖励(int) —为完成一项提议而给予的奖励
  • 持续时间(整数)
  • 频道(字符串列表)

此外,关于报价的一些进一步信息是,有 3 种不同的报价类型:

  • BOGO——买一送一
  • 折扣——购买折扣
  • 信息—提供有关产品的信息

因此,该模式非常简单,因为它包含 3 种不同报价类型的属性。虽然没有解释持续时间,但我从上下文中推测这是天数。

在获取数据的快照视图后,我注意到在预处理阶段进行数据清理的一些关键元素。其中包括:

  • 稍后在预处理过程中扩展channel列,使其成为我的数据集中的分类变量
  • 特征比例——每个的比例是不同的,例如difficulty是以美元为单位,而duration是以天为单位。
  • 没有空值,我们可以保持原样。

b.人口数据

profile数据集中提供了客户的人口统计数据。模式和变量如下:

profile.json

  • 年龄(整数)—客户的年龄
  • 成为会员日期(整数)—客户创建应用程序帐户的日期
  • 性别(str) —客户的性别(请注意,有些条目包含“O”代表其他,而不是 M 或 F)
  • id (str) —客户 id
  • 收入(浮动)—客户的收入

它也相对简单,因为它包含了客户的人口统计资料。

我对income列做了一些数据可视化,发现需要一些进一步的数据预处理步骤。

  • genderincome列中的空值——如果它们没有占据数据集的大部分,则需要删除

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Income also has a relatively normal distribution, ignoring the null values

  • 清洁age=118

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Distribution for agecolumn

  • became_member_on柱的特征工程

c.交易记录

事务数据的模式如下:

抄本. json

  • 事件(str) —记录描述(即交易、收到的报价、查看的报价等。)
  • 人员(字符串)—客户 id
  • time (int) —以小时为单位的时间。数据开始于时间 t=0
  • value —(字符串字典)—报价 id 或交易金额,具体取决于记录

这个数据看起来有点复杂,因为它是按时间排序的,并且有一个事件和值。特别是,value列必须根据事件进行预处理。

我还发现抄本中的人数(即唯一 id 的数量)与人口统计数据中的人数相同,所以这是个好消息。但是为了从这个数据集中提取有意义的见解,需要做大量的预处理。

现在,我对抄本数据集进行了一些数据清理。为了从值列中提取细节,我根据事件将值展开到各个列中。这样,我就有了一个干净的转录数据集来做进一步的分析。

d.定义预处理模型数据的方法

在为模型预处理数据之前,我首先回顾了我的目标。在对数据进行了初步探索之后,我不得不重新评估我将如何为我打算构建的模型清理和准备数据。

为了确定有效报价的主要驱动因素,我必须首先定义星巴克应用程序中的“有效”报价。因此,我对数据集以及这三者如何相互作用做了进一步的探索。

首先,我研究了每种报价类型中的事件种类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Events grouped by offer_type

我们知道有 4 种类型的事件:offer completedoffer receivedoffer viewedtransaction。但是我们的数据显示我们没有任何与transactions相关联的 offer_id,因为它们没有记录在抄本事件数据中。因此,数据预处理的第一个目标是定义一种方法来将 offer _ ids 分配给特定的事务。

此外,我们还知道 BOGO 和折扣优惠在优惠完成时会有一个offer completed事件。但是,信息优惠没有与此事件相关联。因此,我们还规定了定义有效报价的方法,如下所示:

对于 BOGO 和折扣优惠,如果按正确的时间顺序记录了以下事件,则定义为有效优惠:

offer received->-offer viewed->-transaction->-offer completed

同时,对于信息性报价,由于有offer completed事件与之关联,我必须将交易定义为有效报价的转换:

offer received->-offer viewed->-transaction

第 2 部分:数据预处理

a.为交易分配优惠 id

在定义了上面的方法之后,我们现在必须探索将 offer _ ids 分配给特定事务的方法。考虑因素之一是定义以下主要客户群:

  1. 受影响并成功转化的人群—有效优惠:
  • 已收到报价->已查看报价->交易->已完成报价(BOGO/折扣报价)
  • 已收到报价->已查看报价->交易(信息报价-必须在报价有效期内)

2。收到并查看了优惠但未成功转换的人员—无效优惠:

  • 收到的报价->查看的报价

3。购买/完成优惠而不考虑任何优惠的人:

  • 交易
  • 报价已收到->交易->报价已完成->报价已查看
  • 交易->收到报价->完成报价->查看报价
  • 已收到报价->交易->已查看报价->已完成报价
  • 收到报价->交易(信息报价)
  • 收到报价->交易->查看报价(信息报价)

4。收到聘用但未采取行动的人员:

  • 收到报价

对于第 2 组中的人,我需要检查是否有事件,其中有offer receivedoffer viewed事件,但没有转换事件,即offer completedtransaction——这些是无效报价的情况。

我必须将组 2 中的人与组 4 中的人分开,因为组 2 中的人可能已经查看了报价,但没有采取任何行动,而组 4 中的人甚至没有offer viewed事件。

区分有效优惠的转化(第 1 组)和购买/完成优惠而不考虑任何优惠的人(第 3 组)尤其棘手。对于第 3 组中的人,如果offer completedtransaction出现在offer viewed之前,则转换无效(即,不是从要约的成功转换)。也可能有这样的情况,在查看报价之后发生了offer completed,但是在查看报价之前已经完成了交易。在这种情况下,要约可能已经完成,但它也不是有效的转换。

定义目标变量 **effective offer** :

定义这些条件后,我们必须决定目标变量是什么。

我们知道第 1 组客户将是我们的目标变量effective_offer=1,但对于第 2-4 组客户,有许多无效的报价定义。

那么,我们如何定义无效要约呢?如上所述,第二组属于无效要约的定义范围;用户知道一个提议,但是该提议是无效的,因为它没有将用户转化为顾客。所以第二组可以定义为我们的目标变量effective_offer=0

第三组和第四组呢?组 3 由可能已经收到报价但无论如何都要购买的用户组成。从商业的角度来看,我们不想给他们任何报价。

同时,组 4 用户将被认为是低优先级客户,因为他们不做任何动作,不管他们是否收到报价。

因此,我们可以从模型中取消组 3 和组 4 用户的优先级。仍然值得对第 3 组和第 4 组做一些探索性分析,只是为了探索他们的人口统计数据。

上述条件是我可以通过确保交易发生在offer viewed事件之后来分配“影响”交易的报价 id 的基础。

因此,属于组 1 的任何唯一的 person-offer_id 都可以在我们的目标变量effective_offer=1组中考虑。

同时,组 2 在我们的目标变量effective_offer=0组中。对于第 3 组和第 4 组中的客户,我在模型实现中取消了他们的优先级,但是将在第 4 部分中对他们进行一些探索性分析。

因此,我通过将第 1 组和第 2 组客户数据集附加在一起,为每种包含有效和无效报价的报价类型创建了一个数据集,并成功地为我们的 BOGO 和折扣数据集准备了目标变量。

同时,特别是对于信息优惠,在我们可以标记有效优惠列之前,还有一个额外的考虑—优惠的有效性。这是因为转换事件不是offer completed事件,而是transaction事件。

对于信息性报价,报价的duration可以认为是影响的持续时间。因此,我们可以假设,只有在要约的duration范围内,要约才应被视为有效。

同时,对于 BOGO 和折扣优惠,我们可以假设,如果有转换/ offer completed事件,它应该在持续时间内,因为如果优惠超过其有效期,则完成优惠没有意义。

d.特征工程

现在,我们必须回头看看这些功能,看看如何创造性地创造新功能。

待设计的内径 **became_member_on**

回想我最初的数据探索步骤,became_member_on列是日期格式的。因此,为了从该特征中提取有意义的见解,我们可以将其转换为指示成员任期的特征。一个人成为会员的时间长短可能会对他是否接受邀请产生一些影响。

因此,我从became_member_on列中提取了每个人的会员任期天数,使用 2018 年作为当前年份。

d.ii .收到的报价数

作为进一步数据探索的一部分,我发现每个人可能会收到多个报价。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Multiple offers received per person

我们可以从上面看到,在交易数据中,每个人收到的报价范围可以是 1 到 6 个。我有一个假设,即每个人收到的报价频率可能会导致更有效的报价,所以决定设计一个功能offer_received_cnt来解释这个频率。

d.ii .通过交易分离用户行为

我还想知道根据我的定义,有多少事务被认为是“无效”的。通常,这些是不属于第一组的人完成的交易的总和。优惠的目的是推动购买,因此在交易中花费高的用户将被标记为effective_offers

我们已经定义了第 3 组和第 4 组中的人,他们是独立的用户群,是忠实的消费者,已经倾向于购买更多,不受优惠的影响。

但是对于组 1 中的用户来说,在优惠的效果之外有大量的“无效消费”,可能对优惠的有效性有一些预测能力;因为忠诚的用户可能更倾向于接受报价。

其逻辑是想知道,对于受某些优惠(第 1 组)和第 2 组影响很大的用户,是否存在某种消费基线水平,以及“无效交易”的这种基线水平是否具有某种预测能力,可以预测用户接受优惠的倾向。

因此,我计算了每个人的“无效”交易,作为一个附加特征。

然而,在这样做的时候,我发现在这个工程特性列中缺少的值非常多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

High % of missing values in amount_invalid column for BOGO dataset

由于稀疏性,这个列amount_invalid包含在模型中是否有用是有争议的。由于它是如此“稀疏”,它可能没有太多的信息。我计划稍后在模型实现阶段再次评估这个特性。现在,我决定用 0 填充缺失的amount_invalid列,因为它可能代表只有 4%的用户倾向于购买没有优惠的商品;其余 96%的人只会在知道有持续优惠的情况下购买。

同时,我们已经在上面对incomegender列进行了分析,我已经选择删除它们,因为当它们为空时没有用,并且它们只占数据集的 7%。

丁三世。收到报价的间隔时间

我还想将时间作为一个潜在的特征包含到我的数据集中,但是由于事务性数据从时间=0 开始,我怀疑如果没有一些特征工程,它不会有太大的预测能力。我有一个假设,如果一个人在某段时间内收到了多个报价,那么在收到报价之间的时间间隔可能会有一些预测能力。

第 3 部分:实现

既然数据集已经准备好了,我们就可以开始实现模型了。回到我们的目标,我们想分析有效报价的驱动因素,目标变量是effective_offer

由于我们有 3 种报价类型,因此需要构建 3 种不同的模型。由于我们预测一个提议是否有效,这实际上是一个二元分类监督学习模型。

我决定将简单决策树分类器模型作为基线模型,与集成随机森林分类器模型进行性能比较。我选择决策树作为基线模型的原因是因为我想优先考虑模型的可解释性。回到目标,因为我们打算分析特性的重要性来确定有效报价的驱动因素,所以决策树将为我们的分析提供良好的可解释性。

同时,我还选择了随机森林作为替代模型来比较基线模型,作为对决策树简单集成打包的改进,以提高模型训练的准确性。

在我们继续之前,我们必须确保我们预测的类在每个数据集中是平衡的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Class breakdown between BOGO, discount and informational offers respectively

我们可以看到,所有三种报价类型的等级很不均衡,但也没有不平衡到会造成问题的程度。因此,我们可以着手实现模型。

关于模型评估和验证的说明:因为所有 3 个模型的类是不平衡的,我决定实现准确性和 f1 分数作为模型评估度量,正如前面已经提到的。

a.模型实现

回顾我们的目标,我们创建了 3 个模型来预测每种类型的优惠的有效性,具体取决于优惠属性和用户统计数据。

我执行了建模通常所需的步骤:

  • 定义目标和特征变量
  • 拆分为训练和测试数据
  • 应用特征缩放器

我定义了模型管道函数来实现我的模型,因为我计划实现 3 个不同的模型;因此,重复实现会更容易。

我使用决策树分类器作为我的基线模型,并使用随机分配参数的随机森林分类器来比较性能。

BOGO 公司提供型号

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for baseline DecisionTree (DT) classifier model on BOGO offers dataset

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for RandomForest (RF) classifier model with randomly set parameters on BOGO offers dataset

随机森林分类器(RF)模型的准确性实际上最终略微优于决策树分类器(DT)模型,但总体而言,两种模型的性能大致相同(就准确性而言,分别为 82.14%和 81.77%)。第一次尝试的准确率相当高,超过 80%。我将尝试进一步调整模型,以获得更好的准确性。

然而,就 F1 分数而言,两个模型都低于 80%,随机森林模型与决策树分类器相比表现更差,分别为 75.91%和 79.63%。为了分析这一点,我们必须参考精确度、召回率和 F1 分数的公式:

回忆或敏感度或 TPR(真阳性率):

根据 sklearn 文档,召回直观上是分类器找到所有阳性样本的能力。

全部真阳性中被正确识别为阳性的项目数:真阳性/(真阳性+假阴性)

精度:

根据 sklearn 文档,分类器直观地具有不将阴性样品标记为阳性的能力。

在被识别为阳性的项目总数中,被正确识别为阳性的项目数:真阳性/(真阳性+假阳性)

F1 得分:

因为我的 F-beta 分数是 F1,beta=1,所以我认为召回率和精确度同等重要。

公式由精度和召回率的调和平均值给出:F1 = 2 精度召回率/(精度+召回率)

我们可以看到,DT 的 F1 分数略高于 RF,但都低于准确度。这将表明 DT 模型在不将负面事件错误分类为正面事件方面比 RF 模型做得稍好(意思是,将哪些提议无效的人错误分类为哪些提议有效的人)。

F1 得分与准确性的差异表明,可能存在两个模型都错误地将负面分类为正面的情况,这可能是由于类别的不平衡。但是与 F1 分数相比总体较高的召回率/准确度表明,与预测负面情况(即,要约无效的情况)相比,该模型预测正面情况(即,要约有效的情况)更准确,这在给定不均匀的类别的情况下是可以预期的…

然而,回顾我们的用例,我们可能不太关心这些错误分类,因为我们不介意给人们发送比他们想要的更多的报价;我们不想错过任何一个报价有效的人。

鉴于这种情况,我仍然会选择 RF 型号。

因为我的目标是分析有效报价的驱动因素,所以在我从优化中选择最佳模型后,我将检查模型的功能重要性。

a.ii .折扣优惠模式

我重复上面相同的步骤,但是使用我的 offer_discounts 数据集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for baseline DecisionTree (DT) classifier model on discount offers dataset

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for RandomForest (RF) classifier model with randomly set parameters on discount offers dataset

这一次,随机森林分类器模型在准确性方面也比决策树分类器有更好的表现(87.23%比 86.72%),F1 得分也更低(81.43%比 82.87%)。

与准确性得分相比,这些模型的 F1 得分总体较低。这可能表明,在某些情况下,两个模型都错误地对负面情况(effective_offer = 0)进行了分类。同样,我对此并不太担心,因为我更关心准确预测阳性病例的模型,所以我宁愿选择更高准确性的模型,其中病例effective_offer=1的 F1 得分更高,我们的 RF 分类器在这方面具有更好的性能(0.9317 比 0.9280)。

a .三.信息优惠模式

offers_info数据集重复上述步骤:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for baseline DecisionTree (DT) classifier model on informational offers dataset

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results for RandomForest (RF) classifier model with randomly set parameters on discount offers dataset

与其他两个数据集相比,这些模型的性能更差,两个模型的精度都低于 80%,但 RF 模型的性能仍然更好。F1 得分也更差,为 67.54% RF 分类器,比 DT 模型的 68.66%差。

性能较差的一个潜在原因可能是由于我有一个重要的假设,将转换事件指定为仅在查看要约之后且在指定的持续时间内发生的交易;由于删除了那些不管发生的事务,我可能错过了一些有价值的信息。我们可以从总体样本数据集比其他两个报价的数据集小(大约一半)看出这一点,BOGO 和折扣分别只有大约 5K 个样本,而 10K 只有大约 5K 个样本。

b.精炼

在优化模型时,我将首先尝试对 3 个 RF 模型进行参数调整,然后尝试删除或添加特性来提高模型性能。

b. i .网格搜索发现最佳参数

我决定做 GridSearch 来确定模型的最佳参数。

对于所有三个选项,随机森林模型都有相对较好的性能,所以我使用网格搜索来确定最佳参数。

BOGO:

当我使用最佳参数重新运行 BOGO 数据集的模型时,我获得了以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RF model results with params from GridSearch

与第一个模型相比:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing results for 1st model with 2nd model for BOGO dataset

RF 模型的准确性略有提高,从 82.14%提高到 82.51%,F1 得分从 75.91%提高到 77.64%。这是一个很好的性能提升,但幅度很小,这表明可能无法通过参数调整来提高模型的性能。

因此,我将不得不探索其他途径来进一步提高模型的性能。

对于折扣:

同时,对于折扣数据集,运行 GridSearchCV 获得了以下参数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Best parameters for discount offers dataset according to GridSearchCV

使用这些参数实现模型获得了以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RF model results with params from GridSearch

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing results for 1st model with 2nd model for discount dataset

模型的准确率略有提高,从 87.23%提高到 87.47%,F1 评分从 81.43%提高到 82.06%。好的一面是,现在 RF 模型的准确性和 F1 分数都比 DT 模型好。

但是因为增加很少,我们可以再次得出结论,调整参数不会真正显著提高模型的性能。

对于信息优惠:

最后,对于信息性报价数据集,运行 GridSearch 获得了以下参数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Best parameters for informational offers dataset according to GridSearchCV

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RF model results with params from GridSearch

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing results for 1st model with 2nd model for informational dataset

我们再次看到 RF 模型的准确性有所提高,从 75.09%提高到 75.30%,F1 分数从 67.54%略微提高到 67.78%。这种改进是最小的,所以我们研究改进模型的特征选择。

b.ii 去除稀疏特征,例如 **amount_invalid**

就特征选择而言,我想试试看移除amount_invalid变量是否会有帮助,我们已经注意到它是稀疏的,因此在预测报价的有效性方面可能没有用处。

我从我的数据准备中删除了该特征,并使用通过 GridSearch 找到的相同最优参数重新训练了该模型,将 DT 模型作为基线。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing model 2 with model 3 for BOGO model

模型准确性和 F1 分数确实提高了,所以我将在模型中去掉 amount_invalid 特征。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing model 2 with model 3 for discount model

模型的准确性实际上增加了,而 F1 模型保持不变。在这种情况下,我还将删除折扣模型的 amount_invalid 特性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing model 2 with model 3 for informational model

对于 info 模型,模型的准确性实际上降低了,所以我也将保留这个特性。这是意料之中的,因为与其他两个模型相比,该模型已经有了更差的性能,所以与其他模型相比,该模型稍有不足。因此,该模型需要更多的特征来学习更好地预测。

b. iii。删除一级虚拟变量/一键编码

当涉及到热编码时,使用树模型和使用回归模型是有争议的。对于回归分类模型(如逻辑回归),我们通常应移除一个级别的变量,以防止变量之间的多重共线性。一般来说,我们不应该在我这里使用的基于树的模型中遇到这个问题。

然而,关于一个人是否应该这样做还有一些争论。根据一些文章(如这里的)),通常不建议对分类变量进行编码,因为它们会生成稀疏矩阵,导致:

  1. 由此产生的稀疏性实际上确保了连续变量被赋予更高的特征重要性。
  2. 分类变量的单个级别必须满足非常高的标准,以便在树构建的早期被选择进行拆分。这可能会降低预测性能。

在 RF 和 DT 的 scikitlearn 实现中,必须对变量进行编码。因此,我决定测试我的模型性能,如果我放弃一个级别的分类变量(在我的数据中——渠道变量和性别变量),只是为了减少我的模型数据中的稀疏性和噪声。

然而,我发现,总体而言,仅仅通过减少一个级别的分类特征,模型性能并没有太大的改善。

虽然这三个模型都达到了我的基准利率 75%,特别是 BOGO 和折扣模型,我想探索是否可以改善信息模型的性能。

我将暂时把 BOGO 和折扣模型放在一边,因为我对模型的性能很满意。

b. iv。使用多项式特征

由于 info 模型的低精度分数可能是由于模型拟合不足,所以我决定尝试进一步变换特征是否可以提高模型性能。我对 info 模型中的变量应用了多项式特征变换来检查模型性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing best info model so far (model 2) with current model 5

我们可以看到,RF 模型的性能实际上略有下降。因此,保持模型不变可能是一个更好的主意。信息报价的最大准确度为 75.30%,这是可以接受的,尽管它没有 BOGO 或折扣报价高。毕竟,我们已经根据持续时间对报价的“影响”做了一些假设。

绘制到目前为止 RF info 模型的训练和测试精度会产生以下图表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以从上面看到,当我们通过多项式特征为每个模型添加更多变量并移除 amount_invalid 特征时,该模型在训练准确性方面表现得更好。这只是测试精度降低,我们可以看到这是由于过度拟合。

我可以通过使用 RF info model 5 来进一步提高 info model 的准确性和性能,但要添加更多数据,因为我们已经注意到,offers_info数据集的大小是 BOGO 和折扣数据集的一半。因此,最终有了更多的数据和性能调整,删除了不必要的变量和特征转换,有了更多的数据,我可能最终得到的模型性能可能超过 80%。

b .四、关于最佳模式和特性重要性的讨论

现在,我已经完成了对 3 个模型的优化,我们可以检查所有 3 个模型的最佳模型的结果,并检查功能的重要性,以查看产品有效性的主要驱动因素。使用我的best_model函数,我得到了下面的结果数据:

#get best model overall for bogo,discount and info offers
best_model('bogo').append([best_model('discount'),best_model('info')]).transpose()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Model performance for best models

总的来说,我们可以看到,表现最好的模型是第三个模型(使用 GridSearch 查找最佳模型参数并删除 amount_invalid 列),用于预测 BOGO 和折扣优惠的有效性,而表现最好的信息优惠模型是在执行 GridSearch 查找最佳参数之后。

为了找到有效报价的最有影响力的驱动因素,我们可以检查上面我们的最佳模型的特征重要性。

针对 BOGO 车型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于折扣型号:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于信息模型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

检查功能重要性以分析有效优惠的主要驱动因素,我们可以看到,在所有三个方面,有效优惠的最重要驱动因素是会员资格。然而,第二个最重要的特点是三种型号各不相同。

对于 BOGO 要约,成员任期是最重要的特征,其他变量在比例上要小得多。收入、年龄和 offer_received_cnt 是第 2、3、4 位最重要的特征,但所占比例很小。

对于折扣优惠,在会员资格之后,年龄和收入是下一个最重要的变量。但是比例还是很小的。

与 BOGO 和折扣模型相比,信息优惠模型的特征重要性更加分散,收入是第二重要的特征。年龄是第三位,有趣的是移动渠道是第四位。

第 4 部分:侧面探索

a.探究第 3 组和第 4 组用户——不看任何优惠就购买的人

我们之前将第 3 组和第 4 组的人描述为不管是否看到任何报价都会购买的人。现在我们可以做一些探索性的分析,看看这个用户群是由什么样的人组成的。

人工智能数据准备

观察第 3 组和第 4 组的人与第 1 组和第 2 组的人的对比会很有趣,所以我决定在这三组人之间进行比较。

我将来自三种报价类型的所有组的数据附加在一起,然后通过可视化比较每个组的特征。

我还清除了数据集的空值,类似于上面为建模而准备的数据集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Size of each group of customers in overall dataset

比较 3 个组的大小,我们可以看到组 1 最大,而组 2 最小,这并不奇怪,因为我们已经看到我们的数据集中的类不平衡,有利于正类(即effective_offers=1)。同时,对于第 3 组和第 4 组的人来说,也有相当多的人,比第 2 组的人多。

a .二.人口特征探索

同时,为了有效地比较各组,我将各组一起可视化。

首先,我们可以探讨 3 个群体之间的收入分配。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这三个部分中,大多数人都属于中等收入范围(5 万-10 万)。这三个部分之间的收入分配相对相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三个组之间的年龄分布看起来也相对相似,大多数人在 40-80 岁之间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二组是根本没有消费的人,因为优惠对他们无效,因此他们不在图表中。但对于第 1 组和 3+4 组,我们可以看到花费的金额相对相似,只是第 1 组的人花费略多。这是意料之中的,因为我们可能会认为,这些优惠设法刺激他们购买更多,因此他们的总体支出增加了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

会员任期的分布在 3 个细分市场之间看起来也很相似,大多数人的任期在 0-700 天之间。至少在目前提供的数据中,这三个组之间似乎没有太多的人口统计学特征差异。

b .潜力一体机型号

出于好奇,我想知道如果要约类型作为一个分类特征包含在内,我们是否可以预测要约的有效性。优惠的类型会影响用户的反应吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DT baseline model for all-in-one dataset

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RF model for all-in-one dataset

在初始化和运行模型之后,我对照一体化模型检查了我之前构建的所有三个模型的性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将每种优惠类型的 3 个最佳型号的性能与 all_in_one 型号进行比较,我们可以看出,all-in-one 型号不如 RF bogo 和 discount 型号,大约略好于 info 型号。这可能是由于信息模型拉低了性能,导致一体化模型的准确性降低。我怀疑,如果我们将一体化模型的性能分解为只看它预测信息提供类型的有效性的能力,它也将比它预测其他 2 种类型的性能差。

如果我们退一步,从全局来看,3 个独立的模型具有更高的精度比一个一体化模型更有用。这是因为 BOGO 和折扣优惠实际上旨在通过一些促销成本来推动销售,而信息性优惠基本上是免费的,没有成本,如果它们能够推动销售,那将是一种奖励。

因此,我实际上建议 3 个独立的模型更有用。

c .给定一个有效的报价,我们能预测某人会花多少钱吗?

除了一体化模型之外,由于我们已经保存了有效交易的数据集,我很想知道我是否可以建立一个回归模型来预测某人在给定有效报价的情况下会花多少钱。我可以为每种优惠类型分别建立一个模型来预测他们的消费,但是我很想知道优惠类型是否也会决定用户的消费水平。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Comparing results for both regression models

然而,回归模型在预测支出金额方面表现不佳。根据我们第 1 组客户的当前数据,似乎没有足够的信息来预测该优惠类型可以推动的金额。我们可以看到决策树回归模型确实过度拟合了数据,训练分数非常高,但测试分数低于标准。同时,线性回归模型(具有岭/l2 正则化)也显示了特征和目标变量之间的最小相关性。这个模型确实对数据拟合不足。

如果我再次根据优惠类型将模型分成 3 个不同的模型,我可能会获得更好的性能;或者甚至尝试包含不受影响的/无效的事务,但这可能是另一次的探索。

第五部分:结论

总的来说,我发现这个项目很有挑战性,主要是因为transcript数据集中的数据结构。我从两个商业问题开始:

  1. 星巴克应用程序上有效报价的主要驱动因素是什么?
  2. 提供的数据,即报价特征和用户人口统计数据,能否预测用户是否会接受报价?

a.反射

人工智能问题 1 调查结果

对于问题 1,所有 3 个模型给出的特征重要性是,成员的任期是要约有效性的最大预测因素。进一步的研究将能够表明什么样的平均任期天数将导致有效的 BOGO 要约。

对于所有三个模型,前三个变量是相同的——成员任期、收入和年龄。但是,收入和年龄会根据优惠类型改变订单。

对于 BOGO 和折扣优惠,特征重要性的分布相对相等。然而,对于信息提供,分布稍微平衡一些,收入是第二重要的变量。

二.问题 2 调查结果

我决定使用 3 个独立的模型来预测每种优惠类型的有效性,最终 BOGO 和折扣模型的准确性较好(BOGO 为 82.83%,折扣为 87.35%),而信息性优惠的准确性稍差(75.3%)。然而,在商业环境中,我认为 75%是可以接受的,至于信息性报价,通知用户产品是没有成本的。

与此同时,对于 BOGO 和折扣模型,我对 80%及以上的准确性非常满意,因为在向人们显示报价的商业环境中,即使模型错误分类了一些,整体收入的增加也可能证明这几个错误是正确的。

b.主要挑战和潜在改进

在分析和构建机器学习模型来回答上述问题时,我对主要挑战和发现的思考如下:

为交易分配 offer _ ids 的 b.i .归属框架

为了回答问题 1,我必须首先使用交易记录来定义“有效要约”的含义。这被证明是项目中最棘手的部分。我必须定义一个有效转化的漏斗,因为我们有有效和无效转化的数据。因此,我根据每个人之前发生的事件,为转换事件(offer completedtransaction事件)设计了一个归因模型。

最后,我不得不根据用户在脚本数据中的行为,将他们分成 4 个不同的池:

  • 第 1 组:受优惠影响并因此购买/完成优惠的人(成功/有效转换优惠)
  • 第 2 组:收到要约但未受影响的人,因此没有转换事件(要约的无效转换)
  • 第三组:有转化事件但实际上没有受到要约影响的人
  • 第 4 组:收到提议但没有意见或行动的人

即使在将组分开后,根据事务数据将人分配到组 3 也是一个挑战。我必须先定义事件空间,在这个空间中,正确的事件序列将会发生,然后我才能为事务分配一个 offer id(它没有 offer_id),本质上是设计一个基于事件/序列的属性窗口。

在将转化归因于特定的优惠之后,剩下的数据准备和清理就相对简单了。我很高兴没有很多丢失的值,分类变量的准备也相对简单。

b.ii .特征工程

我决定做一些基本的特征工程,因为我发现这个模型在这个项目中的第一次尝试中有点不足,所以我后来添加了特征工程部分。它略微提高了模型的性能,我从became_member_on列中设计出的 membership _ tension 特性最终成为最重要的预测变量。

然而,总的来说,我发现我想不出使用时间数据的额外功能,即使我有预感,收到要约的时间可能对确定它是否有效有很大影响。

b .三.模式实施决定

根据我对问题陈述的定义,我决定根据报价类型建立 3 个独立的模型,因为我想发现什么会推动有效的报价,我认为通过将数据分成报价类型来消除数据中的干扰更有意义。我的决定最终是一个相当好的决定,因为与一体化模型的总体分数相比,单一 BOGO 和折扣模型在测试分数中获得了良好的表现。

对于信息模型,准确性稍差,因为我们有更少的记录(BOGO 和折扣模型的一半)。如上所述,我相信如果我们有更多的数据,我可以获得更高的准确性,因为在我决定改进模型拟合(如添加多项式特征和移除“有噪声”的特征,如 amount_invalid 特征)时,训练和测试得分之间出现了明显的背离模式。由于数据有限,我的决策以模型过度拟合而告终,因此我相信更多的数据会有助于模型的准确性。

关于模型选择的补充说明—我选择了基于树的模型,因为我想评估特征的重要性,但我可以通过测试参数/回归模型(例如,用于分类任务的逻辑回归)来进一步扩展这项研究。假设回归模型和基于树的模型具有不同的数据分析方式,那么这两种模型的系数权重可能会与基于树的模型的特征重要性形成对比。与本研究中的情况相反,功能membership_tenure_days可能不是权重最高的功能。

b .四、探索不同客户群的人口统计

我很想知道第 3 组和第 4 组的特点是什么,他们是完全不受报价影响的客户。然而,在将他们的特征与第 1 组和第 2 组进行比较后,我看不出他们在人口统计学上有任何显著差异。

我希望有更多的数据来了解为什么这部分客户往往不受优惠的影响,以便提出有用的建议,告诉他们如何给他们提供良好的客户体验,即使我们不向他们提供任何优惠。

b.v .模型在有效报价下预测花费金额的准确性

我出于好奇建立了一个回归模型,看看我们能否预测用户的消费金额,因为他们会受到优惠的有效影响。这样做的动机是,如果我们能预测给定一个报价,某人会花多少钱,也许我们就能评估哪个报价能带来最多的收入。

然而,我的模型发现,所提供的功能(即,应用程序用户的特征和人口统计数据)与每个用户的消费金额之间几乎没有相关性。这些功能还不足以预测每个用户的花费。也许如果我们也有一个报价的价值,例如,一个折扣报价,以美元计算的折扣价值,也许我们能够更好地预测。

也许我可以把它们分成 3 个不同的模型,用于 3 种报价类型,就像我对二元分类模型所做的那样,以便得到更好的结果。然而,考虑到这只是一种好奇,我想探究报价类型是否是一个具有统计显著性的预测特征,我为此实例构建了一个一体化模型。如果有更多的时间和数据,这将值得进一步探索。

c.最后的想法

transcript数据集的顺序、基于事件的性质带来了最大的挑战,但它在应用程序数据或许多数字分析数据(包括 web 在内的交易数据)中很常见。因此,我发现这次挑战是一次有益的经历。

如果提供更多种类的产品数据以及产品价格,这个项目肯定可以进一步扩大。它可以扩展到更长时间的客户细分练习,以确定偏好某些优惠类型或产品的客户的属性,甚至预测优惠的相关价格范围。

然而,数据准备和清理会更具挑战性,因此在这种情况下,我很感激所提供的数据更加有限和可控。我对我的车型在此范围内的表现感到满意。

如上所述,这篇文章虽然包含了理解所需要的代码输出,但缺少项目中的详尽细节。如果你想进一步了解我的代码和分析,可以点击这里的链接

使用统计数据进行数据驱动的决策

原文:https://towardsdatascience.com/using-statistics-for-data-driven-decisions-5df26043608b?source=collection_archive---------4-----------------------

需要做出决定是不确定性的明显表现。当存在不确定性时,就存在风险,我们都想降低风险。数据分析是我们用来减少不确定性的工具之一。

随着数字时代的到来,数据量超出了我们所有人的处理能力,每个人都可以访问某种类型的数据。不幸的是,并不是每个人都有足够的知识来创建和使用数据,所以有很多错误的见解/信息被有意或无意地创造出来。我们需要确保我们不是在试图验证先入为主的想法。先入为主的想法会产生偏见,而偏见会损害你的分析。我们,分析专家,特别是当我们年轻时,我们可能会被我们的高级经理陷入这种情况,但我们需要小心做我们应该做的事情。我们都有一个最高目标,那就是尽可能多地获得真相。我们都想找到帮助我们更好地理解数据集的秘密模式。不要让别人把你引向欺骗的道路。

数据挖掘试图发现有意义的模式,统计试图确认这些发现的模式。如果你思考数据和信息,你会意识到它一直在变化。每一秒都有新的点击,新的客户,新的销售等等。当我们从现有的数据分析中得出一些结论时,我们能确定我们能从新的数据中得出同样的结论吗?这就是进退两难的境地…

有一点我们必须永远记住:即使我们在分析所有的流量、所有的客户、所有的人口,我们也总是在处理样本数据。因为每次我们从数据中得出结论,都属于那个特定的瞬间。我们真的不知道下一分钟,或者下一天,或者下一年,会不会出现同样的结论。通过数据分析,我们都在**尝试预测未来。**因此,如果我们想要进行预测,有时与较小的团队合作也是有意义的。

如果没有统计学背景或学历,可以从简单的统计学入手。我会从的零假设开始。它只是暗示观察到的差异仅仅是由于偶然。这项技术的目的是确保我们不会简单地自动接受任何表面价值的差异。我们想确保这个事实不会被推翻。

据(https://explorable.com/null-hypothesis)

零假设 (H 0)是研究者试图反驳、拒绝或取消的假设“无效”通常指的是对某事物的普遍看法,而另一种假设则是研究者真正认为是某一现象的原因。

为了量化零假设,我们使用 P 值

据(http://www.statsdirect.com/help/basics/p_values.htm)

当研究问题的零假设(H 0)为真时, P 值或计算概率是发现观察到的或更极端的结果的概率——“极端”的定义取决于假设如何被检验。

如果 p 值很大,这意味着观察到的差异可能更多,这是预期的,零假设为真,意味着实际上没有真正的差异

如果 p 值很小,观察到的差异可能是真实的,因为这不是预期的。例如,如果 p 为 5%,这意味着观察到的差异可能在 95%的置信水平内可信。这 95%称为 q 值。

虽然谷歌分析帮助每个人访问你在线资产的数据,但它也对分析和人才产生了错误的假设。一些可以访问谷歌分析的人开始填写 Linkedin 的职位描述,成为数据分析师或分析大师。由于许多高级管理人员是数据概念的新手,他们一直在雇佣那些只能从谷歌分析中阅读的人,并对他们抱有期望。

当数据分析没有得到统计数据的支持时,您可能会遇到严重的问题,或者您可能不会得到任何有意义的结果。如果你是一名新的分析师,或者你是一名基于数据做出决策的经理,你应该通过统计测试来检验所有重要的见解。

更多即将推出…

西贝尔·阿克切卡亚

同时发布于:http://www . webanalyticspower . com/en/2017/09/using-statistics-for-data-driven-decisions/

使用 Tableau 可视化维基百科上最棒的视频游戏列表

原文:https://towardsdatascience.com/using-tableau-to-visualize-the-list-of-greatest-video-games-from-wikipedia-eee804459f29?source=collection_archive---------1-----------------------

几周前,我在博客上发布了一篇文章,回顾了我对一个维基百科页面的抓取,该页面列出了有史以来最棒的视频游戏。与此同时,当我忙于其他事业时,我想重温我收集的信息,看看我是否能以有趣的方式将数据可视化,并练习我的紧急画面技巧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Solid Snake and Liquid Snake from Metal Gear Solid (1998). Original artwork by Yoji Shinkawa

为此,我使用了 Tableau Public ,这是一个免费下载的应用程序,具有相当的深度。使用这个程序的一个注意事项是,您需要创建一个 Tableau 配置文件来保存您创建的任何可视化效果。这些将由 Tableau 公共网站托管,因此在保存您的作品之前,您需要了解与您的数据相关的任何专有问题。

简要回顾一下数据,我在这个过程中使用的最伟大的游戏列表包括 1978 年至 2013 年期间发布的 100 款不同的游戏。这些数据包括每款游戏的发布年份、游戏名称、发布的原始平台/主机、游戏类型以及游戏出现在“最伟大游戏”列表中的次数。以下是数据表内容的部分快照:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Basic structure of the “Greatest Games” data table.

我最初在 pandas 中将这些信息保存为数据帧,然后将数据转换并保存为本地 csv 文件。Tableau Public 在可以处理的文件类型方面非常灵活。它可以导入或连接到单个文件(excel,JSON 等。)或远程数据服务器。要处理 csv 文件,您需要从开始菜单中选择“文本文件”。

Tableau Public 的另一个重要特性是,它可以直观地读取和理解每个数据列中存在的数据类型(例如,分类、连续、地理空间),这使得“拖放式”可视化更容易生成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The data structure of my csv file, as interpreted by Tableau. Categorical columns are labeled “Abc”, while continuous variables are labeled “#”. I generated an additional column of information “Console Developer” to ease some of my later visualizations.

创建任何给定的绘图时,只需打开一个新的工作表(参见 Tableau 窗口的左下角),然后将感兴趣的变量拖到它们各自的列、行或标记字段中。这里有几个额外的字段可以以有趣的方式使用,我不会在这里深入讨论。(例如,左上角的“pages”字段可与时间序列数据一起使用,创建一种数据活页本,显示您的时间数据的每一天/月/年。)

下面快速浏览一下 Tableau 窗口,其中一些数据已经放置到位。该图在 x 轴上描绘了年份,在 y 轴上描绘了最伟大的游戏列表出现的数量,游戏作为每个单独的点,由原始平台着色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然 Medium 还不允许将 Tableau 可视化直接嵌入到帖子中,但我可以发布图像捕获,然后在图像中嵌入链接,将您带到 Tableau 公共网站上这些可视化的交互版本。(对于其他介质用户,可以在 Mac 上使用 Command+K,在 PC 上使用 Control+K,在图片上嵌入链接。)

下面是上述情节的一个更加完美的版本,它链接到交互式 Tableau 版本:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用该链接,你可以将光标悬停在图中的任何数据点上,以显示每个游戏的名称、发布年份和原始平台,以及它出现在最伟大游戏列表中的数量(根据维基百科)。

乍一看,这个最初的情节非常有趣。我们可以看到,在 90 年代中后期和 21 世纪初,游戏数量和最伟大游戏列表的数量呈现出总体上升趋势,在 21 世纪中期和以后再次下降。这可能部分是由于历史偏见,90 年代末和 21 世纪初出现在足够远的距离,以至于流行观点已经就这些游戏的伟大之处达成一致,而其他更现代的经典游戏,如《最后的我们》,自发布以来还没有足够的时间巩固它们在各种最伟大游戏列表中的位置。

虽然一簇簇的点可能有些说明问题,但使用分段条形图可以更容易地查看每年最伟大游戏的数量。探索互动的情节,游戏出现在每年最伟大的游戏名单上的数量下降的顺序。:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当确定过去几十年中每年发布的“最伟大的游戏”的数量时,从表面上看这个图表要容易得多。很明显,1998 年和 2001 年是这里最突出的年份。仅在 1998 年就出现了诸如《塞尔达传说:时间之笛》、《合金装备 2:自由之子》、《口袋妖怪红》、《灵魂口径》、《星际争霸》、《半条命》和《生化危机 2》等开创性经典作品,而 2001 年则出现了诸如《光环:战斗进化》、《超级粉碎兄弟:肉搏》、《合金装备 2:自由之子》、《最终幻想 X》、《侠盗猎车手 3》和《寂静岭 2》等其他具有历史意义的重磅作品。

在查看了按年度发布的最伟大游戏的数量后,我想更仔细地看看由主机发布的游戏的数量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过发布的原始控制台绘制游戏对于 PC 和街机游戏来说有些复杂。这在一定程度上是因为这些平台在某种程度上超越了一代游戏机的概念——在家用游戏机被广泛采用之前,街机平台显然占据了主导地位,而个人电脑是一种不受其他家用游戏机占据的不同时间段限制的永恒平台。不过,有趣的是,在最棒的游戏数量排名中,Playstation 游戏机位列前六名。有趣的是,看看有多少任天堂创造的游戏机出现在这个列表中。

为了让 PC 和 Arcade 拥有平等的竞争环境,我按照主机开发商对游戏进行了分类,以了解不同的主机开发商(如索尼、微软、任天堂)在所有不同平台(如 Playstation 1、Playstation 2、Playstation 3 与 NES、SNES、N64 等)上的表现。)

我决定按照列表中提及次数的降序来绘制每款游戏,并由主机开发人员进行着色:(注意,点击交互式绘图,您可以滚动到右侧查看所有列出的游戏)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我认为有趣的是,尽管索尼的个人游戏机比大多数任天堂平台表现更好,但任天堂开发的游戏在最受好评的游戏中表现强劲,被提到的最伟大游戏数量也很多。

我希望你喜欢点击这些最伟大的游戏的可视化。我真的很喜欢在和 Tableau 一起工作的短暂时间里制作它们。我还希望您已经了解了 Tableau 的工作原理,以及如果您决定尝试一下,它会有多友好。

如果你有任何反馈,请告诉我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值