如何使用 Python 购买 Robinhood 的期权
只是真的想测试我的编程技能,以搞乱股票。
那么什么是交易中的期权呢?它们是给予你在一段时间内以一定价格购买或出售资产的权利的合同。有些人将期权视为某种彩票,但我认为它就像 21 点,你可以采取某些策略来降低风险。
在本文中,我将创建 Python 代码来查看股票并购买它。为了做到这一点,让我们看看如何选择看起来像。这是一个期权标准报价的例子。
美国广播公司 2020 年 2 月 14 日 69 美元电话,4.20 美元
我们来分析一下。 ABC 是期权所基于的股票,通常代表该股票的 100 股。2020 年 2 月 14 日 代表期权即将到期的月份。 69 是股票的执行价格。 叫 会是其中的一个选项类型,这里也可以填入选项。4.20 美元是股票的溢价。
所以到目前为止,在期权交易中,微软的股票对我来说非常好。到目前为止,我已经获得了大量的。你可以在这里看到我的得失。我们将利用微软购买罗宾汉的期权。
我用来从 Robinhood 中提取数据的叫做 robin_stocks 。我有一篇文章展示了如何设置它。
让我们自动化一些股票,可以用来建造一个交易机器人。
towardsdatascience.com](/using-python-to-get-robinhood-data-2c95c6e4edc8)
因此,我对微软股票的交易策略是,我通常在当前日期前 30 天买入期权看涨期权,然后选择高于当前股价的执行价格。
robin_stocks
使它变得简单,我们已经可以拉可用的股票期权,我们可以使用find_tradable_options_for_stock.
发送给他们,我已经设置了它,它已经拉了下面的调用。
r.options.find_tradable_options_for_stock(‘MSFT’, optionType=’call’)
我喜欢在数据框中查看结果,所以我会将所有这些数据转移过来。结果将如下所示:
既然我们知道了有效日期,我们现在可以发送一个包含正确信息的期权订单。我们将使用这行代码在robin_stocks.orders.order_buy_option_limit(*price*, *symbol*, *quantity*, *expirationDate*, *strike*, *optionType='both'*, *timeInForce='gfd'*)
中发送订单
对于价格,我们可以只填写当前的期权价格。对于符号,我们将使用MSFT
。数量我们将只购买 1 个合同订单。对于日期,我们将使用从今天(2020 年 2 月 13 日)起的 30 天。因此,我们将尝试选择一个接近 30 天的日期(2020 年 3 月 13 日)。我们将选择一个最接近且高于当前股价的价格。我们想要一个电话。生效时间对一天有利(gfd)。所以我们的代码看起来会像这样,它在 Robinhood 中的翻译是:
robin_stocks.orders.order_buy_option_limit(4.20, 'MSFT*'*, 1, 2020-03-13, 185.00, *optionType='call'*, *timeInForce='gfd'*)
MSFT 2020 年 3 月 13 日 185 电话 4.20 美元
如果我们用 Python 运行这段代码,订单将被发送。然而,这并不一定是命令的执行。下面是完整的代码:*
访问我的微软得失这里!
我这里还有家教和职业指导!
如果你们有任何问题、评论或顾虑,请不要忘记通过 LinkedIn 与我联系!
如何在 Google Colab 中使用 R
GOOGLE COLAB | RSTATS |笔记本
并使用来自您的驱动器和 BigQuery 的数据
安妮·斯普拉特在 Unsplash 上的照片
Colab,或 Colaboratory 是 Google(主要)提供的一个交互式笔记本,用于通过浏览器编写和运行 Python。我们可以在 Colab 中执行数据分析,创建模型,评估这些模型。这个过程是在谷歌拥有的云中服务器上完成的。我们只需要一个浏览器和一个相当稳定的互联网连接。
无论是作为学生、专业人士还是研究人员,Colab 都是促进我们工作的一个很好的替代工具。
虽然 Colab 主要用于 Python 中的编码,但显然我们也可以将其用于 R ( #Rstats )。
这篇文章将告诉你如何在 Google Colab 中运行 R,以及如何在 R 笔记本中挂载 Google Drive 或访问 BigQuery。
在 Colab 中运行 R 有两种方法
- 第一种方法是在 Python 运行时使用 rpy2 包。这个方法允许您一起执行 R 和 Python 语法。
- 第二种方式是实际上在 R 运行时启动笔记本。
如何在 Colab 中一起使用 R 和 Python
- 打开你最喜欢的浏览器。
- 创建新笔记本:https://colab.research.google.com/#create=true。
- 通过执行该命令
%load_ext rpy2.ipython
运行 rmagic 。 - 之后每次要用 R 的时候,在每个单元格的开头加
%%R
。
通过在单元格中执行以下命令来启动 rmagic :
%load_ext rpy2.ipython
使用%%R
执行细胞魔法。如果您希望在 r 中执行单元格中的所有语法,请使用此选项。注意,它必须放在单元格的开头。
%%R
x <- seq(0, 2*pi, length.out=50)
x
这些行将返回一个变量 x ,并将其显示在单元输出上:
图片作者,x
Use 【 to execute 线魔。如果您希望单元格中的一行在 r 中执行,请使用此选项。
下面是如何使用这一行魔法将 R 变量复制到 Python 中:
x = %R x
作者的图像,通过使用 line magic 在 R 和 Python 之间传递变量,并在 Python 中显示 x
如何在 Colab 中使用 R
要直接用 R 使用笔记本:
- 打开你最喜欢的浏览器。
- 转到这个网址:【https://colab.research.google.com/#create=true】T2&language = r,或者这个短网址【https://colab.to/r】T4
访问 URL 后,您将被带到一个新的 Colab 笔记本,默认标题为 Unitled.ipynb 。
乍一看,使用 Python 和 R 运行时的笔记本没有区别。然而,如果我们转到“运行时”设置,并选择“更改运行时类型”,我们将得到一个对话框,确认我们已经在 R 运行时。
作者、运行时->更改运行时类型的图像
您还可以通过尝试将您的驱动器安装到笔记本上来确认您处于 R 运行时环境中。这样做,你会得到这样一个不幸的消息:
作者图片,啊哦,我们不能安装我们的谷歌驱动器!
消息*“挂载您的 Google Drive 仅在托管 Python 运行时上可用。”*明确表示你不是在 Python 运行时。
恭喜你,你现在已经成功地在 Colab 中运行 R 了。可以通过输入R.version.string
打印出 R 版本来查看 R 版本。
这里,已经有几个对数据处理和数据可视化有用的包。可以通过运行print(installed.packages())
来检查。
如果你在安装软件包时遇到问题,这篇文章可能会帮助你:
一些限制以及如何克服其中一些限制
towardsdatascience.com](/how-to-install-packages-in-r-google-colab-423e8928cd2e)
如何在 Colab R 运行时挂载 Google Drive
这应该很容易做到。我们只需要安装“googledrive”包并执行认证过程。
install.packages("googledrive")
library("googledrive")
安装包之后,我们需要对 googledrive 包进行认证和授权。您可以在此处阅读软件包文档:
大多数函数都以前缀 drive_ 开头。自动完成是你的朋友。目标是让驾驶人员感觉…
googledrive.tidyverse.org](https://googledrive.tidyverse.org/)
# authorize google drivedrive_auth(
email = gargle::[gargle_oauth_email](https://gargle.r-lib.org/reference/gargle_options.html)(),
path = NULL,
scopes = "https://www.googleapis.com/auth/drive",
cache = gargle::[gargle_oauth_cache](https://gargle.r-lib.org/reference/gargle_options.html)(),
use_oob = gargle::[gargle_oob_default](https://gargle.r-lib.org/reference/gargle_options.html)(),
token = NULL
)
不幸的是,在尝试认证时,过程并不顺利。相反,我们面对的是这样一条错误消息:
图片作者,错误:无法获得谷歌证书。
显然,错误的发生是因为 httr 包中的交互函数无法执行。
这里有一个我们可以使用的变通办法,由 jobdiogene 的提供:https://gist . github . com/jobdiogenes/235620928 c84 e 604 C6 e 56211 CCF 681 f 0
# Check if is running in Colab and redefine is_interactive()
if (file.exists("/usr/local/lib/python3.6/dist-packages/google/colab/_ipython.py")) {
install.packages("R.utils")
library("R.utils")
library("httr")
my_check <- function() {return(TRUE)}
reassignInPackage("is_interactive", pkgName = "httr", my_check)
options(rlang_interactive=TRUE)
}
运行完那行代码后,我们可以再次尝试验证 Google Drive,现在它可以工作了!
drive_auth(use_oob = TRUE, cache = TRUE)
按作者分类的图像,交互式验证对话框
您需要点击链接并授予包访问您的 Google Drive 的权限。在此之后,您应该能够将授权代码粘贴到代码字段中。
图片由作者提供,授予许可
如何在 Colab R 运行时使用 BigQuery
对于业务人员,或者更习惯使用 R 的研究人员,也许我们需要从公司拥有的 BigQuery 或公开可用的数据集检索数据。
现在我们有了解决方法,授权 BigQuery 并从那里检索数据就很简单了:
install.packages("bigrquery")
library("bigrquery")
bq_auth(use_oob = TRUE, cache = FALSE)
使用自定义查询从 BigQuery 提取数据:
# Store the project id
projectid = "your-project-id"# Set the query
sql <- "SELECT * FROM your_table"# Run the query
project_query <- bq_project_query(projectid, sql, use_legacy_sql = FALSE)# Download result to dataframe
df <- bq_table_download(project_query)
结论
这是我认为我能为数据社区做出的贡献。正如我前面提到的,除了 Kaggle 和 RStudio Cloud 之外,Google Colab 为我们提供了学习或使用 R 的另一种选择。它们都是很好的平台,尤其是用于学习的时候;可以缩短初始设置(下载和安装 R,以及安装包)的时间。尽管在 Google Colab 中使用 R 的方式有点混乱,并且还没有与 Python 运行时相同的服务,但最终,它仍然工作得很好。
感谢阅读!
如果您有任何问题,请拨打 Showwcase 联系我!
如何使用 R Shiny 进行 EDA 和预测
奥比·奥尼耶德在 Unsplash 上拍摄的照片
R Shiny 分析、探索和预测自行车共享注册的简单指南
本文的目的是提供一个简单的指南,介绍如何开发一个出色的应用程序来分析、探索和预测数据集中的变量。
文章的第一部分涵盖了 R 闪亮的基础知识,比如对其功能的解释。此外,我将开发一个交互式图表形式的自行车共享数据的探索性数据分析。然后,我将创建一个预测模型,通过考虑天气条件和一年中的特定日子来帮助应用程序的用户预测系统中自行车注册的总数。
此外,我将在数据集包含的信息的上下文中描述要获取的数据。为了使 web 应用程序有一个目的,在数据理解部分,我将创建几个业务问题,我将通过这些问题来构建 R Shiny。
然后,通过使用 R,我将按照正确的格式排列数据,以构建机器学习模型和闪亮的应用程序。最后,我将展示代码并解释如何创建一个 R Shiny 应用程序的步骤。
内容
- 什么是 R 闪亮?
- 数据理解
- 数据准备
- 建模
- 埃达在 R 闪亮
- R 闪亮中的预测
什么是 R 闪亮?
R Shiny 是一个 R 包,它能够直接从 R 构建交互式 web 页面应用程序,而无需使用任何 web 应用程序语言,如 HTML、CSS 或 JavaScript 知识。
Shiny 的一个重要特性是,这些应用程序在某种程度上是“活的”,因为网页的输出会随着用户修改输入而改变,而无需重新加载浏览器。
Shiny 包含两个基本参数,UI 和服务器。用户界面(UI)包含描述页面布局的所有文本代码、任何附加文本、图像和我们想要包含的其他 HTML 元素,以便用户可以进行交互并理解如何使用网页。另一方面,服务器是闪亮应用程序的后端。该参数创建一个 web 服务器,专门用于在受控环境中托管闪亮的应用程序。
数据理解
用于开发 R Shiny 应用程序的数据集名为 自行车共享数据集 (具体来说就是“hour.csv”文件),取自 UCI 机器学习资源库。
我收集的数据来自名为“ Capital Bikeshare ”的自行车共享系统。该系统由位于 DC 华盛顿州六个不同辖区的一组自行车组成。自行车被锁在停靠站的整个网络中,供用户进行日常运输。用户可以通过应用程序解锁自行车,并在完成骑行后,将它们归还到任何其他可用的坞站。
该数据集包含 2011 年至 2012 年间每小时的自行车注册数,考虑了天气条件和季节信息。它包含 16 个属性和 17,379 个观察值,其中每一行数据代表从 2011 年 1 月 1 日开始的一天中的一个特定小时;直到 2012 年 12 月 31 日。
共有 9 个分类变量,如下所示:
- 日期:日期
- 季节:季节(1 =冬天,2 =春天,3 =夏天,4 =秋天)
- 年:年(0 = 2011 年,1 = 2012 年)
- 月:月(1 至 12)
- 小时:小时(0 到 23)
- 假日:天气日是否为假日(0 =否,1 =是)
- 工作日:一周中的某一天
- 工作日:天气日是否为工作日(如果该日既不是周末也不是节假日,则为 1,否则为 0)
- 天气状况(1 =晴朗,少云,部分多云,部分多云;2 =薄雾+多云,薄雾+碎云,薄雾+少云,薄雾;3 =小雪、小雨+雷雨+散云、小雨+散云;4 =暴雨+冰托盘+雷暴+薄雾、雪+雾)
此外,数据有 7 个数值变量:
- temp:以摄氏度为单位的标准化温度(这些值是通过(t-t_min)/(t_max-t_min),t_min=-8,t_max=+39 得出的)
- atemp:以摄氏度为单位的标准化感觉温度(该值通过(t-t_min)/(t_max-t_min)得出,t_min=-16,t_max=+50)
- 嗡嗡声:标准化湿度(数值分为 100(最大))
- 风速:标准化风速(数值分为 67(最大值)
- 临时:特定小时内使用自行车共享系统的临时用户数
- 已注册:特定小时内注册使用自行车共享系统的新用户数
- 计数:特定小时内租赁自行车总数(包括临时自行车和注册自行车)
商业问题
一旦我理解了这些数据,我就开发了一些我将在本文中回答的业务问题,以展示如何在现实世界中使用 R Shiny 应用程序。
- 数据集中新注册和临时注册的数量是否有显著差异?
- 在这两年中,骑自行车时最主要的天气条件是什么?
- 2012 年,自行车共享系统的新用户注册数量最多的月份是哪个月?
- 在 2012 年的“良好”天气条件下,哪个季节的临时用户和新用户注册数量最多?
- 该公司希望预测 2020 年 5 月 14 日(工作日)下午 3 点的自行车注册数量;提供以下天气信息:
- 将会有 35%的湿度。
- 温度 17 摄氏度,感觉温度 15 摄氏度。
- 每小时 10 英里的风速。
- 和“晴朗”天气类型。
数据准备
为了将数据以正确的格式输入到 R Shiny 应用程序中,首先,我准备了数据。为此,我将数据集加载到 RStudio 中,并检查每个属性的数据类型。
## Bike-sharing initial analysis
#Import the dataset
data <- read.csv('hour.csv')[,-1]
str(data)
有必要注意数据集的第一列是行索引,它不包含任何预测值。因此,我决定加载数据,排除原始数据集的第一列。
来自 str() 函数的结果
现在,一旦加载了变量,检查它们拥有正确的数据类型是绝对重要的。可视化结果,我们可以看到九个分类变量中的八个具有不正确的数据类型。为此,我将数据类型从 int (整数)改为 factor 。此外,我将编号值更改为它们各自的类别名称,以使它们的操作更容易理解。
有必要提及的是,我遵循了一个不同的标准来标记天气状况。通过分析天气的每一个输出,我决定把它们标上从“好”到“非常坏”的等级;其中 1 代表好天气,4 代表非常糟糕的天气。
#Data preparation
#Arranging values and changing the data type
data$yr <- as.factor(ifelse(data$yr == 0, '2011', '2012'))data$mnth <- as.factor(months(as.Date(data$dteday),
abbreviate = TRUE))data$hr <- factor(data$hr)data$weekday <- as.factor(weekdays(as.Date(data$dteday)))data$season <- as.factor(ifelse(data$season == 1, 'Spring',
ifelse(data$season == 2, 'Summer',
ifelse(data$season == 3,
'Fall', 'Winter'))))data$weathersit <- as.factor(ifelse(data$weathersit == 1, 'Good',
ifelse(data$weathersit == 2,
'Fair',
ifelse(data$weathersit ==
3, 'Bad',
'Very Bad'))))data$holiday<-as.factor(ifelse(data$holiday == 0, 'No', 'Yes'))data$workingday<-as.factor(ifelse(data$workingday == 0, 'No',
'Yes'))
此外,我继续将“注册”和“cnt”列分别更改为“新”和“总计”。
这种变化不是必需的,但它将允许我区分新的和注册总数。
#Changing columns names
names(data)[names(data) == "registered"] <- "new"
names(data)[names(data) == "cnt"] <- "total"
最后,对于数据准备的最后一步,我将变量“temp”、“atemp”、“hum”和“windspeed”的值反规格化;以便以后我可以在探索性数据分析和预测模型中分析真实的观察结果。
#Denormalizing the values
#Temperature
for (i in 1:nrow(data)){
tn = data[i, 10]
t = (tn * (39 - (-8))) + (-8)
data[i, 10] <- t
} #Feeling temperature
for (i in 1:nrow(data)){
tn = data[i, 11]
t = (tn * (50 - (-16))) + (-16)
data[i, 11] <- t
} #Humidity
data$hum <- data$hum * 100 #Wind speed
data$windspeed <- data$windspeed * 67
对于最终的安排,我删除了数据集的第一列,因为它对于研究来说并不重要。一旦我有了正确类型的所有变量和所需格式的所有值,我就用当前排列的数据编写一个新文件。
此外,我将使用这个新文件来构建 R Shiny 应用程序的图形。
#Write the new file
data <- data[-1]
write.csv(data, "bike_sharing.csv", row.names = FALSE)
建模
对于该模型,我想预测在考虑时间框架(月、小时和星期几)和天气条件的情况下,一天中可能发生的注册总数。对于这个问题,第一步是删除不属于模型的列。
“季节”和“工作日”列被删除,因为变量“月份”和“工作日”可以提供相同的信息。通过指示月份,我们知道一年中的哪个季节相对应。此外,通过提供关于一周中某一天的信息,我们可以确定这一天是否是工作日。
由于预测模型承认天气状况和某一天的特定信息,可变年份不提供模型所需的任何基本信息。对于这个问题,我从数据框架中删除了变量“yr”。同样,模型中不包括列“casual”和“new ”,因为模型的目的是预测注册总数。
#Modeling
#Dropping columns
data <- data[c(-1,-2,-7,-13,-14)]
拆分数据
既然数据已经为建模做好了准备,我继续将数据分成训练集和测试集。此外,为了将数据用于 R Shiny 应用程序,我将这些数据集保存到一个新文件中。我使用了 0.8 的分割比率,这意味着训练数据将包含总观察值的 80%,而测试将包含剩余的 20%。
#Splitting data
library(caTools)set.seed(123)
split = sample.split(data$total, SplitRatio = 0.8)
train_set = subset(data, split == TRUE)
test_set = subset(data, split == FALSE) #Write new files for the train and test sets
write.csv(train_set, "bike_train.csv", row.names = FALSE)
write.csv(test_set, "bike_test.csv", row.names = FALSE)
模型
此外,我继续选择模型进行预测。由于因变量是数字(总注册数),这意味着我们正在进行回归任务。为此,我预先选择了多重线性回归、决策树和随机森林模型来预测因变量的结果。
下一步,我用训练数据创建了回归模型。然后,我通过计算平均绝对误差(MAE)和均方根误差(RMSE)来评估它的性能。
#Multilinear regression
multi = lm(formula = total ~ ., data = train_set) #Predicting the test values
y_pred_m = predict(multi, newdata = test_set) #Performance metrics
library(Metrics)mae_m = mae(test_set[[10]], y_pred_m)
rmse_m = rmse(test_set[[10]], y_pred_m)
mae_m
rmse_m
多重线性回归梅伊和 RMSE 结果
#Decision tree
library(rpart)dt = rpart(formula = total ~ ., data = train_set,
control = rpart.control(minsplit = 3)) #Predicting the test values
y_pred_dt = predict(dt, newdata = test_set) #Performance metrics
mae_dt = mae(test_set[[10]], y_pred_dt)
rmse_dt = rmse(test_set[[10]], y_pred_dt)
mae_dt
rmse_dt
决策树回归梅和 RMSE 结果
#Random forest
library(randomForest)set.seed(123)
rf = randomForest(formula = total ~ ., data = train_set,
ntree = 100) #Predicting the test values
y_pred_rf = predict(rf, newdata = test_set) #Performance metrics
mae_rf = mae(test_set[[10]], y_pred_rf)
rmse_rf = rmse(test_set[[10]], y_pred_rf)
mae_rf
rmse_rf
随机森林回归梅和 RMSE 结果
一旦我有了所有模型的性能指标,我就继续分析它们,以最终选择最佳模型。众所周知,平均绝对误差(MAE)和均方根误差(RMSE)是衡量回归模型准确性的两个最常见的指标。
由于 MAE 提供预测误差的平均值,因此最好选择 MAE 值较小的模型。换句话说,在 MAE 较低的情况下,预测中的误差幅度很小,使得预测更接近真实值。根据这些标准,我选择了随机森林模型,它的 MAE 等于 47.11。
此外,我继续分析 RMSE。该指标还通过计算预测值和实际观测值之间的平均平方差的平方根来测量误差的平均大小,这意味着它会对较大的误差给予较高的权重。换句话说,使用较小的 RMSE,我们可以在模型中捕获较少的错误。也就是说,随机森林是正确的选择。此外,随机森林的 MAE 和 RMSE 之间的差异很小,这意味着个体误差的方差较低。
现在我知道了随机森林模型是最好的模型,需要将该模型保存在一个文件中,以便在 Shiny 应用程序中使用。
#Saving the model
saveRDS(rf, file = "./rf.rda")
埃达在 R 闪亮
在项目的这一步,我构建了一个 R Shiny 应用程序,可以在其中对数字和分类自变量进行单变量分析。此外,我开发了一个交互式仪表板来回答本文开头提出的业务问题。
在一个新的 R 文档中,我开始创建 R 闪亮的应用程序。首先,我加载了在整个闪亮应用程序和数据集中使用的必要库。
#Load libraries
library(shiny)
library(shinydashboard)
library(ggplot2)
library(dplyr)#Importing datasets
bike <- read.csv('bike_sharing.csv')
bike$yr <- as.factor(bike$yr)
bike$mnth <- factor(bike$mnth, levels = c('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
bike$weekday <- factor(bike$weekday, levels = c('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'))
bike$season <- factor(bike$season, levels = c('Spring', 'Summer', 'Fall', 'Winter'))
r 闪亮的 UI
首先,我创建了 web 页面(UI ),它将显示探索性数据分析的所有信息和可视化。
UI 将是一个变量,包含关于元素的信息,如标题、侧栏和仪表板的主体。要用所有必要的组件构建一个新的仪表板页面,请遵循下面的代码。
ui <- dashboardPage(dashboardHeader(),
dashboardSidebar(),
dashboardBody())
此外,我继续设计标题,创建侧边栏选项卡,并指明正文信息。
为了更好地理解代码,我将把它分成几个独立的部分。但是,有必要知道,为了让应用程序正常工作,我们必须一起运行所有的部分。
对于仪表板标题,我指定了闪亮应用程序的标题名称,并安排了标题显示的空间宽度。
#R Shiny ui
ui <- dashboardPage(
#Dashboard title
dashboardHeader(title = 'BIKE SHARING EXPLORER',
titleWidth = 290),
然后,我定义了侧边栏布局,设置了侧边栏的宽度。然后,用 sidebarMenu() 函数,我指定了侧边栏菜单的标签数量和标签名称。为了设置选项卡,我使用了 menuItem() 函数,其中我提供了选项卡的实际名称(应用程序中显示的名称)、引用选项卡名称(用于在整个代码中调用选项卡的别名),并定义了我想要附加到实际名称的图标或图形。
对于 EDA,我创建了两个名为 Plots 和 Dashboard 的选项卡。在第一个选项卡中,我显示了所有变量的单变量分析。另一个选项卡显示特定变量的双变量分析,以回答业务问题。
#Sidebar layout
dashboardSidebar(width = 290,
sidebarMenu(menuItem("Plots", tabName = "plots", icon = icon('poll')),
menuItem("Dashboard", tabName = "dash", icon = icon('tachometer-alt')))),
此外,在仪表板正文中,我描述了创建的每个选项卡的内容和布局。
首先,我使用了一个 CSS 组件,它是一种可以在 HTML 文档中使用的样式语言,将标题更改为粗体。此外,在 *tabItems(),*中,我设置了上面创建的每个选项卡的内容。使用 tabItem() 函数,我定义了引用标签名,然后描述了它将包含的不同元素。
一旦我确定了引用标签名(’ plots '),我就通过使用 box() 函数找到四个不同的空格来显示信息。使用这个函数,我定义了框的样式(状态)、标题、添加可选的页脚、控件和绘图输出。
在这段代码中,首先,我定义了四个盒子。其中两个框包含一个小部件,另外两个框显示稍后在服务器中创建的图。使用的控件小部件是 selectInput(),,这是一个下拉菜单,有不同的选项可供选择。在同一个函数中,我描述了小部件的引用名、实际名称以及将出现在菜单上的选项列表。另一方面,我用了最后两个方框来揭示剧情的输出。为此,我定义了函数 plotOutput() 并指明了它的引用名。
#Tabs layout
dashboardBody(tags$head(tags$style(HTML('.main-header .logo {font-weight: bold;}'))),
tabItems(
#Plots tab content
tabItem('plots',
#Histogram filter
box(status = 'primary', title = 'Filter for the histogram plot',
selectInput('num', "Numerical variables:", c('Temperature', 'Feeling temperature', 'Humidity', 'Wind speed', 'Casual', 'New', 'Total')),
footer = 'Histogram plot for numerical variables'),
#Frecuency plot filter
box(status = 'primary', title = 'Filter for the frequency plot',
selectInput('cat', 'Categorical variables:', c('Season', 'Year', 'Month', 'Hour', 'Holiday', 'Weekday', 'Working day', 'Weather')),
footer = 'Frequency plot for categorical variables'),
#Boxes to display the plots
box(plotOutput('histPlot')),
box(plotOutput('freqPlot'))),
对于下一个选项卡项目(“破折号”),我使用了与上面代码类似的设计。选项卡的布局包含三个框。第一个框拥有过滤器,其余的框拥有绘图空间。
在过滤框中,我使用了 splitLayout() 函数将框的布局分成三个不同的列。对于这些过滤器,我使用了一个名为 *radioButtons(),*的控件小部件,其中我指出了引用名、实际名称以及我们将在应用程序中使用的选项列表。
然后,在仪表板的其他框中,我指出了它的内容,比如图表,并声明了引用名称。同样,对于最后一个框,我输入了函数 column() ,在这里我指出了它的宽度。此外,我创建了两个不同的列,通过使用 helpText() 函数,我在其中描述了每个天气条件过滤器的含义。
#Dashboard tab content
tabItem('dash',
#Dashboard filters
box(title = 'Filters', status = 'primary', width = 12,
splitLayout(cellWidths = c('4%', '42%', '40%'),
div(),
radioButtons( 'year', 'Year:', c('2011 and 2012', '2011', '2012')),
radioButtons( 'regis', 'Registrations:', c('Total', 'New', 'Casual')),
radioButtons( 'weather', 'Weather choice:', c('All', 'Good', 'Fair', 'Bad', 'Very Bad')))),
#Boxes to display the plots
box(plotOutput('linePlot')),
box(plotOutput('barPlot'),
height = 550,
h4('Weather interpretation:'),
column(6,
helpText('- Good: clear, few clouds, partly cloudy.'),
helpText('- Fair: mist, cloudy, broken clouds.')),
helpText('- Bad: light snow, light rain, thunderstorm, scattered clouds.'),
helpText('- Very Bad: heavy rain, ice pallets, thunderstorm, mist, snow, fog.')))))
)
最后,我创建了一个空服务器来运行代码,并可视化这个闪亮应用程序的进度。
# R Shiny server
server <- shinyServer(function(input, output) {})shinyApp(ui, server)
绘图选项卡
仪表板选项卡
由于我在服务器上没有输出,应用程序将显示空白空间,稍后我将在那里放置绘图。
r 闪亮服务器
此外,在服务器变量中,我继续创建为分析而构建的图,以回答业务问题。
我创建的第一个图是直方图。通过使用输出$histPlot 向量,我访问了 UI 中指示的直方图绘图框,我继续将它分配给 renderPlot({}) 反应函数。这个函数将从 UI 中获取数据,并将其实现到服务器中。
而且,我创建了一个名为“num_val”的新变量。此变量将存储数据集中引用数值变量筛选器的列的名称。现在,有了这个新变量,我开始构建直方图。
# R Shiny server
server <- shinyServer(function(input, output) {
#Univariate analysis
output$histPlot <- renderPlot({ #Column name variable
num_val = ifelse(input$num == 'Temperature', 'temp',
ifelse(input$num == 'Feeling temperature', 'atemp',
ifelse(input$num == 'Humidity', 'hum',
ifelse(input$num == 'Wind speed', 'windspeed',
ifelse(input$num == 'Casual', 'casual',
ifelse(input$num == 'New', 'new', 'total'))))))
#Histogram plot
ggplot(data = bike, aes(x = bike[[num_val]]))+
geom_histogram(stat = "bin", fill = 'steelblue3',
color = 'lightgrey')+
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 14),
plot.title = element_text(size = 16, face = 'bold'))+
labs(title = sprintf('Histogram plot of the variable %s', num_val),
x = sprintf('%s', input$num),y = 'Frequency')+
stat_bin(geom = 'text',
aes(label = ifelse(..count.. == max(..count..), as.character(max(..count..)), '')),
vjust = -0.6)
})
接下来,我绘制了分类变量的频率图。执行与前面相同的步骤,我调用了 output$freqPlot 向量来使用 renderPlot({}) 反应函数绘制图形。同样,我生成了一个新变量来存储与过滤器上选择的值相关的数据集的列名。然后,使用新的变量,我建立了频率图。
output$freqPlot <- renderPlot({#Column name variable
cat_val = ifelse(input$cat == 'Season', 'season',
ifelse(input$cat == 'Year', 'yr',
ifelse(input$cat == 'Month', 'mnth',
ifelse(input$cat == 'Hour', 'hr',
ifelse(input$cat == 'Holiday', 'holiday',
ifelse(input$cat == 'Weekday', 'weekday',
ifelse(input$cat == 'Working day', 'workingday', 'weathersit')))))))
#Frecuency plot
ggplot(data = bike, aes(x = bike[[cat_val]]))+
geom_bar(stat = 'count', fill = 'mediumseagreen',
width = 0.5)+
stat_count(geom = 'text', size = 4,
aes(label = ..count..),
position = position_stack(vjust = 1.03))+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_text(size = 12),
axis.title = element_text(size = 14),
plot.title = element_text(size = 16, face="bold"))+
labs(title = sprintf('Frecuency plot of the variable %s', cat_val),
x = sprintf('%s', input$cat), y = 'Count')
})
现在,我继续为 dashboard 选项卡构建图表。为了回答第三个业务问题,我创建了一个线形图来显示每月的注册数量。此外,我将能够按年份和注册类型过滤图表。
首先,我指出了输出向量和反应函数。然后,我开发了一个表,通过遵循特定的条件,该表将包含绘图中使用的必要列。
后来,考虑到用户在过滤器上选择的注册类型,我生成了一个新变量(“regis_val”)来存储数据集的列名。最后,我建立了线条图。
#Dashboard analysis
output$linePlot <- renderPlot({
if(input$year != '2011 and 2012'){
#Creating a table filter by year for the line plot
counts <- bike %>% group_by(mnth) %>% filter(yr == input$year) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))} else{
#Creating a table for the line plot
counts <- bike %>% group_by(mnth) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))}#Column name variable
regis_val = ifelse(input$regis == 'Total', 'total',
ifelse(input$regis == 'New', 'new','casual'))
#Line plot
ggplot(counts, aes(x = mnth, y = counts[[regis_val]],
group = 1))+
geom_line(size = 1.25)+
geom_point(size = 2.25,
color = ifelse(counts[[regis_val]] == max(counts[[regis_val]]), 'red','black'))+
labs(title = sprintf('%s bike sharing registrations by month', input$regis),
subtitle = sprintf('Throughout the year %s \nMaximum value for %s registrations: %s \nTotal amount of %s registrations: %s', input$year, regis_val, max(counts[[regis_val]]), regis_val, sum(counts[[regis_val]])),
x = 'Month',
y = sprintf('Count of %s registrations', regis_val))+
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 14),
plot.title = element_text(size = 16, face = 'bold'),
plot.subtitle = element_text(size = 14))+
ylim(NA, max(counts[[regis_val]])+7000)+
geom_text(aes(label = ifelse(counts[[regis_val]] == max(counts[[regis_val]]), as.character(counts[[regis_val]]),'')),
col ='red',hjust = 0.5, vjust = -0.7) })
此外,我继续开发条形图来回答业务问题 4。我遵循了与上面代码相似的步骤。首先,我创建了一些限制来创建用于不同过滤器的表,该表将考虑年份和天气条件。然后,我创建了一个变量,它存储了在过滤器上选择的注册类型的列名。最后,构建条形频率图,按年份、注册类型和天气条件显示注册计数。
output$barPlot <- renderPlot({
if(input$year != '2011 and 2012'){
if(input$weather != 'All'){
#Creating a table filter by year and weathersit for the bar plot
weather <- bike %>% group_by(season, weathersit) %>% filter(yr == input$year) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))
weather <- weather %>% filter(weathersit == input$weather)} else{
#Creating a table filter by year for the bar plot
weather <- bike %>% group_by(season, weathersit) %>% filter(yr == input$year) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))
}
} else{
if(input$weather != 'All'){
#Creating a table filter by weathersit for the bar plot
weather <- bike %>% group_by(season, weathersit) %>% filter(weathersit == input$weather) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))
} else{
#Creating a table for the bar plot
weather <- bike %>% group_by(season, weathersit) %>% summarise(new = sum(new), casual = sum(casual), total = sum(total))
}
}
#Column name variable
regis_val = ifelse(input$regis == 'Total', 'total',
ifelse(input$regis == 'New', 'new','casual'))
#Bar plot
ggplot(weather, aes(x = season, y = weather[[regis_val]],
fill = weathersit))+
geom_bar(stat = 'identity', position=position_dodge())+
geom_text(aes(label = weather[[regis_val]]),
vjust = -0.3, position = position_dodge(0.9),
size = 4)+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_text(size = 12),
axis.title = element_text(size = 14),
plot.title = element_text(size = 16, face = 'bold'),
plot.subtitle = element_text(size = 14),
legend.text = element_text(size = 12))+
labs(title = sprintf('%s bike sharing registrations by season and weather', input$regis),
subtitle = sprintf('Throughout the year %s', input$year),
x = 'Season',
y = sprintf(Count of %s registrations', regis_val))+
scale_fill_manual(values = c('Bad' = 'salmon2', 'Fair' = 'steelblue3', 'Good' = 'mediumseagreen', 'Very Bad' = 'tomato4'),
name = 'Weather')
})
现在我已经在服务器中创建了图表,我继续运行代码来可视化这个闪亮的应用程序。
带有图的图选项卡
带有绘图的仪表板选项卡
结论
最后,我继续通过分析展示业务问题的答案。
- 数据集中新注册和临时注册的数量是否有显著差异?
我继续展示图表来回答第一个问题。
新登记类型变量的直方图
可变临时登记类型的直方图
在分析“新”变量时,我指出,在整个数据集中,最少有 0 个新注册,最多大约有 875 个。另一方面,有一个最低的休闲注册 0 和粗略的最高 350。
正如我们所看到的,两个图都向右倾斜,这意味着每天记录的大多数注册分别低于新注册和临时注册类型的 250 和 100。
最后,为了回答第一个商业问题,我得出结论,新注册和临时注册的数量之间存在显著差异。该数据集显示,在 1500 多次观察中,用户每天进行的新注册不到 125 次。然而,在 1000 多次情况下,该系统每天捕获的临时登记不到 50 次。
换句话说,该系统在 2011 年和 2012 年,比使用该系统的临时用户有更多的新用户注册到首都自行车共享。造成这种现象的原因之一是系统的启动。自 2010 年启动该业务以来,在随后的几年里,新用户仍在注册。
- 在这两年中,骑自行车时最主要的天气条件是什么?
为了回答这个问题,我展示了所需的情节。
变量 weathersit 的频率图
通过观察图表,我得出结论,2011 年和 2012 年最常见的天气状况属于“良好”类型。该图显示,数据集中的 11,413 个观测值捕捉到了“好”天气,这意味着这两年的天气大多是晴朗的,很少有云,或部分多云。
- 2012 年,自行车共享系统的新用户注册数量最多的月份是哪个月?
为了回答这个问题,我继续点击 dashboard 选项卡并显示下面的图。
2012 年新注册数量的时间序列图
一旦我按年份和注册类型过滤了图,我就获得了上面显示的结果。我们可以想象,新用户注册量最高的月份是在 9 月。新增用户约为 170,000 的原因之一是,9 月是秋季的开始,气温正在下降。换句话说,热量更少,天气更适合人们骑自行车上下班。
- 2012 年,在“良好”天气条件下,哪个季节的休闲和新注册人数最多?
对于下面的问题,我继续从仪表板选项卡显示两个不同的图。
根据年份和天气条件过滤的绘图季节与临时注册数
根据年份和天气条件筛选的绘图季节与新注册数
正如我们从之前的分析中所知,自行车共享系统中的新注册量远高于临时注册量。对于这个问题,新的注册地块将显示更高的注册用户数,而不管季节。
此外,我指出,在这两种类型的注册中,最高数量的注册发生在秋季,其次是夏季。正如我之前提到的,秋季是人们骑自行车上下班的理想天气。此外,夏季也呈现出相当高的注册数量,因为这是人们度假和使用自行车系统共享进行观光和旅游的季节。
R 闪亮中的预测
为了回答最后一个问题,我开始部署模型。在这一步中,我在 R Shiny 应用程序中创建了一个新的选项卡。在该选项卡中,用户将能够输入每个变量的单个值,并获得注册总数和预测结果的值范围。
为了更好地理解代码,我将类型字符设置为“bold ”,以表示添加到 R Shiny 中的新文本。
在闪亮的应用程序文档中,我继续添加新的库并导入预测所需的数据集。训练和测试数据都被引入到应用程序中以安排分类级别。此外,我加载了随机森林模型来收集平均绝对误差值。
#Load libraries
library(shiny)
library(shinydashboard)
library(ggplot2)
library(dplyr)
**library(randomForest)
library(Metrics)**#Importing datasets
bike <- read.csv('bike_sharing.csv')
bike$yr <- as.factor(bike$yr)
bike$mnth <- factor(bike$mnth, levels = c('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
bike$weekday <- factor(bike$weekday, levels = c('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'))
bike$season <- factor(bike$season, levels = c('Spring', 'Summer', 'Fall', 'Winter'))**train_set <- read.csv('bike_train.csv')
train_set$hr <- as.factor(train_set$hr)****test_set <- read.csv('bike_test.csv')
test_set$hr <- as.factor(test_set$hr)****levels(test_set$mnth) <- levels(train_set$mnth)
levels(test_set$hr) <- levels(train_set$hr)
levels(test_set$holiday) <- levels(train_set$holiday)
levels(test_set$weekday) <- levels(train_set$weekday)
levels(test_set$weathersit) <- levels(train_set$weathersit)****#Importing model
model_rf <- readRDS(file = './rf.rda')
y_pred = predict(model_rf, newdata = test_set)
mae_rf = mae(test_set[[10]], y_pred)
rmse_rf = rmse(test_set[[10]], y_pred)**
r 闪亮的 UI
现在,我在 UI 中加入了新的文本代码。我在 dashboardSidebar() 和 dashboardBody() 函数的末尾添加了新的代码行。
对于侧边栏,我添加了一个名为“pred”的新菜单项,表示闪亮应用程序中的新标签。
#R Shiny ui
ui <- dashboardPage(
#Dashboard title
dashboardHeader(title = 'BIKE SHARING EXPLORER', titleWidth = 290),
#Sidebar layout
dashboardSidebar(width = 290,
sidebarMenu(menuItem("Plots", tabName = "plots", icon = icon('poll')),
menuItem("Dashboard", tabName = "dash", icon = icon('tachometer-alt')),
**menuItem("Prediction", tabName = "pred", icon = icon('search'))**)),
然后,在仪表板正文中,我继续描述上面创建的新选项卡的内容。该选项卡有四个框。前两个框将包含控件小部件,用户可以在其中输入模型中每个变量的值。第一个框将包含所有的分类变量,其中我实现了四个*选择输入()和一个单选按钮()*小部件。
第二个框包含数字变量。为了输入湿度值,我使用了 sliderInput() 小部件从 0%到 100%的范围内选择湿度的百分比。这个小部件接受引用名称、实际名称、最小值、最大值和默认值作为参数。此外,对于剩余的变量,我使用了 numericInput() ,用户可以在这里输入变量的值。这个小部件的参数是引用名称、实际名称和默认值。
此外,我构建了下面的框来显示单个预测的结果。为了显示预测的结果和预测值的范围,我使用了一个名为 verbatimTextOutput() 的控件小部件,在这里我定义了引用名并将其标记为值的占位符。此外,我添加了一个带有 actionButton() 小部件的按钮,以便在用户输入所有值后计算结果。对于这个控件小部件,我将引用名称、实际名称和图标标识为参数。
最后,最后一个框的功能是传递信息,解释我选择的模型。
#Tabs layout
dashboardBody(tags$head(tags$style(HTML('.main-header .logo {font-weight: bold;}'))),
#Plots tab content
tabItems(tabItem('plots',
#Histogram filter
box(status = 'primary', title = 'Filter for the histogram plot',
selectInput('num', "Numerical variables:", c('Temperature', 'Feeling temperature', 'Humidity', 'Wind speed', 'Casual', 'New', 'Total')),
footer = 'Histogram plot for numerical variables'),
#Frecuency plot filter
box(status = 'primary', title = 'Filter for the frequency plot',
selectInput('cat', 'Categorical variables:', c('Season', 'Year', 'Month', 'Hour', 'Holiday', 'Weekday', 'Working day', 'Weather')),
footer = 'Frequency plot for categorical variables'),
#Boxes to display the plots
box(plotOutput('histPlot')),
box(plotOutput('freqPlot'))), #Dashboard tab content
tabItem('dash',
#Dashboard filters
box(title = 'Filters',
status = 'primary', width = 12,
splitLayout(cellWidths = c('4%', '42%', '40%'),
div(),
radioButtons( 'year', 'Year:', c('2011 and 2012', '2011', '2012')),
radioButtons( 'regis', 'Registrations:', c('Total', 'New', 'Casual')),
radioButtons( 'weather', 'Weather choice:', c('All', 'Good', 'Fair', 'Bad', 'Very Bad')))),
#Boxes to display the plots
box(plotOutput('linePlot')),
box(plotOutput('barPlot'),
height = 550,
h4('Weather interpretation:'),
column(6,
helpText('- Good: clear, few clouds, partly cloudy.'),
helpText('- Fair: mist, cloudy, broken clouds.')),
helpText('- Bad: light snow, light rain, thunderstorm, scattered clouds.'),
helpText('- Very Bad: heavy rain, ice pallets, thunderstorm, mist, snow, fog.'))),**#Prediction tab content
tabItem('pred',
#Filters for categorical variables
box(title = 'Categorical variables',
status = 'primary', width = 12,
splitLayout(
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
cellWidths = c('0%', '19%', '4%', '19%', '4%', '19%', '4%', '19%', '4%', '8%'),
selectInput( 'p_mnth', 'Month', c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul","Aug", "Sep", "Oct", "Nov", "Dec")),
div(),
selectInput('p_hr', 'Hour', c('0', '1', '2', '3', '4', '5', '6', '7', '8','9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23')),
div(),
selectInput( 'p_weekd', 'Weekday', c('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')),
div(),
selectInput( 'p_weather', 'Weather', c('Good', 'Fair', 'Bad', 'Very Bad')),
div(),
radioButtons( 'p_holid', 'Holiday', c('Yes', 'No')))),
#Filters for numeric variables
box(title = 'Numerical variables',
status = 'primary', width = 12,
splitLayout(cellWidths = c('22%', '4%','21%', '4%', '21%', '4%', '21%'),
sliderInput( 'p_hum', 'Humidity (%)', min = 0, max = 100, value = 0),
div(),
numericInput( 'p_temp', 'Temperature (Celsius)', 0),
div(),
numericInput( 'p_ftemp', 'Feeling temperature (Celsius)', 0),
div(),
numericInput( 'p_wind', 'Wind speed (mph)', 0))),
#Box to display the prediction results
box(title = 'Prediction result',
status = 'success',
solidHeader = TRUE,
width = 4, height = 260,
div(h5('Total number of registrations:')),
verbatimTextOutput("value", placeholder = TRUE),
div(h5('Range of number of registrations:')),
verbatimTextOutput("range", placeholder = TRUE),
actionButton('cal','Calculate', icon = icon('calculator'))),
#Box to display information about the model
box(title = 'Model explanation',
status = 'success',
width = 8, height = 260,
helpText('The following model will predict the total number of bikes rented on a specific day of the week, hour, and weather conditions.'),
helpText('The name of the dataset used to train the model is "Bike Sharing Dataset Data Set", taken from the UCI Machine Learning Repository website. The data contains 17,379 observations and 16 attributes related to time and weather conditions.'),
helpText(sprintf('The prediction is based on a random forest supervised machine learning model. Furthermore, the models deliver a mean absolute error (MAE) of %s total number of registrations, and a root mean squared error (RMSE) of %s total number of registrations.', round(mae_rf, digits = 0), round(rmse_rf, digits = 0)))))**
)
)
)
添加 UI 代码后,我运行应用程序来可视化布局。
带有默认值和模型说明的预测选项卡
r 闪亮服务器
接下来,我继续添加服务器文本代码,它将使用模型计算单个预测。
首先,对于单个预测结果,我定义了一个 reactiveValues() 函数,其中我设置了一个默认值 NULL。当用户按下“计算”按钮时,该值将做出反应。
接下来,我使用了 observeEvent() 函数来执行预测的计算。这个函数将在闪亮的应用程序后面执行计算,并在用户调用函数开头提到的按钮时显示结果(输入 c a l ∗ ) 。因为在结果和上面创建的反应值之间有一个链接,所以除非用户点击“计算”按钮,否则不会显示结果。现在,我继续调用 ∗ 输出 cal* )。因为在结果和上面创建的反应值之间有一个链接,所以除非用户点击“计算”按钮,否则不会显示结果。现在,我继续调用*输出 cal∗)。因为在结果和上面创建的反应值之间有一个链接,所以除非用户点击“计算”按钮,否则不会显示结果。现在,我继续调用∗输出value ,它是单个预测结果的占位符,通过使用函数 renderText({}) 在应用程序中显示结果。有必要提到的是,这个函数只提供字符串类型的结果。
最后,通过调用占位符显示范围结果(输出 r a n g e ∗ ) 使用函数 ∗ r e n d e r T e x t ( ) , ∗ 并调用函数中的活动按钮 ( ∗ 输入 range* )使用函数 *renderText({}),*并调用函数中的活动按钮(*输入 range∗)使用函数∗renderText(),∗并调用函数中的活动按钮(∗输入 cal);闪亮的应用程序将在指定位置显示范围结果。
此外,由于“单变量分析”和“仪表板分析”部分的代码有许多行文本,为了更好地理解,我决定用符号“…”代替它。
# R Shiny server
server <- shinyServer(function(input, output) {
#Univariate analysis
output$histPlot <- renderPlot({...})
output$freqPlot <- renderPlot({...}) #Dashboard analysis
output$linePlot <- renderPlot({...})
output$barPlot <- renderPlot({...})**#Prediction model
#React value when using the action button
a <- reactiveValues(result = NULL)
observeEvent(input$cal, {
#Copy of the test data without the dependent variable
test_pred <- test_set[-10]
#Dataframe for the single prediction
values = data.frame(mnth = input$p_mnth,
hr = input$p_hr,
weekday = input$p_weekd,
weathersit = input$p_weather,
holiday = input$p_holid,
hum = as.integer(input$p_hum),
temp = input$p_temp,
atemp = input$p_ftemp,
windspeed = input$p_wind)
#Include the values into the new data
test_pred <- rbind(test_pred,values)
#Single preiction using the randomforest model
a$result <- round(predict(model_rf,
newdata = test_pred[nrow(test_pred),]),
digits = 0)
})
output$value <- renderText({
#Display the prediction value
paste(a$result)
})
output$range <- renderText({
#Display the range of prediction value using the MAE value
input$cal
isolate(sprintf('(%s) - (%s)',
round(a$result - mae_rf, digits = 0),
round(a$result + mae_rf, digits = 0)))
})**
})
shinyApp(ui, server)
结论
此外,我继续使用应用程序来回答最后一个业务问题。
- 该公司希望预测某一天和天气条件下的自行车注册数量。
参数:
- 日期:2020 年 5 月 14 日星期四(是工作日),下午 3 点。
- 天气条件:35%的湿度,17 摄氏度的温度,15 摄氏度的感觉温度,10 英里/小时的风速,以及“晴朗”的天气类型。
最后,为了回答最后一个业务问题,我继续输入问题中显示的日期和天气值,然后单击“计算”按钮获得结果。
单一预测结果
从预测中获得的结果是该特定日期和天气条件下的注册总数为 228。此外,预测还揭示了预测值的变化范围。结果显示,该公司预计注册总数在 181 到 275 之间。
旁注
要找到所有的 R 代码和数据集,请访问我的 GitHub 库。另外,在我的 ShinnyApp 中可以找到 R shiny 应用。
如何有效使用随机种子
机器学习过程中经常被忽视的部分的最佳实践
建立预测模型是一个复杂的过程。你需要获得正确的数据,清理它,创建有用的特征,测试不同的算法,最后验证你的模型的性能。然而,这篇文章涵盖了模型构建过程中通常不会引起太多关注的一个方面:随机种子。
❓什么是随机种子?
随机种子用于确保结果是可重复的。换句话说,使用这个参数可以确保任何人重新运行您的代码都会得到完全相同的输出。在数据科学和其他领域,再现性是一个极其重要的概念。很多人已经写了很多关于这个话题的文章,所以我不会在这篇文章中进一步讨论。
根据您的具体项目,您甚至可能不需要随机种子。但是,有两个常见的任务会用到它们:
1.将数据分成训练集/验证集/测试集:随机种子确保每次运行代码时数据都以相同的方式划分
2.模型训练:诸如随机森林和梯度推进之类的算法是不确定的(对于给定的输入,输出并不总是相同的),因此需要随机种子参数来获得可重复的结果
除了再现性,随机种子对于基准测试结果也很重要。如果您正在测试一个算法的多个版本,那么所有版本使用相同的数据并且尽可能相似(除了您正在测试的参数之外)是非常重要的。
随机种子通常是如何设定的
尽管它们很重要,随机种子通常不需要太多的努力就能被设定。我对此感到内疚。我通常使用我正在工作的任何一天的日期(因此在 2020 年 3 月 1 日,我将使用 seed 20200301)。有的人每次都用同一个种子,有的人随机生成。
总的来说,随机种子通常被视为建模过程中的事后想法。这可能会有问题,因为正如我们将在接下来的几节中看到的,该参数的选择会显著影响结果。
🚢泰坦尼克号数据
现在,我将展示随机种子的选择会产生多大的影响。我将使用众所周知的泰坦尼克号数据集来做这件事(下载链接在下面)。
从这里开始!预测泰坦尼克号上的生存并熟悉 ML 基础知识
www.kaggle.com](https://www.kaggle.com/c/titanic/data)
以下代码和图是用 Python 创建的,但我在 r 中发现了类似的结果。与本文相关的完整代码可以在下面的 GitHub 资源库中找到:
[## jai-bans al/random-seed-blog-post
这个存储库包含支持关于随机种子最佳实践的博客文章的代码。这篇博文可以在这里找到…
github.com](https://github.com/jai-bansal/random-seed-blog-post)
首先,让我们看几行数据:
import pandas as pd
train_all = pd.read_csv('train.csv') # Show selected columns
train_all.drop(['PassengerId', 'Parch', 'Ticket', 'Embarked', 'Cabin'], axis = 1).head()
泰坦尼克号数据集样本
泰坦尼克号的数据已经被分成了训练集和测试集。该数据集的一个经典任务是预测乘客存活率(编码在Survived
列中)。测试数据没有附带Survived
列的标签,所以我将执行以下操作:
1.保留部分训练数据作为验证集
2.根据剩余的训练数据训练模型以预测存活率,并根据步骤 1 中创建的验证集评估该模型
拆分数据
让我们先来看看Survived
栏目的整体分布情况。
In [19]: train_all.Survived.value_counts() / train_all.shape[0]
Out[19]:
0 0.616162
1 0.383838
Name: Survived, dtype: float64
在建模时,我们希望我们的训练、验证和测试数据尽可能相似,这样我们的模型就可以在与评估数据相同的数据上进行训练。请注意,这并不意味着而不是这三个数据集应该重叠!他们不应该。但是我们希望每一份报告中的观察结果具有广泛的可比性。现在,我将使用不同的随机种子分割数据,并比较训练集和验证集的Survived
分布。
from sklearn.model_selection import train_test_split# Create data frames for dependent and independent variables
X = train_all.drop('Survived', axis = 1)
y = train_all.Survived # Split 1
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.2, random_state = 135153) In [41]: y_train.value_counts() / len(y_train)
Out[41]:
0 0.655899
1 0.344101
Name: Survived, dtype: float64 In [42]: y_val.value_counts() / len(y_val)
Out[42]:
0 0.458101
1 0.541899
Name: Survived, dtype: float64
在这种情况下,训练集中幸存者的比例远低于验证集中幸存者的比例。
# Split 2
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.2, random_state = 163035) In [44]: y_train.value_counts() / len(y_train)
Out[44]:
0 0.577247
1 0.422753
Name: Survived, dtype: float64 In [45]: y_val.value_counts() / len(y_val)
Out[45]:
0 0.77095
1 0.22905 Name: Survived, dtype: float64
这里,在训练集中幸存者的比例比在验证集中高得多。
完全公开,这些例子是我在循环通过 200K 随机种子后发现的最极端的例子。不管怎样,这些结果有几个问题。首先,在这两种情况下,训练集和验证集之间的存活率分布有很大不同。这可能会对模型训练产生负面影响。第二,这些输出彼此非常不同。如果像大多数人一样,任意设置一个随机种子,那么根据您的选择,最终的数据分割可能会有很大的不同。
我将在文章的最后讨论最佳实践。接下来,我想展示我测试的所有 20 万个随机种子的训练和验证Survival
分布是如何变化的。
一些数据拆分在训练集和验证集存活率%之间有很大差异。
约 23%的数据分割导致了训练集和验证集之间至少 5%的存活率差异。超过 1%的分裂导致至少 10%的存活率差异。最大存活百分比差异约为 20%。这里的要点是,使用任意随机种子会导致训练集和验证集分布之间的巨大差异。这些差异可能会在建模过程中产生意想不到的下游后果。
📈模特培训
上一节展示了随机种子如何影响数据分割。在这一节中,在之后,我使用不同的随机种子来训练一个模型,数据已经被分成训练集和验证集(下一节将详细介绍我是如何做到这一点的)。
提醒一下,我正在尝试预测Survived
列。我将构建一个随机森林分类模型。因为随机森林算法是不确定的,所以需要一个随机种子来实现可再现性。我将在下面展示模型准确性的结果,但是我发现使用 precision 和 recall 也有类似的结果。
首先,我将创建一个训练和验证集。
X = X[['Pclass', 'Sex', 'SibSp', 'Fare']] # These will be my predictors # The “Sex” variable is a string and needs to be one-hot encoded
X['gender_dummy'] = pd.get_dummies(X.Sex)['female']
X = X.drop(['Sex'], axis = 1) # Divide data into training and validation sets
# I’ll discuss exactly why I divide the data this way in the next section
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.2, random_state = 20200226, stratify = y)
现在,我将训练几个模型,并评估验证集的准确性。
# Model 1 from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score # Create and fit model
clf = RandomForestClassifier(n_estimators = 50, random_state = 11850)
clf = clf.fit(X_train, y_train)
preds = clf.predict(X_val) # Get predictions In [74]: round(accuracy_score(y_true = y_val, y_pred = preds), 3) Out[74]: 0.765 # Model 2# Create and fit model
clf = RandomForestClassifier(n_estimators = 50, random_state = 2298)
clf = clf.fit(X_train, y_train)
preds = clf.predict(X_val) # Get predictionsIn [78]: round(accuracy_score(y_true = y_val, y_pred = preds), 3)
Out[78]: 0.827
为了找到这些结果,我测试了 25K 个随机种子,但是准确度变化> 6%绝对值得注意!同样,这两个模型是相同的,除了随机种子。
下图显示了我测试的所有随机种子的模型精确度是如何变化的。
模型精度因随机种子而异。
虽然大多数模型达到了约 80%的准确率,但有相当数量的模型得分在 79%-82%之间,少数模型得分超出了该范围。根据具体的用例,这些差异大到足以产生影响。因此,在与利益相关者交流结果时,应考虑随机种子选择导致的模型性能差异。
最佳实践
既然我们已经看到了随机种子的选择会影响结果的几个方面,我想提出一些最佳实践。
对于数据分割,我认为应该使用分层样本,以便因变量(本文中的Survived
)在训练、验证和测试集中的比例相似。这将消除上述变化的存活率分布,并允许根据可比数据训练和评估模型。
train_test_split
函数可以用 1 个附加参数实现分层抽样。请注意,如果稍后根据具有不同因变量分布的数据评估模型,性能可能会与预期不同。然而,我认为按因变量分层仍然是分割数据的首选方式。
下面是分层抽样在代码中的样子。
# Overall distribution of “Survived” column
In [19]: train_all.Survived.value_counts() / train_all.shape[0]
Out[19]:
0 0.616162
1 0.383838
Name: Survived, dtype: float64 # Stratified sampling (see last argument)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.2, random_state = 20200226, stratify = y) In [10]: y_train.value_counts() / len(y_train)
Out[10]:
0 0.616573
1 0.383427
Name: Survived, dtype: float64 In [11]: y_val.value_counts() / len(y_val)
Out[11]:
0 0.614525
1 0.385475
Name: Survived, dtype: float64
使用stratify
参数,Survived
的比例在训练集和验证集中是相似的。我仍然使用随机种子,因为我仍然想要可重复的结果。然而,我认为在这种情况下,具体的随机种子值并不重要。
这解决了数据分割的最佳实践,但是模型训练呢?在测试不同的模型规格时,应该使用随机种子进行公平的比较,但我不认为特定的种子有太大的关系。
然而,在向利益相关者报告绩效指标之前,最终模型应该用 2-3 个额外的种子进行训练和评估,以了解结果中可能的差异。这种做法可以更准确地传达模型性能。对于在生产环境中运行的关键模型,值得考虑使用多个种子运行该模型,并对结果进行平均(尽管这可能是一篇单独的博客文章的主题)。
🏁结论
希望我已经说服您注意一下经常被忽略的随机种子参数。如果您想查看本文中使用的完整代码,或者对随机 seed 最佳实践有其他想法,请随时联系我们!
如果你喜欢这篇文章,看看我下面的其他作品吧!
使用公开来源数据分析洛杉矶的碰撞模式
towardsdatascience.com](/la-traffic-data-analysis-part-1-53f24e21067d) [## 为您的组织开发技术培训的 7 个技巧
将你的下一个培训课程想法变成现实的技巧
medium.com](https://medium.com/@jai_bansal/7-tips-for-developing-technical-trainings-for-your-organization-928cf7744d44)
如何使用残差图进行回归模型验证?
使用残差图验证您的回归模型
概述
任何数据科学/ML 项目最重要的部分之一是模型验证。这和你之前的工作一样重要。这是欢呼之前的最后一个障碍!
对于回归,有许多方法可以评估你的拟合度,即模型与数据的拟合程度。r 值就是这样一种度量。但它们并不总是最能让我们对自己的模型充满信心。
图片来自 Un flash
犯错是人之常情,随机犯错在统计学上是神圣的
这就是剩余图出现的原因。我们来谈谈什么是剩余图,以及你如何分析它们来解释你的结果。
残差
残差是一个点与回归线垂直距离的度量。简单来说就是预测值和观察到的实际值之间的误差。
残差方程
图 1 是如何根据最佳拟合线可视化残差的示例。垂直线是残差。
图 1 [ StackOverflow
残差图
典型的残差图在 Y 轴上有残差值,在 x 轴上有独立变量。下面的图 2 是典型残差图的一个很好的例子。
图 2 [ 信用
剩余剧情分析
线性回归模型最重要的假设是 误差是独立且正态分布的。
让我们来看看这个假设意味着什么。
每个回归模型本质上都有一定程度的误差,因为你永远不可能 100%准确地预测某件事。更重要的是,随机性和不可预测性总是回归模型的一部分。因此,回归模型可以解释为:
模型中确定性的部分是我们试图用回归模型捕捉的。理想情况下,我们的线性方程模型应该准确地捕捉预测信息。本质上,这意味着如果我们获得了所有的预测信息,那么剩下的所有信息(残差)应该是完全随机的&不可预测的,即随机的。因此,我们希望残差服从正态分布。这正是我们在剩余图中寻找的。那么一个好坏残积的特点是什么呢?
良好残差图的特征
一个好的残差图的几个特征如下:
- 靠近原点的点密度高,远离原点的点密度低
- 它关于原点是对称的
为了解释为什么图 3 是基于上述特征的良好残差图,我们将所有残差投影到 y 轴上。如图 3b 所示,我们最终得到一条正态分布的曲线;满足残差正态性的假设。
图 3:良好的残差图
图 3b:投影到 y 轴上
最后,这是一个好的残差图的另一个原因是,独立于自变量(x 轴)的值,残差以相同的方式近似分布。换句话说,当我们沿着 x 轴移动时,我们看不到残差值的任何模式。
因此,这满足了我们早先的假设,即回归模型残差是独立的,并且是正态分布的。
利用上述特征,我们可以看出为什么图 4 是一个差的残差图。这个图远离原点密度高,靠近原点密度低。此外,当我们将残差投影到 y 轴上时,我们可以看到分布曲线不是正态的。
图 4:不良残差图示例
图 4b:投影到 y 轴上
重要的是要理解,这些图表明我们还没有完全捕捉到模型中数据的预测信息,这就是为什么“会渗入到我们的残差中。一个好的模型在使用预测信息后应该总是只剩下随机误差(回想一下确定性的&随机成分)
总结
要验证回归模型,必须使用残差图来直观地确认模型的有效性。绘制所有自变量的所有残差值可能有点复杂,在这种情况下,您可以生成单独的图,也可以使用其他验证统计数据,如调整后的 R 或 MAPE 分数。
关于作者
Usman Gohar 是一名数据科学家,明尼阿波利斯数据科学的共同组织者,也是一名技术演讲人。他非常热衷于最新的数据科学研究,机器学习,并通过帮助和赋权年轻人在数据科学领域取得成功而蓬勃发展,特别是女性。您可以在 LinkedIn 、 Twitter 、Medium&follow onGithub上与 Usman 联系。
如何在 Python 中使用 Riot API
在本教程中,我将使用 Riot API 来展示如何构建一个像 op.gg 这样的应用程序。
我建议在你开始做任何事情之前,阅读他们的文档以了解他们 API 的最新变化。
什么是 Riot Games API?
Riot Games API 是一个 REST API,它向开发者提供数据,用于构建我们自己的应用程序或网站。目前,所有英雄联盟 API 都是版本 4(2020 年 3 月 19 日更新)。从这个版本开始,他们不再在 API 路径中包含次要版本。
以下是您可以从 Riot Games API 获得的一些数据:
- 服务状态。
- 召唤师详细信息:姓名,级别,个人资料图标,帐户 id。
- 通过召唤师名字匹配历史和匹配细节和时间线。
- 某人当前的游戏信息,如果有人在游戏中。
- 其他信息,查看 API 文档
Riot API 密钥入门
你总是需要一把钥匙来访问 Riot Games API。我们将讨论如何获得 API 密钥。
首先,使用您的 Riot 帐户登录 Riot 开发者门户。就是你每次玩英雄联盟用的账号。
在你的Dashboard
里,有一个DEVELOPMENT API KEY
。请记住,密钥将在 24 小时后过期。不要与任何人共享您的 API 密钥。如果你从 Riot API 得到一个“403”响应,你可能只需要刷新你的密钥。
此外,您可以注册一个个人防暴产品,那么你就不需要每 24 小时刷新您的密钥。通常情况下,个人申请需要两周时间审核。
请记住您提出的请求数量,因为开发 API 密钥和个人产品密钥有上限:
- 每秒 20 个请求
- 每两分钟 100 个请求
如果你注册了一个生产 API 密匙,那就更难注册了。上限是:
- 每 10 秒钟有 3000 个请求
- 每 10 分钟 18 万次请求
完成上述所有要求后,现在您应该获得一个开发 API 密钥。让我们试着看看 Doublelift Riot 账户。使用您的 API 密钥通过 access 在 Riot API 上进行测试:
[https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Doublelift?api_key=RGAPI-YOUR-API-KEY](https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Doublelift?api_key=RGAPI-YOUR-API-KEY)
结果应该是这样的:
请记住,Riot API 是区域化的,您需要选择您的区域。还有,账号详情,只有召唤师的名字容易获取,不加密。其他账户 id 信息是加密的。
还有,召唤师和账号 id 只在每个地区是唯一的,PUUIDs 是全球唯一的。
安装暴动监视器
如果你在谷歌上搜索riot api
或者league of legends api
,有很多库可以使用。这里有一个 Riot API 库的列表。他们中的许多人都没有得到很好的维护,正如你所知,Riot 已经将他们的 API 版本升级到 V4,并取消了所有旧版本。
这里我使用了一个名为的 Python 库。首先,你可以轻松地运行
pip3 install riotwatcher
要查看这样的帐户信息,我们只需尝试从 URL:
访问等级信息
我们还可以使用一行代码获得排名信息:
访问匹配数据
例如,我们想获取最后的游戏信息。
然后对比 op.gg 数据。我们得到了一些准确的数据,但很难读懂。我们需要访问 Champion 和其他静态数据。
截图自 op.gg
存取数据龙
现在我们只得到每个冠军的 id。为了更好的理解,我们需要知道每一个的名字。
从 Data Dragon 可以获得《英雄联盟》的所有静态信息数据。
运行代码后,我们得到了类似这样的结果。
此外,法术,符文和物品信息将从数据龙获得。现在,您几乎已经获得了构建 op.gg 这样的应用程序所需的所有数据。
确定冠军位置
如果你刊登最新的比赛细节。你可能会注意到位置信息和我们从 op.gg 得到的有点不同。
‘role’: ‘DUO_CARRY’,‘lane’: ‘BOTTOM’
你可以建立一个地图来确定每个冠军的位置。
- (中路,独奏):中路
- (TOP_LANE,SOLO): TOP
- (丛林,无):丛林
- (BOT_LANE,DUO_CARRY):底部
- (BOT_LANE,DUO_SUPPORT):实用程序
下一步是什么
现在,您已经了解了什么是 Riot Games API,并且已经成功地使用 python 从 API 中检索了第一批数据。而这些几乎都是构建 op.gg 的数据。
Riot API 还提供对实时客户端数据和重放数据的访问。我打算谈谈如何构建一个基本的实时客户端脚本,为您提供有关您当前游戏的信息。如果你有任何问题,请在下面提问。
了解更多信息
- 你可以从 DataDragon 获得所有关于冠军、物品等的信息。
- 暴乱开发者不和频道。
如何使用 Scala 模式匹配
当 if-else 语句太长时,就该考虑模式匹配了。
Andrew Ridley 在 Unsplash 上拍摄的照片
概观
模式匹配是 Scala 语言提供的最强大的工具之一。类似于 Kotlin 中的when
语句和 Java 中的switch
语句。
本质上,它将一个输入与我们想要匹配的所有可能的情况进行比较。在我看来,这是使用多行if-else
语句的一种优雅的替代方式,当有许多案例需要比较时,可读性更好。
在本教程中,我们将通过几个不同的场景来学习如何在 Scala 中使用模式匹配。
对科特林的when
说法感兴趣的,可以去看看这个教程。
Scala 模式匹配剖析
Scala 模式匹配的剖析如下。
objectToMatch match {
case object1 => println("You match object1.")
case object2 => println("You match object2.")
case _ => println("You match neither object1 nor object2.")
}
objectToMatch
是你试图模式匹配的 Scala 对象的可能值。
case object1
和case object2
是你所知道的可能与objectToMatch
匹配的两种模式。
case _
是 everything else 子句,它本质上意味着objectToMatch
与object1
或object2
都不匹配。
基本用法
既然我们已经理解了模式匹配的结构,让我们看一个简单的例子。
假设我们买了一袋混合水果,我们知道它通常含有苹果、香蕉、草莓或蓝莓。现在,我们有了一台能够对水果进行分类的扫描仪。如果我们使用 Scala 的模式匹配来编写程序,它会是这样的。
fruit match {
case "apple" => println("received an apple.")
case "banana" => println("received a banana.")
case "strawberry" => println("received a strawberry.")
case "blueberry" => println("received a blueberry.")
case _ => println("unable to classify this fruit. is it really a fruit?")
}
如果您有一个名为fruit
的变量,并且分配给它的值是apple
,那么上面的模式匹配语句将把received an apple.
打印到您的控制台。诸如此类。
当fruit
的值既不是apple
、banana
、strawberry
也不是blueberry
时,语句会将unable to classify this fruit. is it really a fruit?
打印到控制台。
现在,如果你要为此写一个if-else
语句,它会是这样的。
if (fruit == "apple") *println*("received an apple.")
else if (fruit == "banana") *println*("received a banana.")
else if (fruit == "strawberry") *println*("received a strawberry.")
else if (fruit == "blueberry") *println*("received a blueberry.")
else *println*("unable to classify this fruit. is it really a fruit?")
在我看来,模式匹配表达式比if-else
更具可读性,但是,嘿,这真的取决于你的偏好。归根结底,上述两种说法做的是同样的事情。
与案例类匹配
除了匹配对象本身的值,我们还可以匹配可能的类型(或case class
)。
假设我们正在为一家超市的新鲜农产品部的计算机扫描仪编写一个分类程序。扫描仪将根据物品的类型给物品贴上标签,例如水果或蔬菜。我想这就是我们如何定义我们的特征和案例类。
trait GroceryItem
case class Fruit(name: String) extends GroceryItem
case class Vegetable(name: String) extends GroceryItem
现在,我们将编写一个函数,它将一个GroceryItem
对象作为其输入,并对它是Fruit
还是Vegetable
进行分类。这是它最简单的写法。
def classifyGroceryItem(item: GroceryItem): Unit =
item match {
case _: Fruit => *println*("label item as fruit.")
case _: Vegetable => *println*("label item as vegetable.")
case _ => *println*("unable to label the item. this seems to be an item for other department.")
}
注意语法_: Fruit
。当我们想要对它的实例类型进行模式匹配时,我们应该这样写我们的case
。此外,该表达式实际上并不查看字段case class
的值(例如name
)。
如果我们还想匹配 case 类的字段,我们可以这样做(看第一个case
表达式)。
def classifyGroceryItem(item: GroceryItem): Unit =
item match {
case *Fruit*(name) if name == "apple" => *println*("item is a fruit and it's an apple.")
case _: Fruit => *println*("label item as fruit.")
case _: Vegetable => *println*("label item as vegetable.")
case _ => *println*("unable to label the item. this seems to be an item for other department.")
}
请注意,case 表达式的顺序很重要。在上面的例子中,如果附加的case Fruit(name)
表达式放在case _: Fruit
之后,代码将永远不会到达它,因为它将立即匹配case _: Fruit
。
从这个例子中,我们还了解到我们可以在case
语句上添加一个if
语句。我发现这在某些情况下很有用。
与选项匹配
在 Scala 中,我们可能有一个Option
类型的对象,这仅仅意味着我们可能有也可能没有值。
假设我们有一个函数,它根据商品的名称扫描超市的库存,如果找到了商品,就返回数量。
val inventory: Map[String, Int] = *Map*(
"apple" -> 10,
"banana" -> 15,
"strawberry" -> 10,
"spinach" -> 30,
"capsicum" -> 25
)
def findItemAndReturnQuantity(itemName: String): Option[Int] = {
inventory.get(itemName)
}
findItemAndReturnQuantity("sugar") // res1: Option[Int] = None
findItemAndReturnQuantity("spinach") // res2: Option[Int] = Some(30)
我们可以使用模式匹配来处理一个Option
对象。让我们编写一个函数来处理findItemAndReturnQuantity
函数的输出。
def handleOptionItemQuantity(quantity: Option[Int]) =
quantity match {
case Some(value) => *println*(s"quantity is **$**value.")
case None => *println*("item is not available.")
}
综合起来看:
handleOptionItemQuantity(findItemAndReturnQuantity("strawberry"))
// quantity is 10.
太好了。🙂
在我们结束这一部分之前,我想向您展示一个简单的提示。在某些情况下,比如这个Option
对象,编译器知道可能的结果是什么。因此,当您键入模式匹配表达式时,应该会看到下面的建议。
匹配(详尽)
如果您选择match (exhaustive)
,它将自动填充值存在和不存在的情况。
def handleOptionItemQuantity(quantity: Option[Int]) =
quantity match {
case Some(value) =>
case None =>
}
记住,如果需要的话,我们还可以在上面的表达式中添加if
语句。例如,当某个商品的库存量不足时,我们希望通知我们的员工。
def handleOptionItemQuantity(quantity: Option[Int]) =
quantity match {
case Some(value) if value < 10 => *println*(s"low stock - quantity is **$**value.")
case Some(value) => *println*(s"quantity is **$**value.")
case None => *println*("item is not available.")
}
就是这样。😃
包裹
当你读到这一节的时候,你已经学会了 Scala 模式匹配的基础知识。您现在应该能够在您的代码中使用它,或者替换一些现有的多行语句if-else
。
如果你也像我一样用 Kotlin 编程,你可能想看看这篇关于 Kotlin 的 when 语句的教程。它本质上相当于 Scala 对 Kotlin 的模式匹配。
当你不知道将要发生什么的时候,如何用科学来决定
用不精确的概率做决策是一件有风险的事情
媒体倾向于指出重新开放经济相对于保持封锁的风险或好处。很少看到任何新闻媒体采取系统的方法,这是我们希望决策者正在做的。我们知道统计爱好者。随着大部分经济现在重新开放,我们抱着最好的希望,但在不确定的时期,我们能确定什么呢?数学可能有答案。
维基百科用户 Alinaderi158 CCA-SA 4.0 的照片。
在我对传感器、机器学习和协作机器人的研究中,理解当你不知道将要发生什么时如何做出决定是我一直在处理的事情。数学可以告诉我们一些我们面临的事情,即使有很多我们不知道的事情。
我们做的每一个决定都有一定的风险。我买本田还是丰田?或者我应该省下那笔钱去坐公交车?去杂货店安全吗?还是我应该呆在家里叫外卖?在工作变得更安全之前,我能靠失业救济金生活下去吗?还是我应该现在就回去?
这些决定伴随着风险。它们也伴随着不确定性。
你可以把风险想象成人生的“已知的未知”,不确定性想象成人生的“未知的未知”。
我们现在都在应对的一大未知是冠状病毒。我向你保证,在 2019 年底和 2020 年初,数以千计的风险评估会议在无数的董事会会议室举行,没有提到全球疫情和全球封锁。它能被解释吗?可能比以前好,但不是完全好。
十几岁时,我是艾萨克·阿西莫夫的超级粉丝。阿西莫夫最出名的有两件事:他的机器人规则和虚构的心理史学,预测未来的数学,他在他的基金会系列中扮演了一个关键角色。从根本上说,阿西莫夫的心理史学是关于在不确定性下的决策,相信大规模的政治运动是可以预测的,或者至少是可以管理的。
混沌理论告诉我们,我们不能做阿西莫夫想要的事情。有太多不可预测的事件会产生巨大的影响。用数学术语来说,它们对初始条件很敏感。即使是像单个病毒的单个 RNA 链的单个变化这样微小而无足轻重的事情,也能对人类事件产生巨大的影响。“蝴蝶效应”意味着没有人能够预测遥远未来的全球性事件。
然而,假设有一个完全理性的负责人,他可以在考虑所有因素的情况下做出决策,并以最小的成本实现利益最大化。知道任何结果的概率都是未知的,某些行动的好处也是未知的,那么即使是超级人工智能也能做出正确的选择吗?这种生物可以依赖哪种数学?这样的人会选择什么样的策略呢?
在协作机器人中,我们不会告诉机器人具体要做什么。我们也不会让他们自己想办法。他们是团队的一部分,团队需要知道如何一起工作。我们使用战术手册。剧本是在很长一段时间内开发出来的,很多游戏,看看什么可行,什么不可行。这也需要一个有经验的教练根据情况选择正确的打法。
任何决策者在做出任何政策决定之前,手中都应该有一个剧本。边走边编是一个灾难的处方。这个剧本需要由手头的主题和政策制定方面的专家来编写,这样他们就知道什么样的决策是可行的。剧本必须包含决策者愿意做出的所有决策。
然而,我们如何利用数据从剧本中做出选择呢?如果你的专家中有一位是数学家,他们可能会建议一些数学方法来用不精确的概率做决策。
不确定性(我们称之为不精确概率)下的决策数学关注的是在你不知道最糟糕的事情会发生或者发生的可能性有多大的情况下做出最佳决策。数学家将最佳决策定义为带来最高收益的决策,这是一个衡量做出给定决策的总体收益的数字。
没有不确定性,做出任何选择的收益都很容易计算,即使结果是随机的。例如,假设你给我一个有六个面的骰子,告诉我如果我掷出 6,你会给我 10 美元,但如果我掷出其他任何东西,我必须付给你 x 美元。x 应该是多少才能让我接受你的提议?事实证明,有一个精确的数学答案,它来自于对“期望值”的计算,而“期望值”就是一个结果的成本或收益乘以它的概率。如果你把所有可能结果的期望值相加,就得到总期望值。如果期望值为正,总的来说,你会受益。如果是负数,总的来说,你会输。赌场知道这一点,因此操纵他们所有的游戏,以预期价值使赌场受益。
在骰子的情况下,掷出 6 的概率是 1/6。滚动其他任何东西的概率是 5/6。10 乘以 1/6 等于 10/6。x 乘以 5/6 等于 5x/6。两者相减,10/6 减去 5x/6,得到(10–5x)/6 或 5(2-x)/6。做一点数学计算,你会发现,如果 x 小于 2 美元,我会受益。如果 x 大于 2 美元,你就会获利。现在,对于一次掷骰,即使 x 很大,我仍可能获得收益。同样地,即使 x 很小,你也可能获得收益。但是在很多很多次的掷骰中,平均来说,具有最高期望值的人获胜的几率更大。
如果你想在任何碰运气的游戏中获胜,你所要做的就是计算出期望值是多少,并确保你能连续玩很多很多次。这就是为什么赌场和彩票中的大多数机会游戏都被操纵,以至于“庄家总是赢”。另一方面,股票市场通常有一个正的期望值。只要你把赌注压在很多很多股票上,就像投资股市指数基金一样,从长远来看,你就不会出错。
您可以将期望值应用于金融、物理、化学、生物等许多领域。数十亿年来,通过反复试验,进化已经确定了许多行为和解剖结构的预期值,并导致我们的形态和功能发展,因为它必须最大化我们的生存机会。
那么为什么不在决策中使用期望值呢?你可以,但是期望值只有在你知道期望什么时才起作用。如果没有呢?与进化不同,我们没有数不清的岁月和数十亿条生命来牺牲,来寻找合适的时机。计算机模型可能对此有所帮助,但是模型也依赖于知道会发生什么;你还能怎么造一个?
数学家们也研究了这个问题,并制定了一些策略。如果你无知,你所拥有的只是你对现实的信念来做决定。然而,这些都不是信仰的飞跃。相反,它们更像是猜测。对于每一个决策,你都要对该决策的最小预期收益或“效用”进行猜测。同样,你对不做这个决定的最大预期成本进行了猜测。
为什么我们关心最小的收益和最大的成本?原因是因为我们想限制我们的预期收益,这样我们就知道它会超过我们的猜测。
例如,假设我想在一次不能保证公平的掷硬币游戏中下注。它抬头的几率在 0.2 到 0.7 之间。我有五美元,我可以用任何方式把它分成正面和反面。我的增益是代表除法的可能结果的函数。最好的划分是什么?
把 h 股放在正面,把 T 股放在反面的预期效用是这些中最小的:
高 x 0.2-高 x 0.8
T x 0.3-H x 0.7
例如,如果我把 2 美元放在正面,3 美元放在反面,那么我的预期效用要么是 2 美元的损失,要么是 1.90 美元的损失,所以预期效用是负 2 美元。
如果我想找出最佳赌注是什么,我需要找出每个赌注的这些函数的最小值的最大值是多少。在 H+T=5 的约束下,这很简单,它就是两个函数相等的地方,或者两条线相交的地方。
最上面一行是最大期望值解。底线是每组赌注的最小期望值解。由作者用 Mathematica 创建。
那个点在 H=$2.75,T=$2.25。它当然还是会输。
这种决策方式被称为“马希民”,因为我们追求最小收益的最大化。它也被称为“最坏情况优化”决策,因为它是如此悲观[1]。几十年来,国际象棋程序一直利用这一点来战胜人类棋手。
也可以尝试优化最大增益。这就是所谓的“最佳情况优化”。那个点是两条线中任何一条的最高点。在这种情况下,最好的情况是把你所有的钱都押在反面,不要押在正面。这给了你大约 1.50 美元的估计收益。
然而,假设我想有一系列好的选择,而不是让这些算法为我挑选一个?如果我真的不确定概率,那么我可能只想过滤掉不好的概率。
有几种方法可以做到这一点。一个观察是,如果做出特定决策 D 的收益总是与所有其他决策一样好,但只对一个 E 更好,那么你应该扔掉 E,因为它永远不会击败 D。这被称为通过“逐点优势”选择最优集合。
一旦你这样做了,你就可以比较每一对决定。你减去他们的收益,然后计算两个决策的最坏情况期望值。这就像看着你的决定选择一个决定而不是另一个决定,看看你会失去什么。那些输给所有其他决定的人,你会丢掉。这种决策方法被称为“最大化”,因为你只是在寻找一个比其他人更好的“最大”决策集。
另一个选择是,只看某个给定决策的“最佳情况”和“最坏情况”之间的期望值都比另一个的期望值好的情况。换句话说,如果我锁定的最佳情况增益是 5,最差情况增益是-7,但我什么都不做的最佳情况增益是-8,那么即使锁定不是我最喜欢的选择,我也必须放弃什么都不做。这种方法被称为“区间支配”,是另一种摆脱糟糕选择的好方法。
我们的最后一个选择叫做电子证据可采性。在这种情况下,我们选择最大化至少一个预期效用情景的决策。也就是说,如果我看每一个可能的决策的预期效用,对于我提出的每一组概率,只有那些在保留方案中最好的才会被保留。这就像想象许多可能的场景,并抛弃那些在任何一个场景中都不尽如人意的决策。剩下的是那些有机会成为最佳选择的。
哪种方法最好?一般来说,如果你很不确定,你就不要选择 maximax 或马希民,因为不管你知道的有多少,你只会得到一个答案。然而,电子容许性、区间优势和极大性将会给你一些与你的不确定性成比例的好决策。少一些确定,多一些答案。就像柴郡猫说的,“如果你不知道你要去哪里,任何道路都可以。”
不考虑最大值和马希民,区间优势倾向于给你留下许多决策。如果你想要的只是摆脱那些完全糟糕的决定,那没问题。否则,最好选择 E-admissive 或 maximality。当你只有两个选择时,这些结果是一样的。一般来说,电子可接受性比最大性稍强。它考虑到了每一种可能的情况,但如果你过于乐观,它可能会被滥用,因为与 maximality 不同,它不仅仅关注最悲观的情况。
在任何情况下,无论你选择什么,都不能保证你不犯错误。你能保证的就是你做了你能做的最好的选择。
[1]特罗法,马蒂亚斯厘米。“使用不精确的概率在不确定的情况下做出决策.”《国际近似推理杂志》第 45 期,第 1 号(2007):17–29。
如何使用 Scikit-Learn 数据集进行机器学习
我们将探索乳腺癌数据集,并创建一个肿瘤分类模型
Scikit-Learn 提供干净的数据集供您在构建 ML 模型时使用。当我说清洁时,我指的是准备好用于训练 ML 模型的清洁类型。最精彩的部分?这些数据集与 Scikit-Learn 包本身一起提供。你不需要下载任何东西。只需几行代码,您就可以处理数据。
拥有现成的数据集是一项巨大的资产,因为您可以直接创建模型,而不必花费时间来获取、清理和转换数据,而这正是数据科学家花费大量时间的事情。
即使所有的基础工作都已完成,您可能会发现使用 Scikit-Learn 数据集一开始会有点混乱。不要担心,几分钟后你将确切地知道如何使用数据集,并在探索人工智能世界的道路上前进。本文假设您已经安装了 python、scikit-learn、pandas 和 Jupyter Notebook(或者您可以使用 Google Collab)。我们开始吧。
Scikit-Learn 数据集简介
Scikit-Learn 提供了七个数据集,他们称之为玩具数据集。不要被“玩具”这个词所迷惑。这些数据集非常强大,可以作为学习 ML 的一个强有力的起点。以下是一些数据集以及如何使用 ML:
- 波士顿房价-使用 ML 根据该城镇的房间数量、犯罪率等属性来预测房价
- 乳腺癌威斯康星州(诊断)数据集-使用 ML 将癌症扫描诊断为良性(不会扩散到身体其他部位)或恶性(扩散到身体其他部位)
- 葡萄酒识别—使用 ML 根据化学特征识别葡萄酒的类型
在本文中,我们将使用“威斯康星州乳腺癌”数据集。我们将导入数据并理解如何读取它。作为奖励,我们将建立一个简单的 ML 模型,能够将癌症扫描分类为恶性或良性。要阅读更多关于数据集的信息,请点击这里获取 Scikit-Learn 的文档。
我如何导入数据集?
数据集可以在sklearn.datasets.
让我们导入数据中找到。我们首先导入保存所有七个数据集的datasets
。
from sklearn import datasets
每个数据集都有一个用于加载数据集的相应函数。这些函数遵循相同的格式:“load_DATASET()”,其中 DATASET 是指数据集的名称。对于乳腺癌数据集,我们使用load_breast_cancer()
。类似地,对于葡萄酒数据集,我们将使用load_wine()
。让我们加载数据集,并将其存储到一个名为 data 的变量中。
data = datasets.load_breast_cancer()
到目前为止,一切顺利。这些加载函数(如load_breast_cancer()
)不会以我们期望的表格格式返回数据。他们返回一个Bunch
对象。不知道什么是Bunch
?别担心。
把一个
**Bunch object**
想象成 Scikit-Learn 对一本字典的别出心裁的名字
照片由 Edho Pratama 在 Unsplash 上拍摄
让我们快速回忆一下字典。字典是一种将数据存储为键和值的数据结构。把字典想象成你所熟悉的那本字典。您搜索单词(关键字),并获得它们的定义(值)。在编程中,你可以选择任意的键和值(单词,数字等等。).例如,为了存储电话簿,键可以是姓名,值可以是电话号码。所以你看,Python 中的字典不仅仅局限于你熟悉的典型字典,而是可以应用于你喜欢的任何东西。
我们的字典里有什么(Bunch)?
Scikit 的字典还是Bunch
真的很厉害。让我们从看它的检索表开始。
print(data.keys())
我们得到以下密钥:
data
是所有的特征数据(帮助我们识别肿瘤是恶性还是良性的扫描的属性,如半径、面积等。)在 NumPy 数组中target
是 NumPy 数组中的目标数据(要预测的变量,在本例中为肿瘤是恶性还是良性),
这两个键是实际数据。其余的键(如下)用于描述目的。值得注意的是,所有的 Scikit-Learn 数据集都分为data
和target
。data
表示特征,这些特征是帮助模型学习如何预测的变量。target
包括实际标签。在我们的例子中,目标数据是将肿瘤分类为 0 表示恶性或 1 表示良性的一列。
feature_names
是特征变量的名称,换句话说就是data
中列的名称target_names
是目标变量的名称,换句话说就是target
列的名称DESCR
,DESCRIPTION 的简称,是对数据集的描述filename
是 CSV 格式数据的实际文件的路径。
要查看一个键的值,您可以键入data.KEYNAME
,其中 KEYNAME 表示键。所以如果我们想看数据集的描述,
print(data.DESCR)
以下是输出的预览(完整描述太长,无法包含):
Scikit-Learn 乳腺癌数据集描述
您也可以通过访问 Scikit-Learn 的文档来查看数据集信息。他们的文档可读性更好,也更整洁。
使用数据集
现在我们已经了解了 load 函数返回的内容,让我们看看如何在 ML 模型中使用数据集。首先,如果您想探索数据集,可以使用pandas
来完成。方法如下:
# Import pandas
import pandas as pd# Read the DataFrame, first using the feature data
df = pd.DataFrame(data.data, columns=data.feature_names)# Add a target column, and fill it with the target data
df['target'] = data.target# Show the first five rows
df.head()
数据框的裁剪视图(不包括所有列)
你应该感到骄傲。您已经将一个数据集加载到一个 Pandas 数据框架中,该数据框架已准备好供探索和使用。要真正看到这个数据集的价值,运行
df.info()
df.info()输出—注意没有丢失值
有几件事需要注意:
- 没有任何缺失值,所有列都有 569 个值。这为我们节省了计算缺失值的时间。
- 所有的数据类型都是数字。这很重要,因为 Scikit-Learn 模型不接受分类变量。在现实世界中,当我们得到分类变量时,我们将它们转换成数值变量。Scikit-Learn 的数据集没有分类变量。
因此,Scikit-Learn 负责数据清理工作。他们的数据集非常有价值。通过使用它们,你将从学习 ML 中受益。
让我们做一些人工智能
最后,激动人心的部分。让我们建立一个模型,将癌症肿瘤分为恶性(扩散)或良性(非扩散)。这将向您展示如何将数据用于您自己的模型。我们将构建一个简单的 K 近邻模型。
首先,让我们将数据集一分为二,一个用于训练模型,为其提供学习数据,另一个用于测试模型,查看模型对以前从未见过的数据(扫描)的执行情况。
# Store the feature data
X = data.data# store the target data
y = data.target# split the data using Scikit-Learn's train_test_splitfrom sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)
这给了我们两个数据集——一个用于训练,一个用于测试。让我们开始训练模型。
from sklearn.neighbors import KNeighborsClassifier
logreg = KNeighborsClassifier(n_neighbors=6)logreg.fit(X_train, y_train)
logreg.score(X_test, y_test)
有没有得到 0.909 的输出?这意味着模型有 91%的准确性!是不是很神奇?在短短几分钟内,你就建立了一个对癌症扫描进行分类的模型,准确率高达 90%。当然,在现实世界中要比这复杂得多,但是你已经有了一个很好的开始。通过尝试使用 Scikit-Learn 的数据集建立模型,您将学到很多东西。如果有疑问,就用谷歌搜索你的任何问题。有一个巨大的机器学习社区,很可能你的问题以前被问过。快乐 AI 学习!
如何使用 Selenium 进行网页抓取并举例说明
使用 Selenium 从 Hoopshype.com 收集 NBA 球员的姓名和薪水
照片由 JC Gellidon 在 Unsplash
Selenium 是一个 Python 库和工具,用于自动化 web 浏览器来完成许多任务。其中之一是网络搜集,以提取有用的数据和信息,否则可能无法获得。这里有一个如何使用 Selenium 的分步指南,以从 https://hoopshype.com/salaries/players/网站提取 NBA 球员工资数据为例。
步骤 1 —安装和导入
pip install selenium
安装完成后,就可以开始导入了。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd
步骤 2 —安装并访问网络驱动程序
网络驱动是这一过程的重要组成部分。它实际上会自动打开你的浏览器来访问你选择的网站。根据您使用哪种浏览器浏览互联网,此步骤会有所不同。我正好用谷歌 Chrome。有人说 Chrome 与 Selenium 配合使用效果最好,尽管它也支持 Internet Explorer、Firefox、Safari 和 Opera。对于 chrome,你首先需要在 https://chromedriver.chromium.org/downloads下载网络驱动。根据您的 Chrome 版本,有几种不同的下载选项。要找到你的 Chrome 版本,点击浏览器窗口右上角的 3 个垂直点,向下滚动帮助,选择“关于谷歌 Chrome”。在那里你会看到你的版本。我的版本是 80.0.3987.149,如下图所示。
现在,您需要知道您在本地计算机上保存 webdriver 下载的位置。我的只是保存在我默认的下载文件夹中。现在,您可以使用下载的 webdriver 的直接路径来创建一个驱动程序变量。
driver = webdriver.Chrome('/Users/MyUsername/Downloads/chromedriver')
步骤 3-通过 Python 访问网站
非常简单但非常重要的一步。你需要你的代码来打开你试图抓取的网站。
driver.get('[https://hoopshype.com/salaries/players/](https://hoopshype.com/salaries/players/)')
运行时,该代码片段将打开浏览器访问您想要的网站。
第 4 步—找到您正在搜集的特定信息
为了提取您想要搜集的信息,您需要定位元素的 XPath。XPath 是一种用于查找网页上任何元素的语法。要定位元素的 XPath,突出显示您要查找的列表中的第一个元素,右键单击并选择 inspect 这打开了开发者工具。对于我的例子,我首先想定位 NBA 球员的名字,所以我首先选择斯蒂芬·库里。
在开发者工具中,我们现在看到元素“斯蒂芬·库里”就是这样出现的。
斯蒂芬·库里< /a > < /td >
这个元素可以很容易地转换成它的 XPath,但是首先,我们需要记住,我们不只是试图定位这个元素,而是所有玩家的名字。使用相同的过程,我找到了列表中的下一个元素,拉塞尔·维斯特布鲁克。
拉塞尔·维斯特布鲁克< /a > < /td >
这两个(以及所有其他玩家名字)之间的共同点是<td class=”name”>
,所以我们将使用它来创建一个包含所有玩家名字的列表。翻译成 XPath 看起来像//td[@class=”name”]
。分解一下,所有的 XPaths 前面都有一个双斜线,我们希望它出现在一个 td 标签中,在那个 td 标签中的每个类需要对应于**【name】**。我们现在可以用这个 Selenium 函数创建球员姓名列表。
players = driver.find_elements_by_xpath('//td[[@class](http://twitter.com/class)="name"]')
现在,为了将每个玩家的名字放入一个列表中,我们编写了这个函数。
players_list = []
for p in range(len(players)):
players_list.append(players[p].text)
按照同样的过程来获得球员的薪水…
斯蒂芬·库里 2019/20 工资
40231758 美元
拉塞尔·威斯布鲁克 2019/20 赛季薪资
38,506,482 美元
在检查这些元素并转换成 XPath 时,我们可以忽略样式和数据值,只关心类。
salaries = driver.find_elements_by_xpath('//td[[@class](http://twitter.com/class)="hh-salaries-sorted"]')
和工资清单文本…
salaries_list = []
for s in range(len(salaries)):
salaries_list.append(salaries[s].text)
第五步——申请每一年,把所有的事情联系起来
通常,在使用 Selenium 时,您会试图检索位于同一网站的多个不同页面上的数据。在我的例子中,hoopshype.com 有追溯到 1990/91 赛季的 NBA 薪资数据。
正如你所看到的,每个季节的 URL 之间的差异只是被包含在最后的年份的问题。所以 2018/19 赛季的网址是https://hoopshype.com/salaries/players/2018-2019/,1990/91 赛季的网址是https://hoopshype.com/salaries/players/1990-1991/。这样,我们可以创建一个函数,循环遍历每一年,分别访问每个 URL,然后将我们之前展示的每一年的所有步骤放在一起。我还将每个球员与他们在该赛季的工资配对在一起,放入一个临时数据帧中,将年份添加到该临时数据帧中,然后将该临时数据帧添加到一个主数据帧中,该主数据帧包含了我们获得的所有数据。最后的代码在下面!
如何在熊猫中使用 SQL
将另一项关系数据库技能添加到您的数据科学工具包中
如果您考虑熊猫数据帧的结构和来自 SQL 数据库的表的结构,它们的结构非常相似。它们都由数据点或值组成,每一行都有唯一的索引,每一列都有唯一的名称。因此,SQL 允许您快速访问您正在处理的任何项目所需的特定信息。但是,非常相似的查询可以使用熊猫!在这篇博文中,我将向您展示如何做到这一点,并解释您需要哪个库来实现它。
。查询()
使用 SQL 时,获取我们需要的信息叫做查询数据。在 Pandas 中,有一个内置的查询方法可以让您做完全相同的事情,它被称为*。查询()。这既节省了时间,又使您的查询在代码中更加连贯,因为您不必使用切片语法。例如,一个使用查询 Pandas 中数据的简单示例。query()* 方法会是:
query_df **=** df.query("Col_1 > Col_2")
否则,如果您不使用此方法获取数据,而是使用切片语法,它看起来会像这样:
query_df **=** df[df[df['Col_1'] **>** df['Col_2']]]
就像我说的,。query() 方法让你的代码看起来更专业,更高效。我想注意的一件重要的事情是,如果/当你决定在你的 Pandas 查询中使用“and”或“or”时,你实际上不能使用单词“and”或“or”——你必须使用符号“and”(&)和“or”(|)。下面是一个使用“&”帮助澄清的示例:
query_df **=** df.query("Col_1 > Col_2 & Col_2 <= Col_3")
pandasql 库
众所周知,使用 SQL 和/或其所有变体的能力是数据科学家在市场上最需要的工作技能之一,即使是在疫情时期。幸运的是,现在 Python 中有一个名为 pandasql 的库,它允许您编写 sql 风格的语法来从 Pandas DataFrames 中收集数据!这对于希望练习 SQL 技能的有抱负的数据科学家和习惯于使用 SQL 风格的语法收集数据的有经验的数据科学家来说都是非常好的。要将它安装到您的计算机上,只需使用!pip 安装:
!pip install pandasql
然后,要将它导入到您的笔记本中,您需要从 pandasql: 中导入一个 sqldf 对象
**from** pandasql **import** sqldf
导入所有内容后,编写一个快速的 lambda 函数是一个好主意,它可以使编写查询更容易。这样做的原因是,每次使用一个对象时,不必传入全局变量。下面是我所学的 lambda 函数,我用它取得了成功:
pysqldf **=** **lambda** q: sqldf(q, globals())
现在,每当你向 pysqldf 传递一个查询时,全局变量将在 lambda 中传递,这样你就不必为每个使用的对象一遍又一遍地做这些了。
现在您已经做好了一切准备,可以使用与 SQL 相同的语法查询数据帧中的数据了!下面是一个例子—这个查询将从一个 df 中返回前 10 个名字:
q = """SELECT Name
FROM df
LIMIT 10;"""
names = pysqldf(q)
names
查询的复杂性取决于您的需求和您作为数据科学家的技能。因此,如果你习惯使用 SQL 风格的语法,或者希望提高你的 SQL 语法技能,使用 pandasql 可以是一个继续组织你的数据&练习你的技能的好方法。感谢您的阅读!
我如何使用 Streamlit 构建 Web 应用程序
用于构建 Web 应用的 Streamlit 和 Python
威廉·艾文在 Unsplash 上的照片
W 说到网站设计,整体架构和建设是由前端开发人员负责的。这些开发人员接受想法和图像,并将其翻译成代码,以便这些想法和图像能够适当地显示在网站上。数据科学家通常不处理前端开发,更专注于应用程序或网站的内部功能。他们更专注于开发的后端。因此,许多数据科学家可能对开发前端应用程序来显示他们的数据科学项目的概念感到不舒服。但是,有一个简单的解决方案可以使前端开发的编码更加简单。
那个解决方案就是一个叫做— Streamlit 的 Python 库!
Streamlit 是一个开源的 Python 库,它使得 web 应用程序的开发变得更加简单,也更加美观。像许多其他 Python 库一样,这个库使复杂的技术性任务对数据科学家来说变得更加容易。为数据科学项目编写前端代码的过程不再像以前那样耗时耗力。
在项目中使用 Streamlit
为了演示 Streamlit 的使用流程,我们将从一个数据科学项目开始:
人工智能媒人
并转换项目中的代码,使其具有交互性和视觉吸引力。
项目:人工智能媒人
作为这个项目的一点背景,主要思想是实现无监督的机器学习,将约会简档聚集在一起,然后在它们各自的簇内匹配它们。这将潜在地减少不兼容的匹配,并增加兼容的简档找到彼此的可能性。要了解有关该项目的编码和开发的更多信息,请单击下面的文章:
为约会应用程序利用无监督机器学习
towardsdatascience.com](/dating-algorithms-using-machine-learning-and-ai-814b68ecd75e)
本文更深入地研究了所使用的聚类算法,以及用我们自己定制的约会资料数据集来创建和编码这些算法的过程。
与项目互动
这个项目的性质只是乞求用户的互动。如果我们有一个只是演示的约会算法,那有什么用呢?为了展示这个项目的全部范围和使用机器学习进行约会配置匹配的能力,我们必须能够与算法进行交互,并从用户输入数据。
在这里我们可以实现 Streamlit 来创建一个任何人都可以与之交互的简单用户界面。
创建 Streamlit 应用程序
为了运行 streamlit,我们必须先 安装 Streamlit 库 。安装完成后,创建一个空的.py
文件,我们将使用它来编写应用程序正常运行所需的所有代码。您可以随意使用任何 IDE。
导入库
让我们从导入我们将使用的库和数据集开始。
在这里,我们正在加载我们的应用程序运行所需的所有库。数据集存储在.pkl
文件中。本文介绍了这些数据集的来源:
我如何使用 Python Web Scraping 创建约会档案
towardsdatascience.com](/generating-fake-dating-profiles-for-data-science-cd3b929972bc)
但是,我们改进了这个过程,以接受实际的标签或类别,而不是之前的数值,这可以在下面的 Github 链接中看到:
permalink dissolve GitHub 是 4000 多万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/marcosan93/AI-Matchmaker/blob/master/Refining-Profile-Data.ipynb)
我们导入的下一个东西是用于用户输入数据的分类模型。如果你觉得有必要了解我们是如何对新用户数据进行分类的,那么看看这篇文章:
使用无监督的机器学习用于新的约会简档
medium.com](https://medium.com/swlh/how-a-dating-app-handles-new-profiles-part-2-fca4f13b5205)
助手功能和类别
为了组织我们的脚本,当我们在 Streamlit 中运行我们的脚本时,我们必须创建一些助手函数来简化这个过程。我们稍后将使用这些函数。
让我们解释一下这些功能的作用:
string_convert()
函数处理我们的原始数据。由于我们的数据集中的一些行和新的用户数据包含列表,因此该函数将这些列表转换为字符串数据类型,以便进行矢量化。vectorization()
函数创建每一列中使用的单词数组,然后删除相应的列。这为每行创建了一个包含字向量的大数据帧。该函数还对新用户输入的单词进行矢量化处理。scaling()
函数缩放矢量化的 DF 以及新的用户数据。top_ten()
函数组织 DF,并找出每个配置文件之间的相关性。然后,它根据新用户数据对相关数据进行排序。然后,它缩小到与新用户数据相关的前 10 个相似简档,然后返回这些简档的 DF。example_bios()
函数主要是为 streamlit app 创建的,通过显示数据集中的随机 bios。其目的是让用户在撰写自己的简历时作为参考。
类别和概率
这里使用的类别是每个配置文件可供选择的选项。它也是供用户在他们自己的约会简档中输入的选择列表。
为了准确地表示每个虚假简介的选择,每个选择的概率是基于每个选择的受欢迎程度而建立的。当随机选择时,这些概率将被考虑在内。
当一个新用户与应用程序交互时,他们会看到上面为他们的约会档案中的每个类别所做的选择。
编码 Streamlit 部分
现在,这就是 streamlit 库的用武之地。在这里,我们将开始使用 streamlit 函数,以便我们的应用程序能够顺利运行。点击此处查找以下所有功能的文档。
标题和页眉
# Creating the Titles and Image
st.title("AI-MatchMaker")st.header("Finding a Date with Artificial Intelligence")
st.write("Using Machine Learning to Find the Top Dating Profiles for you")image = Image.open('robot_matchmaker.jpg')st.image(image, use_column_width=True)
上面的代码告诉 streamlit 显示 web 应用程序的标题、标题和图像。这将是用户在看到页面时首先看到的东西之一。
上面的代码显示了什么
输入新用户简介
# Instantiating a new DF row to classify later
new_profile = pd.DataFrame(columns=df.columns,
index=[df.index[-1]+1])# Asking for new profile data
new_profile['Bios'] = st.text_input("Enter a Bio for yourself: ")# Printing out some example bios for the user
example_bios()# Checking if the user wants random bios instead
random_vals = st.checkbox("Check here if you would like
random values for yourself instead")
在这里,我们正在接受新的数据,算法将使用这些数据来查找前 10 个最相似的配置文件。这些信息将被储存在熊猫数据库中。我们也使用我们的example_bios()
功能来显示随机的 bios 示例供用户参考。我们正在使用 Streamlit 的功能来接受文本输入,以及一个可选的复选框,如果他们选择这样做,将随机选择类别。
使用上面的 streamlit 代码时会看到什么
输入新的用户选择
接下来,我们将让用户做出选择,如果他们选择不随机化他们的选择。
这里我们做一个检查,看看用户是否勾选了要求随机值的复选框。如果他们选择了随机值,那么新的用户配置文件将包含为他们选择的随机值。但是,如果他们选择为自己选择值,那么他们将能够为自己选择值。
通过使用 streamlit 的multiselect()
函数,我们可以让用户为指定的类别选择尽可能多的选项。slider()
功能将允许用户通过与滑块小部件交互来选择他们的年龄。除了用户只能选择一个选项之外,selectbox()
功能的作用类似于多选。
选择数据后,第一个格式化过程开始,将从multiselect()
函数给出的列表转换成字符串和数据集的其余部分。这个过程是通过在循环中实现我们的string_convert()
函数来完成的。
在这里,用户可以为呈现的每个类别进行选择
新的用户配置文件
在用户选择了类别并输入了自己的个人资料后,他们将会看到基于以下代码的约会资料:
# Displaying the User's Profile
st.write("-"*1000)
st.write("Your profile:")
st.table(new_profile)# Push to start the matchmaking process
button = st.button("Click to find your Top 10!")
新用户的约会档案
从这里,用户可以更新他们的个人资料,如果他们希望改变他们的一些选择,或者他们可以通过单击突出显示的按钮继续找到他们的前 10 个约会资料。
寻找前 10 名
if button:
with st.spinner('Finding your Top 10 Matches...'):
# Vectorizing the New Data
df_v, input_df = vectorization(df, df.columns, new_profile)
# Scaling the New Data
new_df = scaling(df_v, input_df)
# Predicting/Classifying the new data
cluster = model.predict(new_df)
# Finding the top 10 related profiles
top_10_df = top_ten(cluster, vect_df, new_df)
# Success message
st.success("Found your Top 10 Most Similar Profiles!")
st.balloons() # Displaying the Top 10 similar profiles
st.table(top_10_df)
单击按钮时,将执行以下代码。点击后,由于with st.spinner():
streamlit 动画,将弹出加载或进度通知。这个进度条将一直显示,直到它下面的所有代码都执行完毕。
在 spinner 函数的下面,我们之前定义的 helper 函数将被执行,以根据我们新的用户配置文件数据找到前 10 个配置文件。找到前 10 个配置文件后,将执行 streamlit 的success()
( 显示成功通知)和balloons()
( 用动画庆祝气球短暂覆盖页面)函数。这些功能并不是完全必要的,但是它们可以使这个过程在视觉上更吸引人。
该过程完成后,将显示前 10 个相似的配置文件:
用户的前 10 名(需要向下滚动查看更多)
结论
我们已经成功地为我们的约会算法编写了一个 streamlit 应用程序!但是为了查看该应用程序的所有优点,您需要在命令终端中运行该应用程序。( 点击此处了解更多信息 )。一旦我们在终端中运行了应用程序,我们就可以随心所欲地与它进行交互。
现在可能有一些潜在的方法来改进整个项目和演示,所以可以随意修改代码。另一个大大改进这个项目的方法是,只要给他们一个应用程序的链接,任何人都可以使用这个应用程序。这需要通过使用 AWS 或 Heroku 将应用程序托管在云上。请关注下一篇文章,它将深入研究在云上部署应用程序!
查看后续文章,我们开发了一个网站来托管我们的 Streamlit 应用程序:
一步一步的教程
towardsdatascience.com](/creating-a-website-to-host-your-python-web-application-f06f694a87e8)
资源
使用无监督机器学习和 NLP - marcosan93/AI-Matchmaker 的匹配简档
github.com](https://github.com/marcosan93/AI-Matchmaker) [## 我用机器学习和人工智能做了一个约会算法
为约会应用程序利用无监督机器学习
towardsdatascience.com](/dating-algorithms-using-machine-learning-and-ai-814b68ecd75e) [## 我为数据科学制作了 1000 份假的约会资料
我如何使用 Python Web Scraping 创建约会档案
towardsdatascience.com](/generating-fake-dating-profiles-for-data-science-cd3b929972bc) [## 约会应用如何处理新的个人资料?(第二部分)
使用无监督的机器学习用于新的约会简档
medium.com](https://medium.com/swlh/how-a-dating-app-handles-new-profiles-part-2-fca4f13b5205)
如何使用 Streamlit 部署包装在漂亮的 Web 应用程序中的 ML 模型
简化快速简单的机器学习 Web 应用程序
不要浪费时间去学 Django 或者 Flask!
不要把时间浪费在学习 Django 或者 Flask 上,多关注机器学习部分!
加州房价预测——Streamlit Web 应用程序(图片由作者提供)
如果你像我或任何其他机器学习爱好者一样,对你来说最糟糕的噩梦,显然不是 Cuda 错误,必须在其他地方部署模型,以在互联网上向你的朋友和网络展示你的工作。有许多方法可以解决这一问题,但在本文中,我将与您分享为什么我认为 Streamlit 是 it 的首选解决方案。
为了使这篇文章有条理并易于参考,让我们把它分成几个部分,这样你就可以直接跳到对你来说重要的部分。
- 有哪些选择?
- 为什么要简化?
- 如何用现有的 ML 代码制作一个 Streamlit Web 应用程序?
- 如何部署 Streamlit Web App?
- 结论
可供选择的事物
还有一些其他的方法来部署 ML web 应用程序,但是它们都有一些缺点,最明显的一个缺点是没有什么比 Streamlit 更简单快捷了。
Tensor flow . js是 TensorFlow 官方使用 Javascript 部署 ML 模型的方式。这是一种将简单的 ML 模型快速部署到 Web 上的非常棒的方式,但是当涉及到复杂的模型时,许多模型还不被这个库支持,并且不是所有在 Python 中工作的模型都能保证在 Javascript 中以相同的方式工作。
*即使我说的是快速,它仍然需要比 Streamlit 更多的工作和时间!
在浏览器、Node.js 或 Google 云平台中训练和部署模型。TensorFlow.js 是开源的 ML 平台…
www.tensorflow.org](https://www.tensorflow.org/js)
lask 是 python 中的一个小框架,它允许你使用你的 Python 技能来开发和部署 web 应用。如果你把它和 Streamlit 相比,你将需要更多的时间来编码和设计一个像样的 web 应用。
[## 欢迎使用 Flask — Flask 文档(1.1.x)
欢迎阅读 Flask 的文档。开始安装,然后了解快速入门概述。有…
flask.palletsprojects.com](https://flask.palletsprojects.com/en/1.1.x/)
D 是一个基于 Python 的 web 开发框架。使用这个框架来部署你的 ML 模型是一个很好的方法,它被包装在一个 web 应用程序中,但是这将需要大量的时间和对框架的理解。
Django 软件基金会非常重视我们开发人员、用户和社区的多样性。我们心烦意乱…
www.djangoproject.com](https://www.djangoproject.com/)
为什么选择 STREAMLIT?
机器学习爱好者不应该浪费时间学习 web 开发,这样他们就可以专注于他们的目标,即构建更好的模型!
这正是 Streamlit 帮助我们的方式。这是构建 web 应用程序的最简单快捷的方法,它可以使用令人敬畏的 UI 元素和 Markdown 吸引人地呈现您的 ML 模型和数据。
Streamlit 是一个面向机器学习和数据科学团队的开源应用框架。在…中创建漂亮的数据应用程序
www.streamlit.io](https://www.streamlit.io/)
现在,在多次称赞 Streamlit 使用简单快捷之后,我这么说是什么意思呢?为了理解这一点,让我和你们分享一下我是如何偶然发现这个惊人的框架的。
我对生成对抗网络感兴趣,目前,我正在探索和构建一些使用不同种类的 GANs 的项目。为了分享我的探索之旅并记录我的项目,我开始撰写 GANs 系列,这是一系列关于 GANs 及其实现的文章。
我遇到的最大障碍是无法部署一个将黑白草图图像转换为彩色图像的条件 GAN 模型。我在生成器模型中使用的模型架构是一个 U-Net 模型,它有相当多的跳跃连接。你可以从这篇文章中浏览详细的解释,用一步一步的代码块来训练模型。
U-NET 模型架构—(图片来源:https://en.wikipedia.org/wiki/U-Net)
我尝试了前面讨论的 web 部署的所有替代方案。这个模型在 TensorFlow.js 中似乎没有预期的效果,我花了将近一周的时间学习和尝试 Django 框架。
这是我偶然看到Adrien Treuille的这篇优秀文章的时候,他展示了他如何使用 Streamlit 在13 行 Streamlit 代码下为一个 TL-GAN 制作了一个令人印象深刻的具有出色 UI 的 web 应用程序!
我花了大约 15 分钟在网站上浏览他们的基本文档,当我试图为我的模型实现它时,Adrien 没有夸大其词,我只花了 12 行 Streamlit 代码来加载经过训练的模型,将其包装在下面显示的 UI 中,并为部署做好准备。
使用条件 GAN 生成草图到彩色图像— Streamlit Web 应用程序(图片由作者提供)
用现有的 ML 代码制作 WEB 应用程序
是的,你没看错,
你只需在现有的 Python 文件中添加几个 Streamlit 函数调用,而无需任何 HTML、CSS 或 JAVASCRIPT 代码来设计你的 Web 应用!
您所要做的就是从 pip 安装 Streamlit 包,并在现有的 python 文件中添加一些 Streamlit 函数。要安装 Streamlit 只需使用以下命令:
pip install streamlit
要检查安装是否成功,并在他们的 hello world 应用中探索,只需使用命令:
streamlit hello
一旦您安装了您的 Streamlit 并根据您的需求进行了必要的更改,您只需使用一个命令在本地运行 web 应用程序。
streamlit run file_name.py
它有各种很酷很有用的功能,比如:
- 保存文件时实时修改
- 只需按下键盘上的 R 键即可重新运行应用
- 只需按键盘上的 C 键 即可清除缓存
- 录制 web app 并在本地保存一个视频文件与大家分享
- …还有更多
我在下面添加了一个 GitHub 要点,向您展示我是如何将 Streamlit 函数调用添加到草图到颜色图像生成模型的现有 python 代码中,使其成为一个功能齐全的 web 应用程序,如上图所示。
我在添加 Streamlit 代码之前的代码被注释掉,以便更容易看到需要做什么更改。如果您希望看到草图到彩色图像生成模型的代码,您可以浏览此处链接的文章。
就是这样!如果包括导入语句和我实现的其他条件,实际上有 13 行额外代码。
部署 STREAMLIT WEB 应用程序
有各种选项可供您部署使用 Streamlit 构建的 web 应用程序。
H eroku 是一种可靠的方式来部署这些 web 应用程序,而不需要使用任何其他云服务并在其上设置虚拟实例。Heroku 为我们打理一切。但 Heroku 的一个缺点是,它在 dynos 的免费版本中只允许 512MB 的大小,TensorFlow 2.2.0 需要更多的空间来安装。如果您的代码不会中断,您可以使用任何低于 2.0.0 的版本。
Amazon Web Services是部署 Streamlit 应用程序的另一个好地方,而且比您想象的要简单。只需用 Ubuntu 18.04 或更高版本启动一个新的 EC2 实例,安装依赖项并运行streamlit run file_name.py
命令。你将获得一个公共网址,你可以与你的朋友和网络在线分享,这样他们就可以通过你的出色的网络应用程序。
itHub repository 是为 Streamlit web 应用程序托管代码的另一种很酷的方式。这不能算作一个完整的部署方法,但 Streamlite 的一个优秀特性是它允许链接到 streamlit run 命令中的代码。因此,如果用户在他们的系统上安装了所有依赖项以及 Streamlit 包,他们可以通过提供到。py 文件。例如,您可以使用以下命令在您的系统上本地运行 my Streamlit web app:
streamlit run [https://raw.githubusercontent.com/tejasmorkar/housing_price_prediction_aws/master/CaliforniaHousingPrices.py](https://raw.githubusercontent.com/tejasmorkar/housing_price_prediction_aws/master/CaliforniaHousingPrices.py)
treamlit 仍然是一个新的框架,并致力于为其用户带来新的和酷的特性。其中一些将在他们的路线图中讨论。我期待的最激动人心的功能之一是一键轻松部署 Streamlit Web 应用程序。在论坛中阅读更多信息。
这是一个简单的 Web 应用程序的视频,我已经用 Ubuntu 18.04 在 AWS EC2 实例上部署了它。
加州房价预测演练视频— Streamlit Web 应用程序
结论
所以,这就是为什么我觉得 Streamlit 是一个如此令人印象深刻的框架,可以帮助每个人专注于机器学习开发的重要部分,并释放部署部分所需的压力。
少关注部署,多关注解决 Cuda 错误!
要开始使用 Streamlit,只需在链接上跳转到他们提供的官方文档—https://docs.streamlit.io/en/stable/
*如果您对从入门到部署 Streamlit web 应用程序的任何内容有任何疑问,您可以在论坛上搜索或提出新问题。您将找到社区成员和 Streamlit 团队回答的几乎所有问题的解决方案—【https://discuss.streamlit.io/ *
如果您有任何疑问、建议、错误或反馈,请随时通过任何最适合您的方式联系我!
我的联系信息:
邮箱:tejasmorkar@gmail.comLinkedIn:https://www.linkedin.com/in/tejasmorkar/ GitHub:https://github.com/tejasmorkar
Twitter:https://twitter.com/TejasMorka**