买入并持有交易策略
用 Backtester 计算策略的性能——一个用于回溯测试的 Python 框架。
米歇尔·汉德森在 Unsplash 上的照片
介绍
买入并持有策略是指在第一个数据点买入一项资产,然后看看最后一个数据点的投资组合价值。
买入并持有策略有时也被用作测试其他策略表现的基准。如果一个精心设计的逻辑不能打败简单的买入并持有策略,这个策略可能一文不值。
虽然手动测量购买并持有策略的性能并不难,但拥有一个回溯测试框架是有用的——您可以进一步改进该策略,它通常带有绘图功能。
见我关于这个话题的其他文章:
我用 Python 写的关于股票市场分析的文章的精选列表。
romanorac.medium.com](https://romanorac.medium.com/stock-market-analysis-in-python-b71bf50151d9)
这里有几个你可能会感兴趣的链接:
- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)
上面的一些链接是附属链接,如果你通过它们进行购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
认识反向交易者
马库斯·斯皮斯克在 Unsplash 上拍摄的照片
Backtrader 是一个用于回溯测试和交易的开源 Python 框架。它让你专注于编写可重复使用的交易策略、指标和分析工具,而不是花时间建立基础设施。
在安装它之前,请安装 TA-LIB 依赖项:
# Mac OS X
brew install ta-lib# see [https://github.com/mrjbq7/ta-lib](https://github.com/mrjbq7/ta-lib) for other platforms
安装 Backtrader 和安装每个 python 包一样简单:
pip install backtrader[plotting]
买入并持有策略
Ashkan Forouzani 在 Unsplash 上拍摄的照片
我们要计算一下,如果我们在 2010 年 1 月 1 日投资 10.000 美元到微软,并一直持有到现在,我们会获得多少收益。
战略
我们只需要几行代码来实现 Backtrader 的买入并持有策略。
以下代码的解释:
- start 方法设置现金的初始金额。
- 对于第一个数据点,只调用一次 nextstart 方法。这非常适合实施买入并持有策略。
- 所有可用的现金都用来购买固定数量的股票。它被截断为整数,因为所有的经纪人都不支持零股。
- 回报在 stop 方法中计算,使用投资组合的现值和初始现金量。
import backtrader as btclass BuyAndHold_Buy(bt.Strategy): def start(self):
# set the starting cash
self.val_start = self.broker.get_cash() def nextstart(self):
# Buy stocks with all the available cash
size = int(self.val_start / self.data)
self.buy(size=size) def stop(self):
# calculate the actual returns
self.roi = (self.broker.get_value() / self.val_start) - 1.0
print("ROI: %.2f, Cash: %.2f" % (100.0 * self.roi, self.broker.get_value()))
回溯测试
正如上面已经提到的,我们想计算持有微软股票大约 10 年我们会获得多少收益。
我们定义 ticker、date 参数并初始化数据馈送:
from datetime import datetimedata = bt.feeds.YahooFinanceData(
dataname="MSFT", fromdate=datetime(2010, 1, 1), todate=datetime(2020, 10, 23)
)
然后我们初始化脑波强化器引擎:
cerebro = bt.Cerebro()
将数据馈送添加到引擎:
cerebro.adddata(data)
将策略添加到引擎中:
cerebro.addstrategy(BuyAndHold_Buy, "HODL")
设置现金:
cerebro.broker.setcash(100000.0)
运行回溯测试:
cerebro.run()# The output
ROI: 788.00, Cash: 88800.40
我们将获得 788%的疯狂回报。如果我们能回到过去😊
Gif 来自 giphy
形象化
我们都听说过“一图胜千言”这句话。这就是 Backtrader 的闪光点。
反向交易者可以想象一个有进场点和出场点的策略。在我们的例子中,我们只有一个入口点,所以交易策略的可视化不会太戏剧化。但是我们需要花相当多的时间来使我们摆脱 Backtrader 的束缚
让我们试试(下面的命令在 JupyterLab 中有效):
cerebro.plot(iplot=False)
可视化的购买和持有交易策略与微软股票。
要了解更多关于买入并持有的策略,请访问反向交易文档。
在你走之前
像往常一样,你可以下载这款 Jupyter 笔记本,在你的机器上试例子。
在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。
照片由Courtney hedge在 Unsplash 拍摄
作为数据科学家买车
从问题陈述到 web 应用程序
应用程序图表
在绿宝石岛(爱尔兰)生活了一年后,是时候搬回巴西了——新冠肺炎疫情让整个世界天翻地覆。
生活在里约热内卢或任何其他巴西大都市的一个有趣(或可悲)的事实是,拥有一辆车几乎是强制性的——只要你买得起。基于此,我决定作为一名优秀的数据科学家来解决这个问题。我建立了一个汽车推荐系统,在网页上搜索汽车,处理数据,并通过机器学习模型传递数据,以便列出和显示与我正在寻找的汽车更相关的汽车——spoiler:这款应用程序对我帮助很大
你可以在web app和我的Github页面上查看应用和我开发的所有代码
应用评分表
获取数据
在这个项目之前,我根本没有实践过网络抓取。不过,只要对某些模块和网页的工作原理有一点了解,你就可以把网络变成一个更强大的数据源。另外,我不能忘记提到我上过 Mario Filho *(巴西该领域的参考文献之一)*数据科学课程,它的内容对我帮助很大。
为了读取页面 HTML 代码并从中获取数据,我使用了 BeautifulSoup 。这个过程很简单,你打开你想获取数据的页面,检查你感兴趣的项目并存储你想要的信息。要做到这一点,您必须了解页面的结构,并想出一种智能的方式来存储和组织您正在抓取的数据。
数据解析
网络抓取本身并不是目的。换句话说,我们总是受网站设计和模式的支配,正因为如此,每个页面都有自己的废弃方式。此外,我们需要解析字符串,以便以我们想要的格式获取信息。
我在三个步骤中得到数据。首先,我抓取了网站的搜索页面,并存储了它的链接、汽车规格和汽车制造商。之后,我解析了每个汽车页面,以获取汽车的特征。最后,我对数据应用了一些特征工程,以便能够应用机器学习算法。
获取搜索页面
解析数据帧
特征工程
为了避免稀疏性问题,我决定对虚拟变量应用一种热编码,并且只选择频率最高的组件。我将低频类别视为噪音,这样我就能够在不损失太多信息的情况下降低一点数据的维度。我还通过应用 scikit learn 中的 fidfVectorizer 将一组原始文本转换为 TF-IDF 特性矩阵。
数据标记
对于这个项目,我决定手动标记训练数据。我在电子表格上打开文件,把我想买或至少看过照片的车设为 1,把我不想买的车设为 0。我本可以使用主动学习技术来标记数据,但是我决定,对于这个项目来说,为了尽可能的准确,我自己来做。
模型
我首先构建了一个只有两个特征(价格和型号)的基线模型。然后我应用了随机森林和 lightGBM 等不同的模型。我还为每个模型测试了不同的变量,这样我就可以根据特性的数量来平衡模型的复杂性。
经过漫长的过程,我决定创建一个由随机森林和 lightGBM 组成的集合模型。
模型结果数据分析
除了模型提供的分数*(由于不平衡数据标签,我使用平均精度和 Roc AUC 分数作为度量标准),我还构建了一个仪表板,显示关于得分最高的汽车的信息。*
每次更新应用程序的数据库时,仪表板也会更新。因此,让我们检查几个当前日期的图表和曲线图。
通过查看上面的图表,我可以衡量模型的运行情况。嗯,到目前为止结果是惊人的!我正在寻找两个品牌(大众和福特)的价格在 17-30k 雷亚尔以内的汽车。除此之外,福特嘉年华和福特 ka 是我最有可能购买的汽车。此外,所有这些型号都是我感兴趣的汽车。所以,这个应用程序运行得非常好!
app 会帮我买车吗?!
这个问题的答案很简单:对我肯定有帮助!事实上,它已经在起作用了。我每天都在更新数据库,以便找到最好的报价。当我快要到达巴西的时候,我将会决定当我到达那里的时候我将会买的每一个。
结论
我建立了一个非常好用的汽车推荐系统。所有的建议都与我正在寻找的一致,我很自豪能够使用我的数据科学技能来完成这个美丽的任务。
如果你想了解更多关于项目本身的信息,请查看我的 Github 上的代码。关于它,有很多我在这篇文章中没有提到,比如容器、烧瓶和 Streamlit 应用程序的使用。
如果你需要任何帮助来建立你的推荐系统,让我知道,我会帮助你。
(以书呆子的方式)买车
通过使用机器学习进行价格预测,书呆子搜索引擎可以找到二手车价格的好交易。
我不是那种可以通过观察汽车的光学系统(或者通过观察整个汽车)来说出汽车型号、品牌、年份的人。因此,当我不得不从成千上万的选择中做出买哪辆车的选择时,我的选择几乎是随机的。我可以上网浏览一堆照片,但对我来说它们看起来都差不多。
所以我决定做我最擅长的事,用最无聊的方式解决问题。😃
我的目标是买一辆二手车,以我心中特定的预算,最大化我能得到的价值。同样,我不知道在这个上下文中值是什么,因为我对汽车一无所知。但是让我们假设有一个函数 y = f(X) 可以告诉我们一辆车的价格( y ),给定该车的特征( X ,又名特征)。价值不是一个客观指标,而是"市场认为"通过添加/删除某个特定功能(例如三门与五门汽车)汽车的价格会发生多大变化。“市场认为”是人们集体认同的,数学上的 对一辆汽车有无给定特征的价差分布的预期。
在一个“明知故犯”的世界里,每个人都会知道函数 y = f(X) ,并用它来设定他们想要出售的汽车的价格。
虽然有在线价格计算器和带有车型-年份-公里价格建议的表格(近似于 y = f(X) ),但并不是每个人都以这种方式来评估他们的汽车价格。此外,特定买方或卖方对价值的感知可能与市场认为的**(y = f(X))不同( y’=f’(X) )。例如,卖方可能会分配一些价值用于今天出售汽车,而不是等待,为此她愿意降低汽车的价格,但作为买方,我对此没有任何价值,所以我会将这辆汽车视为销售机会。**
因为我对自己的价格-价值关系( y’=f’(X) )没有什么特别的个人想法,所以我会尽量去找市场是怎么想的( y=f(X) )对于那些我关心的特征( X )。例如,我不介意汽车的颜色,但让我们假设白色汽车往往更便宜,让我们假设我不知道这一点。因为车的颜色不在,【y * = f(X )在价格上不会对白色或黑色版本的同款车做任何区分,【y 】会介于两者之间(具体要看我用白色和黑色车的多少来找函数【y * = f(X ))。在查看白色( y_white )和黑色( y_black )车的实际要价时,我应该发现y _ white<y <y _ black。因此,我可以利用实际价格和预测价格之间的差异来找到对我来说比较划算的交易。越负的 y_actual-y,越好成交。在我们的例子中,y _ white-y <0和y _ black-y >0。所以这样一个过程的最终输出会是“买白色车的建议。****
所有这些冗长的介绍就是为什么建立一个模型(即估计 y=f(X) ) 来预测二手车价格可以帮助像我这样的不专业的人做出数据驱动的决定,而不需要真正了解汽车,相信“市场”拥有数据的所有相关信息,我可以提取这些信息来做出更明智的决定。**
模型结构
该过程如下:
- 创建 y=f(X)**
- ____ 获取大量汽车数据: X 和 y_actual*
- ____ 训练一个机器学习模型, y=f(X)**
- 使用 y_actual-y 寻找优惠*
我为构建模型考虑的特征( X )是:*
****numerical features:** consumption [km/l], mileage [km], original price [euro], acceleration [s], motor’s power [kW], car’s age [days], quarterly minimum (Q min) & maximum expenses (Q max) [euro], annual spent (based on the average fuel consumption plus expenses) [euro]**categorical features:** fuel [diesel, benzine, electric, hybrid..], car body [hatchback, sedan, suv...], energy label [A, B, C.. F], brand [audi, honda, toyota...], model [a3, auris, golf, yaris...], transmission [automatic, manual, semi-automatic]**
训练的模型是一个简单的 GradientBoostingRegressor,具有网格搜索超参数调整和 k 倍交叉验证。
**def train_model(X,y,features):
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV, KFold
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
GB = GradientBoostingRegressor()
xg_param_grid = {
'n_estimators': [300, 400, 600, 800],
'learning_rate': [0.04,0.02],
'max_depth': [6],
'subsample': [0.8]
}
kfold = KFold(n_splits=10, random_state=0, shuffle=True)
gsXGB = GridSearchCV(GB, param_grid=xg_param_grid, cv=kfold, scoring="neg_mean_squared_error", n_jobs=-1, verbose=1)
gsXGB.fit(X_train[features], y_train)
XGB_best = gsXGB.best_estimator_
y_hat_test = gsXGB.predict(X_test[features])
y_hat = gsXGB.predict(X)**
为了知道哪个特征与预测汽车价格更相关,可以检查模型的特征重要性图:
预测汽车价格时模型指定的功能重要性
似乎起步价(新车时的价格)是预测二手车价格最重要的因素,其次是车龄和行驶里程。
人们也可以使用 SHAP 库来更好地理解特征和预测之间的关系。这篇文章对 SHAP 价值观有一个很好的解释:点击这里。
SHAP 汇总图
例如,在 SHAP 汇总图中,可以看到预测的价格主要受汽车原始价格的影响:原始价格越低(蓝色),预测的价格越低(SHAP 值低于 0)。要素的 SHAP 值表示知道该要素的值会在多大程度上改变该样本预测的模型输出。数字特征有一个简单的解释,但分类特征有点难以解释,因为它们是标签编码的,即类别字符串被转换为数字。例如,编码特征变速器的标签将自动转换为 0,将手动转换为 1;因此变速器 redish 点对应更高的值,因此 1: 手动。变速器 redish 点(手动)和 blueish 点(自动)之间的价格预测差大约为 1000€。这个大约 1k 的€是值**市场分配给拥有自动变速箱而不是手动变速箱的汽车。****
汽车原始(新)价格的 SHAP 依赖图
SHAP 依赖图显示了单个特征对模型预测的价格的影响。图中的每个点都是数据集上的一个预测。x 轴上的值是要素,y 轴是该要素的 SHAP 值。该颜色对应于第二个特征,该特征可能与我们正在绘制的特征有交互作用。例如,原价似乎与预测价格呈非线性关系:原价越高,预测越高,但从 15k 的€到 20k 的€新车价格增加的二手车预测价格比从 35k 的€到 40k 的€增加的多(大约 1k 的€对 500 的€)。在相同的图中,可以看到,对于相同的原始价格,例如 20k€,里程越高,预测的价格越低,并且该差异可以对预测的价格产生大约 1.5k€的影响。
根据 SHAP 依赖图,预测的汽车价格与里程数和车龄(天数)之间存在(相当)线性关系。粗略估计,里程每增加 75000 公里,预测价格下降 1k€。同样,一辆 1000 天前的汽车,其预测价格会有 1000€的下降。这些是经验法则,但并不意味着每辆车都是如此。
********
里程和车龄(天数)的 SHAP 相关图
通过绘制 SHAP 力图,也可以理解模型是如何预测每辆车的价格的。例如,下一个图显示汽车价格的基值应该在 10100€左右,这对应于汽车价格的平均值。但是,本例中显示的特定汽车的预测价格较低,即 9233€。这主要是因为高里程(101685 公里)和车龄(3110 天)分别使价格下降了约 400€和 1.3k€。汽车的原价是 19811€,这使得模型预测的价格增加了不到 250€。从基础值(10100€)到模型输出值(9233€)的其余贡献可以在图上观察到。
SHAP 力图解释了单个汽车的预测价格如何通过每个特征增加(左侧红色特征)或移除(右侧蓝色特征)的值来解释
我很好奇的想知道,低油耗(高公里/升)的汽车是否会有更高的平均年行驶里程。考虑到下图中显示的消耗和年里程的联合分布,似乎没有如此明确的关系。
消耗量[公里/升]和年里程[公里]的联合分布
寻找交易
既然我们已经创建了模型 y=f(X) ,我们可以继续使用价格预测来查找使用 y_actual-y 的交易。我决定构建自己的书呆子搜索引擎,在那里,我将绘制出(预测价格)与y _ 实际 (要价),而不是显示汽车选项列表及其照片(任何汽车销售网站通常都会这样做)。如果一辆车落在 1:1 线(y _ actual=y ), 表示要价公平。如简介所述,我其实对那些y _ actual*<**【y 的车比较感兴趣。如果您想使用我的搜索引擎,请点击下面的“结果”标签。我建议您检查桌面版本,因为移动版本的扩展性不好。
有两个标签,“自动”只显示自动变速箱的汽车,而“所有汽车”既有手动的也有自动的(实际上甚至有一些半自动的,我不知道存在)。图中每个点是一辆车,x 轴代表模型预测的价格【€】(【y )),y 轴是要价【€】(y _ 实际 )。圆点的大小与汽车的消耗量相关。圆点的颜色与年度总支出相关(一年的税收支出加上取决于汽车消耗的平均燃料支出加上实际价格减去明年同一辆汽车的模型预测价格,这是当我增加 14000 公里的里程和 365 天的车龄时模型的输出)。我还添加了一些过滤器,以防你想查找特定的品牌、里程等。***
在该图中,划算的汽车是那些远离 1:1 线向右的点,即预测价格> >实际价格。如果你点击这个点,你将被重定向到汽车的链接,将能够看到汽车的照片和更多的信息。如果你被重定向到一个搜索列表,那是因为汽车已经售出。
选择“结果”选项卡查看搜索引擎。提示:移动版扩展性不好,检查桌面版
用于训练模型并在前面的图中显示的数据来自于 2020 年 7 月在荷兰一个网站上提供的二手车价格。在获得数据之前,我使用了一些预过滤器,例如至少从 2012 年起行驶里程不到 180000 公里、€不到 17k 的汽车。
最后,在所有这些分析之后,我能找到的最佳交易是这样的:
图片由 Ronda Jenkins 从 Pixabay 拍摄
我想我要征求一下别人的意见…
购买足球队:机器学习方法
一种比随机猜测或从 18000 名职业选手中挑选选手更好的方法。
托马斯·塞勒在 Unsplash 上的照片
随着我们进入一个体育已经成为我们生活中至关重要的一部分的世界,它也成为投资者获得更好回报、与观众互动并让他们感受到自己存在的热门市场。此外,我们可以看到体育观众的激增导致了更多的锦标赛,对投资者来说,利用这些赛事已经成为一项艰巨的任务。我们接受了一项挑战,帮助主要投资者从 18000 名足球运动员中挑选出最好的球员,以建立一支能够参与并超越大联盟中其他俱乐部的梦想足球队。我们利用机器学习算法对我们俱乐部的潜在团队成员和投资者的潜在预算进行分类,以优化他们的市场收益。因此,我们想出了一个战略来建立最好的团队,同时牢记投资者的预算限制在 10 亿欧元。
简介
我们有一个国际足联数据集,其中有几个名为——评级,释放条款和工资的列。我们假设在即将到来的超时数据集中没有这些变量。这些可以用于各种形式,如将玩家评定为表现较好的玩家或中等或达不到标记的玩家。此外,它还可以转化为应该被邀请参加一些俱乐部聚会、活动等的玩家。我们对评级变量使用监督学习建立了两个模型,并通过将该变量分为两类使其成为一个分类问题:大于或等于 70 和小于 70 作为我们的潜在俱乐部成员或不是。我们选择 70 分作为我们的门槛,因为大多数主要俱乐部只有评分高于 70 分的球员。为了与他们竞争,我们倾向于只让那些评分高于我们门槛的玩家参与。此外,我们还利用模型结果来预测投资者每年提供俱乐部会员资格的成本。我们的第二个模型利用了从我们之前的最佳分类器中获得的预测评级类别,而不是“实际评级”,在这里,将 release_clause 和年薪的组合作为投资者成本作为我们的因变量。
数据集
我们使用的是来自 Kaggle FIFA 完整球员数据集的 FIFA 2019 和 2020 数据。国际足联完整的球员数据集包含 18k+独特的球员和 100+从国际足联最新版本中提取的属性。它包含:
- CSV 格式的文件。
- 国际足联 2020–18,278 个独特的球员和每个球员的 104 个属性。(测试数据集)
- FIFA 2019–17,770 个独特的球员和每个球员的 104 个属性。(训练数据集)
- 球员位置,在俱乐部和国家队的角色。
- 玩家属性,包括攻击,技能,防守,心态,GK 技能等。
- 球员的个人资料,如国籍,俱乐部,出生日期,工资,薪金等。
数据清理
- 在某些地方,两个数据集具有相同要素的不同数据类型。读取数据字典后,我们将它们同步。
- 有些变量有内置公式,因此我们更正了它们的格式。
- 我们根据字典定义或重复的列删除了*、【索菲法 _id】、【玩家 _url】、【短 _ 姓名】、【长 _ 姓名】、【真实 _ 面孔】、【多比】、【GK _ 潜水】、【GK _ 搬运】、【GK _ 踢腿】、【GK _ 反射】、【GK _ 速度】、【GK _ 定位】和【body_type】,因为它们在我们的分析中没有增加任何有用的影响。*
- 我们将的总体评分转换为两个二元等级,评分> 70(因为许多大俱乐部使用这个门槛)来招募他们的团队球员,并将被视为我们的因变量
探索性数据分析
我们首先考虑了用于执行探索性数据分析的各种有趣的统计数据。
- 单变量统计,如缺失值在整个数据中的百分比,以处理缺失值,连续变量(计数、均值、标准差、最小值、最大值、偏度、峰度、唯一值、缺失值、IQR)及其分布的单变量统计。
- 双变量统计:特征之间的相关性,连续变量的 T 检验和分类变量的卡方检验和 Cramer’s V。
单变量
我们对连续变量进行单变量分析,以了解数据集中不同字段的分布情况。根据我们的观察(均值、标准差、偏度、峰度等。),我们观察到许多关键特征遵循正态分布。此外,四分位间距(IQR)用于使用 Tukey 的方法检测异常值。
对于分类变量,单变量分析包括它们的计数、唯一值、具有最大计数的类别(即,顶部)、它们的频率以及它们缺失值的数量。从分类表中,我们可以看到 player_tags,lended _ from,nation_position,player_traits 有超过 54%的缺失值。用任何有希望的值来估算这些并不容易**。**
双变量
对于连续变量
我们构建了一个相关矩阵,以了解评级和其他解释变量之间的线性关系程度,以及在后面的阶段可以排除哪些变量。我们使用 Python 中的 seaborn 包创建了上面的热图。
T 型测试
我们还进行了 t 检验,以检查等级= 1 时变量的平均值是否与等级= 0 时变量的平均值有显著差异。在这个阶段之后,我们去掉了一些不重要的变量或者与因变量没有任何关系的变量。
用于分类变量
我们进行了卡方检验,以检查因变量评级变量的显著性。下表包含与分类变量相对应的 p 值。在我们的分析中,我们得到了偏好脚并不重要。
为了找到分类变量与因变量之间的相关性,我们应用了克拉默 V 法则。
V 等于卡方的平方根除以样本大小 n 乘以 m,m 是(行— 1)或(列— 1)中较小的一个:V = SQRT(X2/纳米)。
- 释义: V 可视为两个变量之间的关联,以其最大可能变化的百分比表示。V2 是变量之间的均方典型相关。对于 2 乘 2 表,V =基于卡方的关联度量。
- 对称度: V 是对称度。哪个是自变量并不重要。
- 数据等级: V 可能与名义数据或更高的数据一起使用。
- 取值: 取值范围从 0 到 1。
在这个场景中,我们保留了显示自变量和因变量之间良好相关性的列。这些是’俱乐部 _ 新’,‘位置’,‘攻击率’,‘国家’
特征工程:
1。重新分类/输入变量
- 由于 team_jersey_number,nation_jersey_number 实际上不是一个连续变量,我们决定将它们视为分类变量。
- 我们进一步将 team_position 的‘未上场’作为缺失值,并将球员重新分类为防守队员、进攻队员、守门员、休息队员、中场队员、替补队员、未上场队员、,从而将 29 个唯一值减少到 7 个级别。
- 我们推测一个守门员将会有最小值的*、【速度】、【射门】、【传球】、【运球】、【防守】、【体能】*从而赋予这些值。
- 此外,2 个变量— 国籍和俱乐部具有很高的基数。根据它们的数量和事件发生率,我们将它们重新归类为低基数变量。
2。创建变量:
- 从数据中,我们观察到’ player_positions’ 给出了关于玩家的多个游戏位置的想法。因此,我们决定将各个球员在不同场地位置的可用总次数分配到“_ 位置”。
- 一个玩家的 work_rate 是由他的攻防速率给定的;因此,我们把它们分成变量。
- 我们还计算了期限单个球员将与俱乐部相关联,以更好地了解他们对俱乐部的忠诚度。
- 我们还使用了一键编码来利用分类变量,这种形式可以提供给 ML 算法,以便在预测中做得更好。
3。 型号 1
此处,Y =人群事件发生率为 31.23 %的等级(为 1 级)
3.1。 逻辑回归:
对于逻辑回归模型,我们首先在没有正则化的情况下进行分类,然后进行岭和套索回归。L1 正则化逻辑回归需要解决一个凸优化问题。然而,用于解决凸优化问题的标准算法不能很好地处理在许多实际设置中遇到的大型数据集。
应用惩罚以最小化损失函数时逻辑回归的目标:
正则化前后运行逻辑回归模型(L1 和 L2)的最佳结果可总结如下:
3.2。 KNN:
kNN 是一种基于案例的学习方法,它保留所有的训练数据用于分类。不同算法的评价标准之一就是它们的性能。由于 kNN 是一种简单而有效的分类方法,并且作为最有效的方法之一令人信服,这促使我们为 kNN 建立一个模型,以提高其效率,同时保持其分类精度。
参见图 1,训练数据集包括 11 个数据点,分为两类{正方形,三角形},分布在二维数据空间中。如果我们使用欧几里德距离作为我们的相似性度量,则根据局部区域中的距离度量,具有相同类别标签的许多数据点彼此接近。
例如,如果我们用实线圆圈表示 k=3 的区域,并检查类别之间的多数投票,我们观察到我们的数据点{circle}将被分类为三角形。但是,如果我们增加虚线圆表示的 k =5 的值,我们的数据点将被归类为正方形。这促使我们优化我们的k-最近邻算法,以找到分类误差最小的最优 k 。
实验:
我们最初用 k= 1 训练我们的 k- NN 模型,将我们的数据分成 70% -30%作为我们的训练和验证数据。从表 2 中,我们观察到训练精度为 1,这意味着模型完全拟合,然而,测试数据的精度和 AUC 高于验证数据,这表明过度拟合,因此,我们主观地进行参数调整。
优化:
我们利用肘方法找到训练数据的最小误差。在运行了最佳的 *k、*之后,我们观察到当 *k=7、*时观察到最小的错误率。尽管我们的优化结果在训练和验证中表现得更好,但是我们的测试 AUC 已经降低。
尽管测试的准确性降低了,但是我们观察到相同的精确度-召回率增加了,这表明我们的模型更好地分类了更多的类(1 ),因为它是我们的目标类。(评分大于 70 的玩家)。
3.3。** 决策树:
决策树方法是一种用于分类、预测、解释和数据处理的强大的统计工具,在许多领域具有潜在的应用。
使用决策树模型有以下优点:
- 通过将原始输入变量分成重要的子组,简化了输入变量和目标变量之间的复杂关系。
- 没有分布假设的非参数方法,因此易于理解和解释。
主要的缺点是它可能会过拟合和欠拟合,特别是在使用小数据集时。
实验:
我们从 Sklearn 库中训练了决策树分类器,没有传递任何参数。从表中,我们观察到数据过度拟合,因此我们必须调整参数以获得优化的结果。
优化:
我们使用以下参数:
- **条件:**字符串,可选(default=" Gini "):
- max_depth: int 或 None,可选(默认值=None):
树的最大深度。如果没有,则扩展节点,直到所有叶子都是纯的,或者直到所有叶子包含少于 min_samples_split 样本。
- min_samples_split: int,float,可选(默认值=2):
树的最大深度。如果没有,则扩展节点,直到所有叶子都是纯的,或者直到所有叶子包含少于 min_samples_split 样本。
- **最小权重分数叶:**浮点,可选():
要求位于叶节点的权重总和(所有输入样本)的最小加权分数。当未提供 sample_weight 时,样本具有相同的权重
从上面的实验中,我们看到基尼在实验参数的所有变量中都优于熵。因此,我们的标准是基尼。类似地,我们可以观察到其他参数对于 max_depth = 10,min_samples_split = 17.5,Min_weight_fraction_leaf =0, Gini 给出了更高的精度。因此,利用这些参数,我们训练我们的模型来观察没有过度拟合,并且我们可以在类别 1 类别中捕获更多的真实类别。
3.4。 支持向量机:
SVM 的民间观点是,他们找到一个“最优”超平面作为学习问题的解决方案。最简单的 SVM 公式是线性公式,其中超平面位于输入数据 x 的空间中。
在这种情况下,假设空间是以下形式的所有超平面的子集:
f( x ) = w⋅x +b
硬保证金案例:
最大边缘分离超平面的目标是找到:
软保证金案例:
时差变量也是目标函数的一部分:
成本系数 C>0 是一个超参数,它指定了错误分类惩罚,并由用户基于分类任务和数据集特征进行调整。
径向基函数支持向量机
一般来说,RBF 核是合理的首选。该核非线性地将样本映射到更高维的空间中,因此,与线性核不同,它可以处理类别标签和属性之间的关系是非线性的情况。此外,线性核是 RBF 的特例,因为具有罚参数ĉ的线性核与具有某些参数(c,γ)的 RBF 核具有相同的性能。第二个原因是影响模型选择复杂性的超参数的数量。
实验:
我们让我们的训练数据接受线性 SVM 分类器,而不对其进行软边界训练。然而,观察到的结果看起来很有希望,
取得好成绩的原因是数据在大部分时间几乎是线性可分的,很少有错误分类。
优化:
我们决定使用线性径向基函数运行网格搜索,改变 C 和γ来有效地训练我们的模型。通过网格搜索,我们得到了如下的最佳估计量
SVC(C=1,cache_size=200,class_weight=None,coef0=0.0,decision_function_shape='ovr ',degree=3,gamma='auto_deprecated ',kernel='linear ',max_iter=-1,probability=True,random_state=None,shrinking=True,tol=0.001,verbose=False)
对于径向基函数,我们得到了最好的估计
SVC(C=100,cache_size=200,class_weight=None,coef0=0.0,decision_function_shape='ovr ',degree=3,gamma=0.001,kernel='rbf ',max_iter=-1,probability=True,random_state=None,shrinking=True,tol=0.001,verbose=False)
由于泛化误差(期望损失)被用来逼近总体误差,我们观察到 RBF 核模型的误差值是其他模型中最小的。此外,这是我们最好的模型,因为它比其他模型更符合数据。
RBF 核将数据带入更高的无限维空间,这有助于我们的模型脱颖而出。精确召回曲线向我们展示了用 AUC-0.961 预测阳性类别的效果。
4。 模式二:
这里,X 是相同的,包括来自模型 1 的预测评级和 Y =释放条款+52 *工资作为投资者的成本。(52 乘以给定的周工资)。
从前面的单变量和双变量分析中选择重要变量后,我们绘制了自变量和因变量的散点图。
可以清楚地看到,它们遵循一种关系,但它似乎不是线性的。我们通过开发一个线性模型证实了这一点。
4.1。 线性模型:
结果:
r 方形链 0.54
r 平方验证 0.55
r 平方测试 0.54
R 平方是对完美预测接近程度的度量。这里,R 广场不好。
**从残差中检查线性:**数据应该是随机分散的。但是在这里,我们发现它们不是随机的。这意味着线性模型永远不会是适合这个模型的好选择。
4.2。 **决策树:**在这个场景中,这是比线性模型更好的选择。
结果(基线):
训练数据: R 平方— 0.99,RMSE — 0.05
验证数据: R 平方— 0.54,RMSE — 8.05
测试数据: R 平方— 0.59,RMSE — 7.35
有明显的过度合身的迹象。该模型的表现不如预期。因此,我们尝试了基于 min_split、tree_depth 和 min_weight_fraction_leaf 以及学习标准的网格搜索。
如上所示,最小分割=3,最大深度=15 时,熵的性能更好。
网格搜索后的结果:(主模型)
列车数据: R 平方— 0.85,RMSE — 4.40
验证数据: R 平方— 0.69,RMSE — 6.59
测试数据: R 平方— 0.70,RMSE — 6.26
r 平方值现在似乎好得多。RMSE 值也很低,过拟合的问题也得到解决。
因此,为了预测投资者的成本,决策树在这里表现得更好。
最终策略:
最后一步是制定一个为我们团队挑选球员的策略,记住:
- 评级应大于 70(表示 1 级)
- 预算——10 亿欧元,玩家人数约 30 人。
首先,我们只选择评分高于 70 分的玩家。剩余玩家数量— 5276
其次,我们进行了一些分析,如投资者成本的十分位数分析。我们做了一些桶,每个桶有大约 30 名来自剩余池的玩家,并根据投资者的成本按降序排列这些桶。
这里我们可以观察到,从第一桶中挑选全队所需的金额是34.5 亿欧元(超出预算)。这意味着我们不能直接挑选前 30 名球员,从第 11 组中挑选球队所需的金额为9.45 亿欧元(在我们的预算内)。然而,从这个桶中挑选所有的玩家是一个错误的策略,因为我们会留下将近 300 个高价值的玩家。因此,最好的解决方案是从最高级别中挑选 8-10 名核心玩家,其余的从中低级别玩家中挑选。
通过上面的分析可以很容易地做出这个决定,这取决于投资者和球队经理来决定他们的球队需要什么样的球员。
**5。**结论:
在这项工作中,我们构建了两个模型,利用机器学习算法来使投资者受益,同时捕捉有意义地将玩家分类为表现良好的玩家,然后将他们回归到投资者的预算中。结果、分类和回归拟合是一种新的选择模型,用于监督学习表现优于其他团队的球员。最终,我们缩小了俱乐部内球员的选择过程,这比随机选择要好得多。
**未来范围:**我们还可以实现时间序列技术。作为我们的因变量,评级和成本都取决于前几年的数据。例如,如果某个玩家在 2019 年 12 月的评分为 85,那么他在 2010 年 1 月的评分大约为 85 +/- 3。因此,时间序列技术可能对这些数据有用。
参考文献:
- 郭,龚德&王,惠&贝尔,大卫&毕,亚新。(2004).基于 KNN 模型的分类方法。
- 颜人。(2015).决策树方法:分类和预测的应用。
- https://towards data science . com/how-to-tune-a-decision-tree-f 03721801680
- 阿波斯托利斯-阿芬图利斯。(2015).线性核和 RBF 核的 SVM 分类。10.13140/RG
再见,美丽的汤!我如何使用 Python 和 ParseHub 抓取新冠肺炎数据?
意见
用美汤刮数据繁琐!
在使用 Python 抓取网页时,美汤被认为是语言的最佳伴侣。但是,编写数百行代码来抓取一个表格或一个 web 元素会耗费您所有的精力和时间。
这就是为什么我在报废过程中切换到 ParseHub。而且,我在几分钟内就做到了。
使用 ParseHub
从 ParseHub 中选择 web 元素需要 5 分钟。在底层,这个工具开始制作 JSON、CSV 文件供我们提取。此外,我们可以使用他们的 API 来访问数据。这种无代码的交互界面使得捕捉 web 元素和提取所需数据变得更加容易。
获取所有数据后,您可以转到“获取数据”并运行工作流和提取数据。然后,您会发现将文件保存为 CSV、JSON 或使用 API 访问数据的选项。
Python
我已经使用 API 访问了来自 ParseHub 的数据。然后用“json”库加载它来读取数据。
import json
import requests as rq
class Covid:
def __init__(self, api_key, project_token) :
self.api_key = api_key
self.project_token = project_token
self.data = self.get_data()
def get_data(self) :
response = rq.get(f'https://www.parsehub.com/api/v2/projects/{self.project_token}/last_ready_run/data', params={
"api_key" : self.api_key })
data = json.loads(response.text)
return data
加载后,您可以轻松访问所有数据。获取关于冠状病毒的所有信息,如全球总病例数、任何国家的总病例数等。我有构建函数来获得世界上发生的总病例数、总死亡数和总恢复数。除此之外,我还创建了一个函数,返回与每个国家的病例和死亡人数相对应的数据。
def get_total_case(self):
return self.data['total'][0]['value']
def get_total_deaths(self) :
return self.data['total'][1]['value']
def get_total_recovered(self) :
return self.data['total'][2]['value']
def country_data(self,country_name):
data=self.data['country']
for country in data:
if country['name'].lower()==country_name.lower():
return country
您也可以在类中添加其他函数。我只和这些人呆在一起。然后,我创建了该类的一个对象,并调用驻留在其中的方法。
data=Covid('Your API Key','Project Token')
data.get_data()
print("Total Cases:",data.get_total_case())
print("Total Deaths:",data.get_total_deaths())
print("Total recoveries:",data.get_total_recovered())
print(data.country_data("India"))
我试着查了印度的 19 个病例和死亡人数。
如果我不得不使用美丽的汤,这个任务可能会杀了我一两个小时。但是,这个工具节省了我大量的时间和精力。你也应该用这个工具来尝试你的网络抓取实验。
注意安全!讨论和反馈,在 Linkedin 上找我!
拜拜大数据!
意见
每个人过去都说大数据是未来。有错吗?现在呢?
艾蒂安·吉拉尔代在 Unsplash 上拍摄的照片
在我天真无邪的日子里,当我刚刚开始攻读数据科学硕士学位时,任何大数据话题都会让我兴奋地在椅子上扭动身体。我想分一杯羹。我想从无尽的流中分析垃圾,建模,可视化,转化,粉碎它。几年后,“大数据”这个词让我扬起了眉毛,等待着另一场流行词汇和模糊期望的阵雨。是大数据失去了吸引力,还是我变得愤世嫉俗了?
流行语对现实
我最近对流行语过敏。它们被高估了,不再有任何意义。这里有一句话没有告诉你什么:*让我们利用大数据在这个新的数字世界中带来创新。*听起来很酷,当然。然而,现实可能是停留在 Excel 电子表格,挫折和缓慢的计算。
大数据让每个人都兴奋不已,因为它代表了巨大财富的概念(“这将是 huuuuge”,听起来很熟悉吧?)在这里你可以搜索、找到和使用任何对你有价值的东西。我的第一反应是认为“在所有这些数据中,一定有我们肯定想知道的东西”。这可能是真的,但代价是什么呢?
没有合适的基础架构,大数据就什么都不是
处理大量数据需要计算能力、合适的存储和合适的工具来将数据从一个位置移动到另一个位置。瓶颈比你想象的要容易得多。随着云计算平台的出现,计算能力变得越来越便宜、越来越容易获得,云存储的指数级增长、云计算的定期使用甚至是本地服务器的维护都意味着一笔巨大的开支。本世纪关于数据的最大教训是:
虽然某些数据对某个特定的矿商来说像黄金一样有价值,但对另一个矿商来说,这将是对存储空间的巨大浪费。
公司存储这些数据,并选择这些数据以后是否有用,而成本已经花掉了。如果在收集数据之前先确定数据是否有用,会怎么样?
大数据并不总是意味着有趣的数据
垃圾进,垃圾出是数据科学界最重要的一句话。许多被认为是大数据的东西是垃圾,这意味着它是不可靠的、未经清理的数据,需要大量的工作才能使用。有时,在一个非常大的数据集中发现的少量信息不值得花费精力、时间和成本去寻找。
根据 Forrester 的报告,企业中至少有 60%的数据未被使用。
如果将这些未使用数据的存储成本投入到人们真正关心的数据的适当基础架构中,会怎么样?
数据越多总是越好吗?
“把尽可能多的数据扔给人工智能”的时代已经结束了。人们已经意识到,不,不是每一个功能都是有用的(甚至可能是有害的!)而且数据的质量往往比数量更重要。我们希望数据以可靠、一致的方式衡量我们关心的事情。通过了解我们数据的质量,它还允许我们进入一个可解释、负责任和安全的人工智能阶段。
这是(大)实施和(大)更好的基础设施的时代。
我们意识到我们得到了数据。现在,我们需要基础设施来安全地使用它、共享它、分析它,并区分无用的垃圾和有价值的信息。我们还决定,数据和人工智能是为了让世界使用,让世界理解,并承诺两者的质量和可靠性。尽管有些人很难理解这一点,但数据(就像生活中的许多其他事物一样)不需要庞大,它需要可靠。
大数据已死。可靠数据万岁!
听起来没那么性感了,不是吗?
再见了移动网络。你好效率网!
意见
MobileNet 是应用和边缘部署的首选模型。现在它被 EfficientNet Lite 模型家族所取代。
卢克·坦尼斯在 Unsplash 拍摄的照片
如何在处理能力和内存有限的移动和边缘设备上以良好的速度运行复杂的深度学习模型?创建一个以 MobileNetV2 为主干的模型,转换成 Tensorflow Lite,就大功告成了。现在它受到了 EfficientNet Lite 的挑战。请继续阅读,了解 EfficientNet 对 EfficientNet-Lite 的需求,以及如何创建 EfficientNet Lite 模型,我们还将比较这些模型,看看谁更胜一筹。如果你想深入了解 EfficientNet 的架构,你可以阅读下面的文章。
让我们深入了解所有不同高效网络模型的体系结构细节,并找出它们的不同之处…
towardsdatascience.com](/complete-architectural-details-of-all-efficientnet-models-5fd5b736142)
在我开始之前,是的,我无耻地窃取了 Rhea Moutafis 热门文章拜拜 Python 的标题。你好朱莉娅。
Tensorflow Lite 中 EfficientNet 模型的缺点→需要 EfficientNet Lite
最近,我写了一篇文章,将 EfficientNet 与其他预训练的模型进行了比较,如 MobileNetV2、Inception 和 Xception,我想将这些保存的模型转换为 Tensorflow Lite 的对应模型,以查看它们的推理时间如何相互比较。
[## EfficientNet 应该是 goto 预训练模型或…
比较不同预训练模型的时间和准确性,并最终创建一个集成来提高结果。
towardsdatascience.com](/efficientnet-should-be-the-goto-pre-trained-model-or-38f719cbfe60)
在比较模型尺寸之前一切都很好,但在那之后,我震惊了。
比较模型尺寸
为了计算推断时间,我加载并处理了一张图片,对其进行了一百次预测,并取其平均值。
比较模型推理时间
Tensorflow Lite 模型的 MobileNet 推理时间如预期的那样下降了,但 EfficientNet 模型的推理时间增加了!!!Tensorflow Lite 应该使模型更小并减少推理时间!那么为什么会出现这种情况,如何解决呢?这在 EfficientNet Lite 中已得到澄清,根据此文章,它有以下更改:
- 删除挤压和激励网络,因为它们没有得到很好的支持
- 用 RELU6 替换了所有的 swish 激活,这显著提高了训练后量化的质量
- 在放大模型时修复了茎和头,以减少缩放模型的大小和计算
Tensorflow Lite 中的 MobileNet 与 EfficientNet Lite
这些模型将由模型制作者创建,正如其教程中所述
在为设备上的 ML 应用部署 TensorFlow 神经网络模型时,模型生成器库简化了将该模型适配和转换为特定输入数据的过程。
它确实可以做到这一点,并且支持 MobileNetV2、ResNet50 和 EfficientNet Lite 系列的前五种型号。您还可以使用ImageModelSpec
从 Tensorflow Hub 使用不同的模型,或者创建或拥有自定义模型并将 ModelSpec 导出到 Tensorflow Hub,然后使用ImageModelSpec
。
在本文中,我将只结合 MobileNetV2 和 EfficientNet Lite 0 到 4。使用的数据将是带有雏菊、蒲公英、玫瑰、向日葵和郁金香标签的花卉数据集,这些数据将被分成 80%、10%和 10%,分别用于训练、验证和测试。
为此,我们需要 Tensorflow 示例,可以使用以下方式进行 pip 安装:
!pip install -q git+https://github.com/tensorflow/examples.git#egg=tensorflow-examples[model_maker]
然后,我们进行所需的导入,即模型规格、图像分类器、图像分类器的数据加载器、TensorFlow、NumPy 和 Matplotlib。
from tensorflow_examples.lite.model_maker.core.data_util.image_dataloader import ImageClassifierDataLoader
from tensorflow_examples.lite.model_maker.core.task import image_classifier
from tensorflow_examples.lite.model_maker.core.task.model_spec import (mobilenet_v2_spec,
efficientnet_lite0_spec,
efficientnet_lite1_spec,
efficientnet_lite2_spec,
efficientnet_lite3_spec,
efficientnet_lite4_spec)
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
然后我们加载数据,将它分成所需的类别,并使用ImageClassifierDataLoader
类为图像分类器做好准备。可以使用from_folder
方法,它假设不同类别的图像存在于主文件夹的不同子文件夹中,子文件夹的名称是类别名称。确保图像具有 PNG 或 JPG 扩展名,因为只有它们受支持。
image_path = tf.keras.utils.get_file('flower_photos',
'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz', untar=True)data = ImageClassifierDataLoader.from_folder(image_path)
train_data, rest_data = data.split(0.8)
validation_data, test_data = rest_data.split(0.5)
让我们看看我们的数据
资料组
现在用 model-maker 创建模型是一行程序。
model = image_classifier.create(train_data, model_spec=model_spec, epochs=epochs, validation_data=validation_data)
指定您想要的型号规格,对于 MobileNetV2 是mobilenet_v2_spec
,对于 EfficientNet Lite-2 是efficientnet_lite2_spec
,如导入中所述。如果没有指定,EfficientNet Lite-0 是默认的。我每个人都训练了 15 个时期,下面是结果。
所有模型的训练和验证准确性和损失
令人惊讶的是,EfficientNet Lite-4 在测试和训练集上的表现都很差,但这可能只是意味着它需要更多的训练时期。验证集上表现最差的是 MobileNet,其他 EfficientNet 模型彼此接近,EfficientNet Lite-2 和 EfficientNet Lite-3 以最高的准确度分享战利品。
要转换这些模型并将其保存为 Tensorflow Lite 文件,请编写
model.export(export_dir='.')
这将保存一个 label.txt 和一个 model.tflite 文件。通过创建一个解释器,可以像普通的 tflite 模型一样使用这些模型。
# Read TensorFlow Lite model from TensorFlow Lite file.
with tf.io.gfile.GFile('model.tflite', 'rb') as f:
model_content = f.read()
# Read label names from label file.
with tf.io.gfile.GFile('labels.txt', 'r') as f:
label_names = f.read().split('\n')
# Initialze TensorFlow Lite inpterpreter.
interpreter = tf.lite.Interpreter(model_content=model_content)
interpreter.allocate_tensors()
input_index = interpreter.get_input_details()[0]['index']
output = interpreter.tensor(interpreter.get_output_details()[0]["index"])
# Run predictions on each test image data and calculate accuracy.
accurate_count = 0
for i, (image, label) in enumerate(test_data.dataset):
# Pre-processing should remain the same. Currently, just normalize each pixel value and resize image according to the model's specification.
image, _ = model.preprocess(image, label)
# Add batch dimension and convert to float32 to match with the model's input
# data format.
image = tf.expand_dims(image, 0).numpy()
# Run inference.
interpreter.set_tensor(input_index, image)
interpreter.invoke()
# Post-processing: remove batch dimension and find the label with highest
# probability.
predict_label = np.argmax(output()[0])
# Get label name with label index.
predict_label_name = label_names[predict_label]
accurate_count += (predict_label == label.numpy())
accuracy = accurate_count * 1.0 / test_data.size
print('TensorFlow Lite model accuracy = %.3f' % accuracy)
模型的大小,测试的准确性,以及推断时间(也是 100 次的平均值)都被记录了下来。
结果
所以结果很明显。如果模型大小和推理时间比准确性更重要,那么只使用 MobileNetV2,否则 EfficientNet Lite 系列应该是您的首选模型,尤其是 EfficientNet Lite-0 可以作为 MobileNetV2 的直接替代品。
再见了蟒蛇。你好朱莉娅。
意见
随着 Python 的寿命逐渐停止,一个热门的新竞争者正在出现
如果朱莉娅对你来说还是个谜,别担心。茱莉亚·凯撒在 Unsplash 上的照片
D 别误会。Python 的流行仍然受到计算机科学家、数据科学家和人工智能专家组成的坚如磐石的社区的支持。
但是如果你曾经和这些人共进晚餐,你也会知道他们对 Python 的弱点有多不满。从速度慢到需要过多的测试,到不顾之前的测试而产生运行时错误——有足够多的事情让我们恼火。
这就是为什么越来越多的程序员采用其他语言的原因——顶尖高手是 Julia、Go 和 Rust。Julia 非常适合数学和技术任务,而 Go 非常适合模块化程序,Rust 是系统编程的首选。
由于数据科学家和人工智能专家处理大量的数学问题,朱莉娅是他们的赢家。即使经过严格的审查,Julia 也有 Python 无法超越的优点。
尽管未来几年对它的需求量会很大
towardsdatascience.com](/why-python-is-not-the-programming-language-of-the-future-30ddc5339b66)
蟒蛇的禅与朱莉娅的贪婪
当人们创造一种新的编程语言时,他们这样做是因为他们想保留旧语言的优点,并修正不好的地方。
从这个意义上说,吉多·范·罗苏姆在 20 世纪 80 年代末创造了 Python 来改进 ABC。后者对于一门编程语言来说太完美了——虽然它的刚性使它易于教授,但在现实生活中却很难使用。
相比之下,Python 还是比较务实的。你可以在 Python 的禅中看到这一点,它反映了创作者的意图:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
[...]
Python 仍然保留了 ABC 的良好特性:例如可读性、简单性和初学者友好性。但是 Python 比 ABC 更健壮,更适应现实生活。
ABC 为 Python 做了铺垫,Python 也在为 Julia 做铺垫。戴维·巴洛在 Unsplash 上拍摄的照片
从同样的意义上讲,Julia 的创造者希望保留其他语言中好的部分,抛弃不好的部分。但是 Julia 更有野心:它不是要取代一种语言,而是要打败所有的语言。
这是《T4》中朱莉娅的创作者 T5 所说的:
We are greedy: we want more.We want a language that's open source, with a liberal license. We want the speed of C with the dynamism of Ruby. We want a language that's homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab. We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell. Something that is dirt simple to learn, yet keeps the most serious hackers happy. We want it interactive and we want it compiled.
Julia 希望融合当前存在的所有优点,而不是用其他语言的缺点来交换它们。尽管 Julia 是一种年轻的语言,但它已经实现了创造者设定的许多目标。
Julia 开发者喜欢什么
多才多艺
Julia 可以用于从简单的机器学习应用到巨大的超级计算机模拟的任何事情。在某种程度上,Python 也可以做到这一点——但是 Python 不知何故成了这项工作的一部分。
相比之下,朱莉娅就是为了这种东西而生的。自下而上。
速度
Julia 的创造者想创造一种和 C 一样快的语言,但是他们创造的比 C 更快。即使 Python 在近几年变得更容易加速,但它的性能和 Julia 能做到的还是相差甚远。
2017 年,朱莉娅甚至加入了 Petaflop 俱乐部——这个小型语言俱乐部的速度在峰值性能时可以超过每秒 1 Petaflop。除了 Julia,现在只有 C、C++和 Fortran 在俱乐部里。
每一步的微小进步,整体的巨大飞跃
towardsdatascience.com](/ten-tricks-to-speed-up-your-python-codes-c38abdb89f18)
社区
拥有 30 多年历史的 Python 拥有一个庞大的支持性社区。几乎没有一个与 Python 相关的问题是你在一次谷歌搜索中得不到答案的。
相比之下,朱莉娅社区非常小。虽然这意味着你可能需要进一步挖掘才能找到答案,但你可能会一次又一次地与相同的人联系。这可能会转化为程序员关系,而这种关系是没有价值的。
代码转换
你甚至不需要知道一个 Julia 命令来用 Julia 编码。不仅可以在 Julia 中使用 Python 和 C 代码。你甚至可以在 Python 中使用 Julia!
不用说,这使得修补 Python 代码的弱点变得极其容易。或者在了解 Julia 的同时保持高效率。
库仍然是 Python 的强项。苏珊尹在 Unsplash 上的照片
图书馆
这是 Python 的最大优势之一——它有无数维护良好的库。Julia 没有很多图书馆,用户抱怨说它们没有得到很好的维护。
但是当你考虑到 Julia 是一种资源有限的非常年轻的语言时,他们已经拥有的库的数量是相当可观的。除了 Julia 的函数库数量在增长这一事实之外,它还可以与 C 和 Fortran 的函数库进行接口,以处理绘图等问题。
动态和静态类型
Python 是 100%动态类型化的。这意味着程序在运行时决定一个变量是浮点数还是整数。
虽然这对初学者来说非常友好,但它也引入了大量可能的错误。这意味着您需要在所有可能的场景中测试 Python 代码——这是一项相当耗时的愚蠢任务。
因为 Julia 的创建者也希望它易于学习,所以 Julia 完全支持动态类型。但是与 Python 不同的是,如果你愿意,你可以引入静态类型——例如,以它们在 C 或 Fortran 中存在的方式。
这可以节省您大量的时间:您可以在任何有意义的地方指定类型,而不是为不测试代码找借口。
为什么 Julia 比 Python 更适合 DS/ML
towardsdatascience.com](/5-ways-julia-is-better-than-python-334cc66d64ae)
数据:在东西小的时候投资
在 StackOverflow 上标记为 Julia(左)和 Python(右)的问题数量。
虽然所有这些事情听起来都很棒,但重要的是要记住,与 Python 相比,Julia 仍然微不足道。
一个很好的指标是 StackOverflow 上的问题数量:此时,Python 被标记的次数比 Julia 多 20 次!
这并不意味着 Julia 不受欢迎——相反,被程序员接受自然需要一些时间。
想一想——你真的想用另一种语言编写你的全部代码吗?不,你宁愿在未来的项目中尝试一门新语言。这造成了每种编程语言在发布和采用之间都会面临的时间延迟。
但是如果你现在采用它——这很容易,因为 Julia 允许大量的语言转换——你就是在投资未来。随着越来越多的人收养朱莉娅,你已经获得了足够的经验来回答他们的问题。此外,随着越来越多的 Python 代码被 Julia 取代,您的代码将更加持久。
是时候给朱莉娅一些爱了。亚历山大·辛恩在 Unsplash 上的照片
底线:做朱莉娅,让它成为你的优势
四十年前,人工智能只不过是一种小众现象。行业和投资者不相信它,许多技术都很笨重,难以使用。但是那些在那时学到这一点的人是今天的巨人——那些需求如此之高以至于他们的工资与一名 NFL 球员的工资相当的人。
同样,朱莉娅现在也还是很小众的。但当它成长时,最大的赢家将是那些早期采用它的人。
我不是说如果你现在收养朱莉娅,十年后你一定会赚很多钱。但是你增加了你的机会。
想想看:大多数程序员的简历上都有 Python。在接下来的几年里,我们会在就业市场上看到更多的 Python 程序员。但是如果企业对 Python 的需求放缓,Python 程序员的前景将会黯淡。一开始很慢,但不可避免。
另一方面,如果你能把朱莉娅写进简历,你就有了真正的优势。因为说实话,是什么让你和其他的毕达哥尼亚大师有所不同呢?不多。但是,即使在三年后,也不会有那么多 Julia 程序员了。
有了朱莉娅-斯奇尔斯,你不仅展示了你对工作要求之外的兴趣。你也证明了你渴望学习,你对成为一名程序员有更广泛的理解。换句话说,你适合这份工作。
你和其他 Julia 程序员是未来的摇滚明星,你知道的。或者,正如朱莉娅的创作者们在 2012 年所说的:
Even though we recognize that we are inexcusably greedy, we still want to have it all. About two and a half years ago, we set out to create the language of our greed. It's not complete, but it's time for a 1.0 release — the language we've created is called [Julia](https://julialang.org/). It already delivers on 90% of our ungracious demands, and now it needs the ungracious demands of others to shape it further. So, if you are also a greedy, unreasonable, demanding programmer, we want you to give it a try.
Python 仍然非常受欢迎。但是如果你现在学习茱莉亚,那可能是你以后的金奖券。从这个意义上说:再见 Python。你好朱莉娅。
编辑:我做了一个关于 Julia 和 Python 的演讲!由 Hatchpad 主持,视频为 此处 。
BYOL:带来你自己的损失
我们如何用客户损失函数改进交货时间估计
亲爱的鉴赏家们,我邀请你们去看一看 Careem 的送餐平台。具体来说,我们将看看我们如何使用机器学习来改善交付时间跟踪的客户体验。
简介
计划一顿饭时,时机至关重要。这就是为什么我们非常小心地估计订单的交货时间。然而,交付时间取决于几个复杂的因素——出于这个原因,机器学习是预测预计到达时间的正确选择。
Careem 的食品交付平台界面,用于交付时间估算
乍一看,这只是一个典型的回归问题:获取一些功能,根据历史交付时间训练一个合理的模型以最小化 RMSE,使用合适的交叉验证策略估计平均误差的预期下降,并与领导层分享,部署,广泛宣布,并获得尊重,信任,晋升…
在这篇文章中,我将尝试解释这种方法的错误。我将描述我们对这个问题的解决方案以及我们衡量用户影响的方式。然后,我将向您展示我们如何构建一个自定义损失函数来更好地优化用户订单满意度。
有什么问题吗
- 训练你的模特对抗 RMSE 。RMSE、梅、胡伯等损失是大多数回归问题的典型选择。然而,这些损失反映了我们客户的感受吗?最大的问题是它们是对称的——它们不能区分提前 20 分钟或晚 20 分钟送达的订单。我的直觉肯定能看出区别…如果我们的模特表现出更多一点的同理心,那就太酷了。
- 通过平均误差评估成功。 又来了。想象一下,您的团队已经努力工作了一个月,用其昂贵的基础设施设置实时交通数据流,以获得减少错误的功能,现在,它最终从平均 3 分钟下降到 2.5 分钟!20%的涨幅,什么结果!这绝对值得…是吗?实际上很难说,这在很大程度上取决于一个特定的问题。对于我们和许多其他应用程序来说,客户很可能甚至不会注意到这种变化。
- 获得尊重、信任、晋升。
这个挺简单的!工作是为了乐趣,而不是为了升职!
那么,我们该怎么办?
免责声明:出于法律原因,此处显示的所有数据都是合成的,但它是以代表真实行为的方式构建的。
目标分布
让我们从找到衡量成功的方法开始。在某些情况下,测量 MAE 是有意义的。然而,在交货时间估计的情况下,这在很大程度上是没有意义的。它没有告诉我们对客户有什么影响。
我们关心的是客户体验。你关心的是对你的客户体验的影响,这可以通过多种方式来衡量:交付率、流失率、保留率、LTV、呼叫中心联系率、NPS 评分。例如,在 Careem,我们使用反映业务状态的呼叫中心联系率、流失率、交付时间和交付评级的加权组合。
问题是这些很难优化。因此,数据科学家经常求助于 RMSE、梅、胡伯等作为代理人。然后只在部署后测试真实的用户影响。
让我们假设我们项目的目标是提高平均交付率。我们需要了解我们的模型将对交付 ratting 产生什么影响。做到这一点的一个方法是查看历史交付时间估计,并查看当出现各种交付时间错误时,客户评级会发生什么变化。下面我们看到一个图表,显示了平均行程等级,显示的交付时间误差估计中不同程度的误差:
左图是 Careem 的反馈页面,订单完成后发送。在右图中,根据交货时间估计经验,给出了每个仲裁箱的平均等级(见免责声明)
有许多直观的见解:
- 人们喜欢准时或早一点得到食物
- 如果送货时间过长,你会感到失望
- 不要对过早得到食物感到太兴奋,但是仍然,感觉它比延迟交付更积极
如果食物晚送了 22 分钟以上,那么分数应该在 1.9 分左右(见顶部的免责声明)。利用这一点,我们有一个清晰的方法将我们的交货时间误差转化为对订货周转时间的估计。然后在一个验证数据集上,当使用我们的模型时,我们能够估计旅行的预期平均评级。因此,我们找到了一种为我们的模型评估有意义的度量的方法。
查看图表,同样重要的是要强调,最佳模型不一定是 MAE 等于 0 的模型。如果我有一个完美的模型,我可能会将预测稍微向左移动一点,以确保我们做顾客最喜欢的事情——比我们最初承诺的时间提前几分钟交付食物。
好了,回到正轨,我们的目标已经确定。
典型解决方案
一个非常合理的下一步是针对这个目标运行您最喜欢的超参数优化算法。对于下面的图,我们针对这个目标在 120 次迭代中使用 RMSE 损失来调整 Catboost。我们先来比较一下这两位会把我们带向何方。
在左图中,有一个对 120 回合 HPO 的评估,当时 RMSE 既用了客观又用了失败。在右图中,针对 RMSE 进行了优化,但评估是使用评级目标进行的。
不伟大,也不可怕。这是一个小小的改进,但它是免费的。此外,现在,你对你的工作的潜在影响有了更好的理解,而不是说“新的实施将交付时间估计提高了 U%”,你会添加一个微小而重要的后缀:“…预计将带来大约 K 星的评级提高”,或“保留率提高了 P%,或“收入增加了 H%,或“人们微笑的次数增加了 28%”。
定制损失函数
当然,这不是我们能做的全部。是的,我们提高了一点分数,但是仍然面临着 RMSE 对称性的问题。想出一个自定义损失函数是相当常见的,尤其是在各种深度学习领域。我喜欢这个帖子,它很好地总结了高级损失函数。
但令人惊讶的是,经典的机器学习应用程序并没有广泛采用损失函数定制,尽管它们有时肯定会从中受益。让我们考虑一个围绕 MSE 的通用形式调整:
函数 g 可以像数据科学家幻想的那样复杂,只要你的应用从中受益……而且函数 g 有某种形式的导数。但是,即使不深入兔子洞,我们也可以挑选最简单的误差 g 步函数:
在这种情况下, g 只不过是一个动态权重,它是根据误差为每个对象选择的。姑且称之为分段 MSE 吧。最明显的参数选择是使它们与每个错误的等级成比例。这样,模型会比早期交付更努力地避免延迟交付,变得不那么乐观。
那么,没有什么比计算预测的一阶和二阶导数更容易的了:
这就是我们在您最喜欢的梯度推进实施之上运行所需的全部内容,并具有广泛的超参数优化
左图显示了与每个篮子的预期评级成比例的损失函数形状。右图显示了超参数优化目标(评级)
我们在与香草 RMSE 的比赛中取得了一点成绩,但前面还有很长的路要走。事实是,我们新的损失函数形状不是最优的,即使它看起来像。
考虑一个简单的例子。数据集有一个异常对象,它完全是凭空出现的:一个快递员(我们称他们为队长)的自行车在距离目的地仅一个街区的地方坏了,送货花了 3 个小时。您的数据集中没有可以帮助区分这种特殊情况的要素,而且很可能该对象会损害整体算法的性能。如果损失函数不太关注异常值,那就更好了。
反对这种固定客户损失的第二个理由是优化。机器学习中的大多数模型都是通过某种形式的梯度下降来优化的。在这个顺序的(而且往往是随机的)过程中,任何变化:不同的初始化、学习速率、批量洗牌都会导致不同的结果。因此,正如我们改变采用不同数据集的模型的学习率一样,调整损失函数的系数可能有助于提高性能。
损失函数选择的自动化
遗憾的是,我们无法做出模型的 c_k 参数。但是让它们成为超参数并不太坏。现在,在其他模型的参数中(我使用的是 Catboost ),我们将使用相同的超参数优化程序来调整 c_k。
左图显示了一系列考虑的损失函数(五分位数损失)。右图显示了超参数优化目标(评级)
现在,分数明显更高了。毫不奇怪。这是因为损失是为这个特定问题和这个特定数据集定制的。
此外,通过这种设置,HPO 直接(嗯,几乎)优化了您关心的指标——平均预期评级,而不是抽象的和业务不可知的 MSE。
下一个图显示了我们的赢家损失函数的形状,它是在第 151 次迭代中发现的。
分段均方误差的最佳损失。是由 HPO 程序与 240 轮选择。
误差低于 18 的地方看起来到处都是倾斜的 MSE。然后,它将误差大于 18 的对象去优先级化。看着上面的柱状图,它可能看起来是反直觉的:18 分钟的误差预计是最需要避免的!
但我们不应该忘记,HPO 过程不仅着眼于柱状图,而且整体考虑数据集、模型性能、模型的其他超参数和目标的组合。可能没有一个物体的模型会犯如此大的错误。因此,相反,它专注于将物体从篮 11–18移动到篮 5–11。或者,这种行为可能有其他原因。因此,损失函数形状不必是直观的,以便提供最好的分数。当综合考虑所有因素时,这个损失函数在这个特定的背景下是不成立的。
又一次海关损失
所以,我们已经取得了很大的进步。让我们再做一点小小的改变。先前的损失函数通过缩放 RSE 来修改它。很好,但是不够灵活。向前迈进了一步,通过增加一个偏差来概括它:
然后,我们称之为有偏分段 MSE。
同样,我们执行 HPO 的相同操作,但是现在与我们的 c 和 b 一起运行,与算法的其余超参数一起运行。
左图显示了一系列考虑的损失函数(有偏差的分段 MSE 损失)。右图显示了超参数优化目标(评级)
最好的分数是我们以前最好成绩的又一次增加。新获得的定制损失的形状看起来更像弗兰肯斯坦,但仍然很漂亮。
有偏分段均方误差的最佳损失。是通过 HPO 程序用 360 轮选出来的。
其他损失
上面将定制的可调物镜与 RMSE 进行了比较,尽管后者是最广泛采用的一种物镜,但对于当前应用来说,它有一个主要缺点—它是对称的。但是还有其他类型的非对称损失函数。一个流行的例子是五分位数损失。我们要把这个和我们的分段函数进行比较。同样,它的主要参数α将被视为超参数,与之前实验中的方式相同。
左图显示了一系列考虑的损失函数(五分位数损失)。右图显示了超参数优化目标(评级)
分位数回归的结果比任何以前调整过的 RMSE 要好,但是仍然会因调整过的分段损失而损失很大。
值得注意的是,除了损耗特定参数外,上述所有实验都使用了相同的超参数集。此外,对于模型的超参数的数量增加的 HPO 运行,迭代的数量也增加以说明这一点(例如,对于分段需要 7 个额外的超参数,而对于有偏差的分段 MSE 有 14 个额外的超参数)。
基于模型的目标
事实是,这里我们已经使用了一个非常简单的方法来评估预期评级,但是没有什么(几乎没有什么)阻止你使用一个复杂的 ML 模型来评估你的目标。比方说,你想把客户流失降到最低,而客户流失取决于配送时间误差。答对了。这是完美的婚姻,尤其是当客户流失模型已经开发出来的时候。唯一的问题可能是,整个训练变得非常慢,但是在很多应用中,这根本不是一个限制。
非凸物镜
在这个特殊的例子中,我们的主要度量评级几乎是凸的,这就是为什么即使 RMSE,五分之一正在失去,差距不是那么大。例如,如果我们的交付时间经验分布看起来更像下图中的分布,分段损失的边际收益将显著增加。在 链接 部分,你将可以找到一个笔记本,在它周围玩耍。
取决于交付时间估计经验的平均评级示例。
结论
损失函数只受你的幻想和你的计算能力的限制,而且通常来说,实现和调整一个定制的损失函数实际上是有益的。
一览表
尽管这些特定的价值是合成的,但我们的生产设置以非常相似的方式工作,该模型在我们平台上的实际影响是极好的:我们已经将超过 25%的订单转移到交付时间体验更好的篮子中。它不仅帮助我们更好地理解什么是重要的以及为什么重要,而且它也为我们的客户带来了很好的体验(我们知道它变得有多好!).
链接
与文章相关的代码位于数据集的中(见免责声明)。
此外,如果有人想使用任何损失函数,你可以安装这个小的库(顺便说一句,它对任何贡献都非常开放)。
绕过熊猫的记忆限制
我如何简化我的 ETL 管道
V-Yan 在 Shutterstock 上的照片
当你遇到一组新的数据时,你需要花一些时间去了解它。这个过程就像第一次见到一个陌生人一样。而不是问“你叫什么名字?”,“你是哪里人?”,以及“凯蒂·佩里还是泰勒·斯威夫特?”你问“你的分布是什么样的?”,“您是否包含任何缺失或意外的数据?”,以及“您如何与其他数据相关联?”。
一个典型的数据科学家一天要花 80%的时间来准备要处理的数据。像熊猫这样的工具通过增加一套强大的功能来探索和管理数据,使得这个过程更加高效。熊猫可以将一个普通的 CSV 文件转换成有洞察力的聚合和图表。再加上熊猫的头号特点就是让我出不了 Excel。
然而,熊猫并不全是玫瑰和阳光。由于数据帧(熊猫的基础)保存在内存中,一次可以处理多少数据是有限制的。当试图将纽约出租车数据(10 亿多行和 10 年的信息)的大小打包到 Pandas 中时,分析数据集可能会导致内存不足异常。大多数熊猫相关教程只使用 6 个月的数据来避免这种情况。
克服记忆极限
在 Pandas 中处理大量数据(太大而不适合内存)需要以下方法之一:
- 将数据分成易于管理的部分(分块)。
- 使用 Pandas 之外的服务来处理数据的过滤和聚合。
- 以上两种方法的结合。
Apache 项目 Spark 和 Arrow 旨在提供处理大数据的解决方案,但我发现安装和使用数据库是 Arrow 和 Spark 带来的复杂性的无痛替代方案。最近,我偶然发现了开源项目 QuestDB ,它声称在时序数据库领域具有高性能,所以我决定尝试一下。
QuestDB 的 REST API 使用一种我已经熟悉的查询语言接受请求:SQL。如果需要的话,可以对结果进行分页,但是也可以将它们过滤成对熊猫的内存更友好的大小。虽然性能分析不是这篇文章的主要目标,但是通过 QuestDB 的 SIMD 指令和高性能设计,处理速度也有所提高。
与常见的 ETL 方法相比,在数据管道中加入像 QuestDB 这样的数据库有一些优势(如下图所示):
- 查询数据集的动态方式。
- 降低了过滤和聚合的复杂性。
- 缩短从原始数据到熊猫的路径。
在之前(使用 ETL 工作流)和之后(使用 QuestDB)处理大型数据集的过程。作者图片
使用 QuestDB
对于下面所有的例子,我使用一个简单的函数来查询 QuestDB 并将结果转换成 Pandas 数据帧。
import pandas as pd
import requests defread_questdb(query, host, per_page = 10000, max_records = None):"""
Sends a SQL query to a specified host.
Parameters
----------------
query : string
A SQL query
host : string
A host location in the form of a URL. [http://host:port](http://host:port)
per_page : int
The limit of results to return per page.
max_records : int
The maximum amount of records to return (soft limit).
"""data = []
offset = 1
page = 1
get_more = True
columns = None
params = {"query": query, "limit": f"{offset},{per_page * page}","count": "true"}
while get_more:
r = requests.get(f"{host}exec", params=params)
jsond = r.json()
if r.status_code != 200:
raise ValueError(jsond['error'])
if not columns:
columns = [x['name'] for x in jsond['columns']]
if jsond['dataset'] != []:
data = data + jsond['dataset']
if jsond["count"] < (per_page * page) or (max_records != None and (per_page*page) >= max_records):
get_more = False
else:
offset = (per_page * page) + 1
page += 1
params['limit'] = f"{offset},{per_page * page}"
params['nm'] = 'true'
return pd.DataFrame(data=data, columns=columns)
对于数据,我已经预加载了纽约出租车数据集,该数据集从 2009 年到 2019 年有 1,636,055,518 行数据。列定义可在 nyc.gov 的网站上获得。
文档中有更多关于安装 QuestDB 以及如何加载数据的信息。
了解出租车数据集
先从分析 fare_amount 开始。在我的 Macbook Pro 上不可能将 16 亿行数据存储到 Pandas 中,所以我需要使用 QuestDB 来帮助我将数据压缩到更易于管理的大小。
平均票价是多少?
query = "SELECT avg(fare_amount) FROM trips"
avg_df = read_questdb(query, hostname)
avg_df['avg'][0]
>>>11.771664413356518
我也很好奇 fare_amount 和 passenger_count 有什么关系。较大的团体倾向于长途旅行吗?以下是按乘客数量划分的平均票价图。
query = "SELECT passenger_count, avg(fare_amount) FROM trips"
df = read_questdb(query, hostname)
ax = df.plot.bar(x='passenger_count', y='avg', title='Average Fare by Passenger Count', label='Passenger Count')
ax.legend(["Avg Fare Amount ($)"])
#add a horizontal line for the average
ax.axhline(y=avg_df['avg'][0], color='red')
passenger_count 为 0 对我来说不合适,虽然这可能有一个很好的原因,但我现在将从数据帧中删除该数据,并对数据进行排序和重新索引。
#drop zero passenger count data and set index and sort values
df = df.drop([6]).set_index('passenger_count').sort_values('passenger_count')#change to integers
df.index = df.index.astype('int64')#don't need to specify x axis
ax = df.plot.bar(y='avg', title='Average Fare by Passenger Count', label='Passenger Count')
ax.legend(["Avg Fare Amount ($)"])
ax.axhline(y=avg_df['avg'][0], color='red')>>>avg1 11.548458
2 12.119514
3 11.892298
4 12.091368
5 11.466198
6 12.276963
7 31.622068
现在,乘客计数按升序排列,0 乘客计数列已删除,我可以看到不同乘客计数的平均值与数据集平均值一致,只有乘客计数为 7 除外。
由于我已经将目标数据集缩小到 passenger_count 为 7 的行,所以我可以将目标行放入 Pandas 数据框架中,并使用“describe”函数来获得 fare_amount 分布的概况。
query = "select * from trips where passenger_count = 7"
df7 = read_questdb(query, hostname)
df7['fare_amount'].describe()
>>>
count 1494.000000
mean 31.622068
std 31.708050
min 0.010000
25% 7.000000
50% 12.000000
75% 70.000000
max 373.000000
Name: fare_amount, dtype: float64
该输出的三个初步观察结果:
- 标准差大于平均值。既然票价不可能是负数,那就意味着数据严重失真。
- 最小值为 0.01。我不是出租车的常客,但我很确定一旦打开计价器,起价会超过 0.01 美元。
- 最大值为 373。异常值可能会对平均值施加压力。
我可以画出数据的分布。
ax = df7['fare_amount'].plot.hist()
正如预期的那样,分布严重偏斜,一些较大的异常值将平均值拉得更高。但是这告诉我们什么呢?所有其他的乘客数量也是如此吗?我应该改用中间值而不是平均值吗?还能对这些数据提出什么问题?
换个话题,我很想知道每小时的平均费用是如何随着时间的推移而变化的。我可以使用 QuestDB 中的抽样来帮助组织每月时段中的 fare_amount 平均值。
query = """
SELECT pickup_datetime, avg(fare_amount) / (avg(cast((dropoff_datetime-pickup_datetime) as long)) / 1000000 / 60 / 60) fare_hr FROM trips SAMPLE BY 1M;
"""
fare_change_df = read_questdb(query,hostname)
fare_change_df['pickup_datetime'] = pd.to_datetime(fare_change_df['pickup_datetime'])
ax = fare_change_df[:125].plot(x='pickup_datetime',y='fare_hr')
这张图表产生了新的问题。为什么 2012 年 fare_amount 会暴涨?是什么导致了 2015 年的跳水?平均每小时工资在稳步下降;什么因素会导致这种情况?
结论
要让我对出租车数据感到放心,还有很长的路要走。我只触及了单个列的表面,还有关于其他列以及这些列之间的关系的无限量的附加问题。每个回答的问题都会引出更多的问题。
Pandas 是 Python 数据科学堆栈中比较重要的库之一,但是随着数据量的增长,完全在 Pandas 中工作需要额外工具的帮助。我喜欢使用 QuestDB 来执行大容量过滤、聚合和分组操作,以扩展 Pandas 的效用。
[1]吉尔出版社,清理大数据:最耗时,最不愉快的数据科学任务,调查称(2016),福布斯
面向 Pythonistas 和数据科学家的 C++
《依附入门》有助于学习 C++
图片取自https://negativespace.co/。
当我在大学学习数学的时候,我在一个统计模块中接触到了 Python 和 R。从那以后,我只坚持使用这两种语言,只在需要的时候涉足其他语言。
最近,我想提高我的编程基础,并了解更多关于我们数据科学家对 Python 和 R 习以为常的底层概念,同时也想找到一些方法来改进我的工作流。所以我接受了学习 C++的挑战,这样做让我发现了依附。
坚持
Cling 是一个交互式的 C++解释器,有助于提供类似于用 Python 编码的体验。这给我的 C++学习经历带来了巨大的好处,我相信它也能帮助许多其他人。
你好,世界!
Hello,World 的基本 C++程序!对于 Python 用户来说可能是令人畏惧和不快的。下面是一个例子:
#include <iostream>int main() {
std::cout << “Hello, World!” << std::endl;
return 0;
}
一旦编写完成,程序就可以被编译(如果没有错误),然后运行以查看输出。
下面是相同的,但是当使用附着解释器时:
#include <iostream>
std::cout << “Hello, World”! << std::endl;
不需要编译!
这是一个非常简单的例子,但是使用 Cling 可以让你以一种互动的方式探索 C++函数、向量等等,让你做更多的实验。
例如,为了试验向量,你可以使用解释器来帮助学习函数和语法。
#include <vector>
vector<int> data;data.push_back(1);
data.push_back(2)
// return the vector to see what happened
data;
Jupyter 笔记本
还有一个 Jupyter 内核,它可以使学习更加互动,同时还可以帮助您学习如何在数据科学流程中展示您的工作。
装置
安装非常简单,使用 Conda 即可完成:
conda install -c conda-forge cling
要获得 Jupyter 内核,还需要安装“xeus-cling ”:
conda install xeus-cling -c conda-forge
设置 Jupyter 笔记本
正常运行Jupyter Notebook
,然后选择一个 C++内核,如下图所示:
结束语
解释 C++并不是最终的解决方案,像这样使用 C++意味着你失去了这种语言的很多能力。但是,作为一种学习工具,依附是非常宝贵的,如果你已经有了一些其他语言的基础,它可以帮助你加快学习进程。
相关的代码和笔记本可以在我的 GitHub 上获得,这也包括代码启动代码来导入一个简单的单列 CSV。
c 代表分类
分类和回归问题之间的区别的简要概述。
Alexander Schimmeck 在 Unsplash 上的照片
什么是分类?
分类是两种类型的监督机器学习任务(即我们有一个标记数据集的任务)之一,另一种是回归。
需要记住的要点:监督学习任务使用特征来预测目标,或者,用非技术术语来说,它们使用属性/特征来预测某些东西。例如,我们可以通过篮球运动员的身高、体重、年龄、脚步速度和/或其他多个方面来预测他们会得多少分或者他们是否会成为全明星。
那么这两者有什么区别呢?
- 回归任务预测一个连续的值(即某人将得到多少分)
- 分类任务预测一个非连续值(即某人是否会成为全明星)
我如何知道使用哪种技术?
回答以下问题:
“我的目标变量有顺序吗?”
例如,我预测读者推荐年龄的项目是一个回归任务,因为我预测的是一个精确的年龄(例如,4 岁)。如果我试图确定一本书是否适合青少年,那么这将是一项分类任务,因为答案可能是“是”或“否”。
好吧,所以分类只针对是/否,对/错,猫/狗问题,对吧?
不,这些只是简单的例子😄
示例 1:将人员分组
想象一下这样一个场景,你每年都有一批新学生,你必须根据他们的性格特征把他们分门别类。
照片由em recan ark在 Unsplash 上拍摄
在这种情况下,房屋没有任何类型的顺序/等级。当然,哈利肯定不想被安置在斯莱特林,分院帽显然考虑到了这一点,但这并不意味着斯莱特林更接近格兰芬多,就像 25 更接近 30 而不是 19 一样。
示例 2:应用标签
类似地,如果我们有一个包含菜肴成分的数据集,并试图预测原产地,我们将解决一个分类问题。为什么?因为国家名称没有数字顺序。我们可以说俄罗斯是地球上最大的国家,或者中国是人口最多的国家,但这些都是国家的属性(即土地面积和人口),而不是国家名称的内在属性。
明白了!数字是回归,文字是分类
抱歉,没有。
回想一下我之前提到的图书推荐项目,回答以下问题:如果我想预测一本书是否适合
- 幼儿(2-5 岁)
- 小学年龄的儿童(6-10 岁)
- 青少年(11 -12 岁)
- 年轻成年人(13-17 岁)
- 成人(18 岁以上)
我会用什么:回归还是分类?
好吧,假设标签有一个清晰的顺序,你肯定会想把这个问题当作一个回归问题,把“小孩”编码为“1”,把“成人”编码为“5”。
结论
非常感谢您的阅读!我希望这个对分类和回归任务之间的关键区别的简要介绍已经澄清了你的问题和/或巩固了你已经知道的东西。
最后,如果你没有带走任何其他东西,我希望你永远不要忘记以下几点:
总是从问“我试图预测什么”开始。
为什么?因为一旦这个问题解决了,剩下的就变得简单多了;正如卡尔·荣格曾经说过的,“问对了问题,就已经解决了一半的问题。”
进一步阅读
原载于 2020 年 5 月 24 日https://educatorsrlearners . github . io。
有线新闻直播人口统计
使用 matplotlib、plotly 和 python 探索饼图中的相关数据
在 Unsplash 上拍摄的 ThisisEngineering RAEng
对于那些熟悉这位电影主持人的人来说,这部电影的情节围绕着各种角色的恶作剧,一位女性打破玻璃天花板,主持地方新闻,而不是全国新闻。苹果的电视剧《早间秀》(The Morning Show)也使用了打破电视播出规范的情节设计。根据美国人口普查数据,美国女性人数超过男性 50.8%比 49.2%。一段时间以来,在有线电视新闻网上看到女性变得很正常,然而,考虑到今年对种族公正的重新关注,少数族裔在整个网络的空中记者中的代表性如何?在这篇文章中,我将探讨航空人才网络的人口统计和性别分布。我将以饼状图的形式展示福克斯新闻频道、CNN、ABC、CBS 和 NBC 的性别和种族统计数据,并使用支线图创建一个水平布局。此外,我将使用均方差来评论最准确和最不准确地反映美国一般人口的网络。
根据美国人口普查数据,详细描述美国性别和种族人口统计的饼状图。图片作者。
数据和图书馆
性别和种族统计数据是从每个网络网站的图像数据中手动收集的。如果可能的话,使用他们的个人维基百科页面进一步调查暗示不同种族人口统计或没有代表性图像的空中人物的名字。美国人口普查数据网站用于收集美国的性别和种族人口统计数据。
饼图是使用 Matplotlib 创建的静态图表和 plotly 创建的动态图表。Pandas 用于将 excel 文件加载到数据框架中。所有的脚本都是在 Jupyter 笔记本上完成的,可以在 GitHub 上找到数据集。
在我们的数据中,拥有最多空中通讯员的网络是哥伦比亚广播公司,有 93 名空中人物。这个数字随着出现在节目 60 分钟的嘉宾记者的数量而膨胀。下一个最高的网络记者数是美国有线电视新闻网(CNN ),有 71 个空中贡献者。每个网络的直播贡献者平均人数略多于 61 人。数据文件由站点的计数数据组成。为了创建我们的饼图,我将计数数据标准化为百分比。
## Load count data
df = pd.read_excel("New_Demos.xlsx")## Split into demographics and gender tables
df_D = df[['Station', "White", "Latino", "Black", "Asian"]]
df_G = df[['Station', "Male", "Female"]]## Get percentages from counts
df_D = df_D.set_index("Station")
df_D=df_D.div(df_D.sum(axis=1),axis=0).multiply(100).round(decimals=1)df_G = df_G.set_index("Station")
df_G=df_G.div(df_G.sum(axis=1),axis=0).multiply(100).round(decimals=1)
我使用下面的代码将美国人口计数手动添加到相应的 dataframe 对象中。
df_D.loc['US Population'] = [60.0, 18.4, 12.4, 5.6]
df_D['Other'] = 0.0
df_D.at['US Population', "Other"] = 3.6df_G.loc['US Population'] = [49.2, 50.8]
计算均方差
为了计算一个网络的人口统计和美国一般人口之间的差异,我实现了一个函数来计算均方差(MSE)。该函数执行以下步骤:
- 设置基线行(我使用美国人口或第六行)
- 循环遍历每一行,直到基线行
- 计算每行之间的 MSE,并将其存储到一个列表中
- 将列表作为新列追加到原始数据帧中
def mse(dataframe, size):
baseline = list(dataframe.iloc[5])
sums = []
for item in range(5):
comparison = list(dataframe.iloc[item])
## Calculate MSE
amount = [(abs(j-i)**2)/size for i,j in zip(baseline, comparison)]
sums.append(sum(amount))
sums = ['%.1f' % elem for elem in sums]
sums = [float(elem) for elem in sums]
sums.append(0)
return(sums)df_D['MSE'] = mse(df_D, 5)
df_G['MSE'] = mse(df_G, 2)
网络的 MSE 分数。图片作者。
美国广播公司是由男性主导的,福克斯与美国的真实人口统计相比很差。另一个有趣的福克斯统计数据是,20 位女性中有 13 位是金发女郎,占了令人吃惊的 65%。据研究人员称,白种人中天生金发的人估计只占总人口的 5%。人们注意到,身居要职的女性比普通人更有可能拥有金发。
照片由mārtiņš·泽姆利克斯在 Unsplash 拍摄
构建动态饼图
为了创建动态饼图,我使用了 plotly。不幸的是,动态图表在本文中变成了静态的,但是功能仍然保留在 GitHub 上的笔记本代码中。为了创建动态图表,我将 plotly 链接到笔记本。
## Load libraries
import numpy as np
import plotly.offline as py
import plotly.graph_objs as go
from plotly import tools## Connect to notebook
py.init_notebook_mode(connected=True)
然后构建互动情节:
## Create Color Schema
cmap = plt.get_cmap('Set2')
colors = [cmap(i) for i in np.linspace(0, 1, 8)]### Note: 'marker=' lines are apart of the go.Pie function
## Build Gender Pie
gender_pie = go.Pie(labels=q['US Population'].index,
values=q['US Population'], marker=dict(colors=colors[1:3],line=dict(color='#FFF', width=2)), domain={'x': [0.0, .4], 'y': [0.0, 1]}, showlegend=False, name='Gender', textinfo='label+percent')## Build Demographics Pie
demo_pie = go.Pie(labels=w['US Population'].index,
values=w['US Population'], marker=dict(colors=colors, line=dict(color='#FFF', width=2)), domain={'x': [.6, 1], 'y': [0.0, 1]}, showlegend=False, name='Demographics', textinfo='label+percent') ## Set pie chart layout and plot figure
layout = go.Layout(height = 600, width = 1000,autosize = False, title='Gender and Racial Demographics of US Population')fig = go.Figure(data = [gender_pie,demo_pie ], layout = layout)py.iplot(fig, filename='basic_pie_chart')
生成的结果图如下,用户可以滚动查看每个切片的更详细视图。在我们的示例中,由于数据帧被标准化为 100%,因此计数数据与切片大小相匹配。
详细描述美国人口性别和人口统计的动态饼图的静态图像。图片作者。
静态饼图
为了构建静态的性别和人口统计饼图,我使用 matplotlib 和 subplots 让两个饼图共享一个水平轴。我们的网络数据不包括人口统计中的“其他”类别,因为构成该类别的不同身份的数量很大。首先,让我们定义我们的数字和两个支线剧情。
## Horizontal Layout (I use this!)
fig = plt.figure(figsize=(16,8), dpi=200)
ax1 = plt.subplot(1,2,1)
ax2 = plt.subplot(1,2,2)
子情节中定义的三个位置定义了子情节的位置和布局。
## Vertical Layout
fig = plt.figure(figsize=(8,16), dpi=200)
ax1 = plt.subplot(2,1,1)
ax2 = plt.subplot(2,1,2)
我决定在这篇文章中使用水平布局来显示更容易。为了准备创建饼图的数据,我调换了我们的数据框架,并手动为图表分配了颜色。
## Transpose dataframes
q = df_G.transpose()
w = df_D.transpose()## Gender pie chart
z = q['Fox'].plot(kind='pie', ax=ax1, autopct='%1.1f%%', startangle=90, fontsize=16, colors=['dodgerblue', 'pink'])## Demographics pie chart
t = w['Fox'].plot(kind='pie', ax=ax2, autopct='%1.1f%%', startangle=90, fontsize=12, colors=['thistle', 'seagreen', 'gold', 'coral'])## Remove label text between plots
plt.ylabel('')
ax1.yaxis.label.set_visible(False) ## Save figure
plt.savefig("Images/Fox.png", dpi=400)
以下是新闻网络的静态饼状图,从最大 MSE 到最小 MSE,在人口统计数据框架中,美国人口重复出现在底部。
福克斯新闻频道
福克斯新闻频道谈空气个性性别和人口分布。图片作者。
全国广播公司
全国广播公司对空气个性性别和人口分布。图片作者。
美国有线新闻网;卷积神经网络
美国有线电视新闻网关于空气人物性别和人口分布。图片作者。
哥伦比亚广播公司
哥伦比亚广播公司对空气个性性别和人口分布。图片作者。
美国广播公司
空气中的人物性别和人口分布。图片作者。
美国人口
根据美国人口普查数据,详细描述美国性别和种族人口统计的饼状图。图片作者。
结论
这是一个新网络关于空气人物性别和人口统计的案例研究。一些电视网在让直播人物与美国人口相匹配方面比其他电视网更好,CBS 在性别和人口统计方面的 MSE 最低。福克斯新闻频道是民族构成中最不具代表性的。我的名字是科迪·格利克曼,可以在 T2 的 LinkedIn 上找到我。这篇文章的代码和数据可以在 GitHub 上找到。请务必查看我的其他一些探索 python 可视化技术的文章。
使用 Diamonds 和 Matplotlib 创建星图的教程
towardsdatascience.com](/stars-charts-in-python-9c20d02fb6c0) [## 不断变化的美国住房市场人口统计数据
一个使用海绵和赛璐珞制作动画的人口金字塔
towardsdatascience.com](/changing-us-housing-markets-demographics-34d9b0c71cb4) [## COVID 期间的大学足球旅行
当圣母大学在 8 月 17 日暂停面对面学习时,这是对阳性病例激增的回应…
towardsdatascience.com](/college-football-travel-during-covid-1ced0164840e)
Apache Spark 的缓存模式
平衡磁盘、ram 和真实来源之间的选择
许多角度提供了同一场景的许多视图。缓存与分区的工作方式类似。信用
Apache Spark 提供了一些非常简单的机制来缓存进程内计算,这有助于减轻繁琐且固有的复杂工作负载。这篇文章旨在提供一个可接近的心智模型来分解和重新思考如何构建 Apache Spark 计算。无论您的下一个应用程序是批处理作业还是流作业,这里的目标都是为您提供必要的先决条件,以便满怀兴趣地处理您的下一个 Apache Spark 项目!
火花应用程序工作负载
首先,让我说明一个简单的工作负载应该适合内存中数量相对较少的执行器——因为简单的工作负载本质上是简单的:就像加载一组数据,并在一个公共的 ETL 流中将它与另一组数据连接起来。这里所需的开销往往很低,因为您只需要在总处理时间的一部分内将两个数据集都放入内存中——如果调优正确的话。这种工作量是数据工程师的饭碗。
简单的 Spark ETL 流程
上面是一个基于批处理的提取转换加载(ETL)工作负载的简单示例。批处理工作负载通常更像是传统的 Map-Reduce 风格的作业,正是这种风格让 Hadoop 在当年大受欢迎!
C 复杂的工作负载通常不会完全适合内存由于底层数据的成本,或者由于作业的性质,如流管道作业。复杂的工作负载往往会以非常有趣的方式咬你,主要是因为在本地工作的事实,在开发或阶段环境中,很少 在生产中第一次就能很好地扩展。
生产可能是一个可怕的地方,数据速率(每秒事件数等)以超出传统正态分布的方式激增和增长。不确定的事情,尤其是在海量数据的领域,往往会导致管道尖叫着停止工作,导致工作死亡,让客户愤怒——这一切都是因为我们必须在运营成本和不幸的内存不足异常之间进行平衡。
复杂工作负载的示例包括典型的时间序列摄取管道,具有针对实时指标或运营仪表板的流式统计聚合,或者 good ol '实时机器学习管道(请参见下面的示例)。这些工作负载通常是数据工程师和应用机器学习或统计/性能工程师的共同努力。
复杂火花流工作负载
这可能是一个计算量很大的 Spark 应用程序。
上面的例子是一个假的用例*,使用 Apache Spark 结构化流进行所谓的流-流连接。这进一步包括通过昂贵的实时机器学习转换、二次流连接、过滤的后连接查询以及广告推荐流的下游发布,将广告定向到该流管道。理论上,像这样的管道可以把你每天在网上看到的广告发送给你。*
既然我们对简单工作负载和复杂工作负载之间的差异有了大致的了解,我们可以学习如何以更智能的方式解决复杂的问题。走吧。
通过分解简化
有趣的是,大多数简单工作负载和复杂工作负载之间的差异往往可以归结为智能分解模式,因为复杂工作负载可以被视为一系列具有分布式终点线的简单工作负载,所有进程都独立地奔向一起,并且它们都可以完全独立地运行(例如:非确定性工作负载)或确定性地运行,其中先前的执行阶段将问题简化为更简洁的层。
接下来我们将看看 Spark 是如何分配工作的。相信我,这一切都指向某个地方!
Apache 的基本原理引发了分布式计算
在 spark 世界中,一切都始于资源。这个资源有一个源,描述了如何从给定的源读取数据。在最简单的基于文件的 spark 应用中,我们从一个 DataFrameReader 开始。
一堆乐高积木。可以把 RDD 看作是一个单独的单元,它被一些独立的小分区封装起来。如果 RDD 中的一个块丢失了,它可以并且将会被重新计算。信用 Unsplash
DataFrameReader 可用于大多数较简单的数据读取任务,如 json、csv、orc 和其他任务,使我们能够快速将数据加载到 Spark 中,以通过一系列转换进行评估,从而得出最终结果(或行动)。正是这个(load)->(transform)->(write)有向无环计算图(DAG)使得 Spark 工作起来如此有趣。从一个简单的文件开始,如下所示。
*spark.read.json("file://some/path/file.json")*
我们能够很容易地将 json 数据作为数据帧读入 spark 内存。这个数据框架在 Apache Spark 的最新版本中封装了一个强大但几乎隐藏的宝石。那是 RDD。
RDD 是 spark 如何在自己的游戏中击败 Map-Reduce 的。它代表弹性分布式数据集。这些数据集被划分成多个逻辑分区。例如,假设您有一个有 32 个分区的阿帕奇卡夫卡主题。Apache Spark 会自动将 Kafka 资源上的读取流转换成一个有 32 个分区的 RDD ,以遵循并保留最初的 Kafka 分区方案。
这意味着以下是 rdd 的真实情况。
- 所有分区都成为执行阶段中的任务。因为每个分区都可以并行操作,这意味着您的处理作业可以平均分布在所有可用的 Spark 执行器上。(Spark 执行器是运行在 Spark Workers 上的 JVM 进程)
- 在从读到写(或动作)的过程中丢失的任何单个分区都可以独立地重新计算,而无需所有分区都重新开始。与 Map-Reduce 相比,这是一个巨大的速度提升,在 Map-Reduce 中,整个任务都会失败,而单个任务或计算阶段会失败。
- 如果文件系统或 Kafka 主题使用这些块或分区来提供 RDD 的底层分区,而这又可以在简单的数据帧中使用,那么您可以使用常见的散列分区方案( crc hash )来确保您总是在相同的逻辑分区中处理相同种类的数据。例如:假设我们有一个按照一天中的几个小时划分的卡夫卡主题。我们将有 24 个分区,对于给定分区的数据处理将总是有一组那个小时的数据。是的,这将有热点,但我们永远不必在给定分区之外寻找该小时之外发生的信息,而且在许多情况下,这意味着我们不必四处转移数据,也不必承担在整个集群中移动数据的 IO 成本。
但是什么是遗嘱执行人呢?
展示了 Spark 应用程序的结构:照片来源 @ Spark Docs
执行器是 Spark 对分布式计算进程的命名,它只是一个运行在 Spark Worker 上的 JVM 进程。执行者的唯一工作是在工作的各个阶段内,完全致力于被描述为任务的工作的处理(更多细节参见 Spark 文档)。
持久性、缓存和存储级别:您为什么应该关注
内存胜过昂贵的 IO。信用
明智地使用缓存
我一直认为缓存是调优的一个典型组成部分,鉴于这篇文章是关于缓存的,那么让我们假设你会免费带回家一点调优和 调试技能 !
在 Apache Spark 中适当地使用缓存可以让您成为可用资源的主人。内存不是免费的,虽然它可能很便宜,但在许多情况下,从长远来看,将数据帧存储在内存中的成本实际上比返回到真实数据集的来源更昂贵。如果您已经查看了 Spark UI (当 spark.ui.enabled 设置为 true 时在端口 4040 上运行)并且已经确定您不能从系统中挤出性能,那么您是应用缓存的候选人。
主要是如果计算过程中花费的大部分时间是从系统 A 或 B 或 C(比如 HDFS 或 MySQL 或 Redis)加载数据,并且无法通过向外扩展来提高速度。spark 的横向扩展意味着在更多机器上的更多 RAM 上添加更多 CPU 内核。然后,您可以开始考虑有选择地缓存最昂贵的计算部分。
*// profile allows you to process up to 64 tasks in parallel.
spark.cores.max = 64
spark.executor.cores = 8
spark.executor.memory = 12g*
*上述配置将允许您使用 8 台运行 8 个内核和 12gb ram 的机器。我们使用 amazon 的 c5d.2xl 机器,为堆外分配 2gb,为操作系统分配 2gb。因此上例中的 12g。
火花储存
当您缓存数据帧的沿袭时,StorageLevel 的概念就出现了。
*val df = spark.**read
.schema**(Encoders.**product**[SomeCaseClass].**schema**)
.option("**basePath**", "hdfs://path/to/data/lake/root/table")
.**parquet**("**hdfs://path/to/data**/lake/root/table/year=2020/month=2")
.**transform**(expensiveTransformation)
.**join**(otherDataFrame, df("key").equalTo(other("uuid")))*
上面我们有一个加载、转换和连接带有附加数据框的数据的示例。假设这个操作是懒惰的*,在你提供一个动作之前不会计算任何东西,那么我们可以通过在我们的数据帧上调用 head 来欺骗和缓存这个血统,以将 Spark 推入动作。*
*import org.apache.spark.**storage**._
df.persist(**StorageLevel**.MEMORY_ONLY_SER)
df.head // computes the expensive operations and caches
df.**storageLevel** // will show you how things are stored.*
一旦您缓存了您的计算,在这种情况下,调用 persist 并选择 StorageLevel。MEMORY_ONLY_SER 您可以根据初始计算的结果继续进行尽可能多的操作,而不必在源代码或初始读取命令处重新开始每个操作。
StorageLevel 有从 DISK 到 OFF_HEAP 到 NONE 的选项。我建议看看那里的选项,并测试有助于加速 Spark 应用程序的不同选项。
当您处理完缓存的数据后,您可以通过调用 unpersist 轻松地将它从 Spark 中移除。用魔杖轻轻一点,告诉哈利波特迷们恶作剧成功了。
*df.unpersist*
这将立即移除缓存,或者您也可以使用阻塞选项。
*df.unpersist(blocking=true)*
然后,您将释放您的资源,用于剩余的必要计算。
大数据和大数据的叉积是内存不足异常— Holden Karau
结论
我对 Spark 进行缓存和持久化的方法是将其更像 JVM 垃圾收集器。如果我需要多次访问同一个数据,我会将它存储在缓存中。这允许我减少往返于数据的真实来源(s3a://或 hdfs://)的次数。考虑到我所处理的数据类型,主要是 parquet 和其他基于文件系统的数据,在 IO 和总加载文件方面都很繁重。一旦我加载了数据,通常最好在做出另一个决定之前缓存数据,这样我就不会不经意地回到 hdfs 或 s3 来再次加载相同的数据。
关于作者
参见我在Streaming Trend Discovery上的另一篇文章,看看我们如何用 Spark 处理一些更复杂的用例。
使用卷积神经网络(CNN)的仙人掌图像分类达到 98%以上的准确率
我们的目标是构建一个分类器,将图像分类为“仙人掌”或“非仙人掌”
了解数据集
这个分类问题来自于卡格尔挑战赛中的一个。我们的目标是构建一个分类器,将图像分类为“仙人掌”或“非仙人掌”训练集包括 17500 幅图像,而验证集有 4000 幅图像。有仙人掌标志的图像在名为 cactus 的文件夹中,反之亦然。以下是来自训练数据集的示例。
仙人掌
非仙人掌
数据预处理
当我们通过使用 Pyplot 库简单地绘制这些图像来仔细查看其中一些图像时,我们可以观察到它们的大小不同,不适合后面的训练过程。另外,请注意,我们用 1 和 0 标记了所有图像,表示仙人掌和非仙人掌。
因此,我们需要将所有的图像标准化为相同的大小。根据我们的实验,最佳策略是将这些图像裁剪为 48×48 像素的大小。下面是一些裁剪过的图片。第一行显示原始图像,第二行显示修改后的图像。
这种方法的好处是它保存了图像的所有细节;然而,我们有时会丢失图像的边缘,如果图像太小,我们需要用黑色背景扩展图像,使其大小与其他图像相同。失去边缘可能是一个大问题,因为我们有可能用这种技术将仙人掌从图像中切掉。
CNN 结构和培训
卷积神经网络包含 3 层卷积层和 2 个全连接层。每个卷积层都有一个 3 乘 3 滤波器,步长为 2,输出为 64 个节点。之后,数据通过 max-pooling 层,以防止过度拟合并提取有用的信息。
model = Sequential()model.add(Conv2D(64, (3,3), input_shape = X_train.shape[1:]))model.add(Activation(‘relu’))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(64, (3,3)))model.add(Activation(‘relu’))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(64, (3,3)))model.add(Activation(‘relu’))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Flatten())model.add(Dense(64))model.add(Dense(1))model.add(Activation(‘sigmoid’))model.compile(loss=”binary_crossentropy”,optimizer=”adam”,metrics=[‘accuracy’])history = model.fit(X_train, Y_train, batch_size=32, epochs=10, validation_split=0.1, use_multiprocessing=True)model.save(‘model_48_crop’)
下面是模型结构的概述。
模型概述
我们用 10 个纪元来训练模型,结果显示出惊人的效果。第一个精度是下面代码片段中的训练精度,第二个精度是验证精度。请注意,在最终预测之前,我们使用了部分(10%)训练集作为验证集。
试验结果
我们使用 Kaggle 提供的 validation_set 作为我们的测试集,对我们训练好的模型进行最终预测。
testdata = pd.read_pickle(“pickled_data_validation/crop_images(48, 48).pkl”)test_images = testdata.loc[:, data.columns != ‘class’]test_images = test_images.to_numpy()test_images = test_images.reshape((len(test_images),48, 48, 3))test_images = test_images/255.0print(test_images.shape)test_labels = testdata[‘class’]test_labels = test_labels.to_numpy()type(test_labels)test_labels = test_labels.reshape((len(test_labels),1))loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)print(‘Restored model, accuracy: {:5.2f}%’.format(100*acc))
这是结果。它达到了几乎 99%的准确率,这是惊人的。
结论
这篇文章的主要目标是与你分享卷积网络结构对这种二进制分类问题,如猫和狗的图像分类。希望你能对这类问题有更好的理解。
笼赛:XGBoost vs. Keras 深度学习
笼子比赛(作者插图)
自从我第一次尝试深度学习以来,我一直对将其应用于结构化的表格数据感兴趣。我已经写了几篇关于这个主题的文章,我正在为曼宁出版社写一本关于结构化数据深度学习的书。通过利用深度学习的灵活性和减少特征工程的潜力来解决结构化表格数据的问题将是非常棒的。
在表格数据上使用深度学习的想法并非没有批评者。我听到的一个一致的反对意见是,非深度学习方法,特别是 XGBoost,编码更简单,更容易解释,性能更好。我决定我需要用我书中的主要例子来测试这个断言:预测多伦多有轨电车网络的延迟。多伦多市发布了一个数据集,描述了自 2014 年 1 月以来的每一次电车延误。挑战在于使用这个数据集来训练一个机器学习模型,该模型可以预测给定的有轨电车行程是否会被延迟。
为了说明这本书的关键点,我使用 Keras 功能模型创建了一种深度学习方法来解决有轨电车延迟预测问题。该解决方案包括一组模块,用于清理数据、构建和训练模型,以及部署训练好的模型。为了对这两种机器学习方法进行公平的比较,我的目标是用 XGBoost 替换 Keras 深度学习模型,对其余代码进行最小的更改。想象一下,从原始数据的获取到训练模型的部署,整个解决方案就是一辆汽车。我想更换汽车的引擎(机器学习模型),而不改变车身、电气系统、内部或汽车的任何其他方面。
更换发动机,让汽车的其余部分保持不变(作者插图)
我惊喜地发现,用 XGBoost 替换 Keras 深度学习模型是多么容易。以下部分描述了我将包含训练 Keras 模型的代码的笔记本转换成训练 XGBoost 模型的笔记本的步骤。
重构用于定型和测试模型的数据
深度学习模型是一个多输入 Keras 函数模型,它需要在一系列 numpy 数组上进行训练,如以下代码片段所示:
相比之下,XGBoost 模型期望在 numpy 列表数组上进行训练。我需要将训练和测试数据从 Keras 期望的格式转换成 XGBoost 期望的格式。首先,我将测试和训练数据集从 numpy 数组列表转换为列表列表:
我有点害怕使用 for 循环来做这件事——我肯定有更 Pythonic 化的方法——但是这个单元运行得足够快,我希望代码易读。
接下来,我将上一步中的每个列表转换成一个 numpy 列表数组,转置以获得正确的数据组织:
这些转换的输出是我们想要的 XGBoost 格式的数据——列表的 numpy 数组:
下图显示了原始数据形式(numpy 数组列表)的值如何以数据的目标形式(列表的 numpy 数组)结束:
将数据从 Keras 要求的格式转换为 XGBoost 要求的格式
训练和应用 XGBoost 模型
现在我已经有了 XGBoost 所需格式的数据,我已经准备好训练 XGBoost 模型了。下面的代码片段显示了训练和保存模型的代码:
我在 XGBoost fit 语句中使用了一个非默认参数:将 scale_pos_weight 设置为 one_weight 。这个参数让我考虑数据集在否定情况(没有电车延迟)和肯定情况(电车延迟)之间的不平衡。数据集中只有大约 2%的记录表示有轨电车延误。XGBoost fit 语句中的 scale_pos_weight 参数被设置为与 Keras 模型的 fit 语句中使用的值相同的值,其中 class_weight 参数的" 1 "值被设置为 one_weight ,如以下代码片段所示:
接下来,我将训练好的模型应用于测试集,并从模型中获得测试集的预测。
最后,我评估了 XGBoost 模型的准确性:
比较 XGBoost 和 Keras 的结果
现在我们已经有了经过训练的 XGBoost 模型的结果,我们可以比较使用 Keras 深度学习的解决方案和使用 XGBoost 的解决方案的整体特征。下表总结了结果:
XGBoost 与 Keras 结果汇总
让我们更详细地看一下每个比较类别:
- XGBoost 是性能的赢家,尤其是回忆。召回对于预测有轨电车延误的用例至关重要——当将要有延误时,我们希望最小化预测无延误的模型(假阴性)。如果模型预测延迟并且没有延迟(假阳性),用户可能最终步行到他们的目的地或者乘坐出租车而不是有轨电车。最终的影响并没有那么糟糕,因为用户仍然有很好的机会按时到达目的地。然而,由于假阴性(当有延迟时,模型预测没有延迟),影响是坏的,因为用户可能会乘坐有轨电车,并冒着迟到的风险到达他们的目的地。因此,召回对于有轨电车延迟预测问题至关重要,XGBoost 显然具有更好的召回结果。
- 训练时间是平局。在没有 GPU 且迭代次数有限的本地系统上,XGBoost 的训练时间更快。然而,Keras 的训练时间因跑步而异,并且取决于回调耐心参数。“耐心”参数控制一旦目标性能测量(如认证准确度)不再提高,训练运行将持续多少个时期。因为 Keras 的训练时间变化如此之大,所以我认为这个类别是不确定的。
- 代码复杂度是平局。Keras 模型有更复杂的代码来构建功能模型的层。然而,正如上面关于重构用于训练和测试模型的数据的部分所示,XGBoost 需要额外的代码来将数据转换成它所期望的形式。因为 Keras 有更复杂的代码来构建模型,而 XGBoost 需要额外的代码来准备数据,所以我也把这个类别称为平局。
- Keras 在灵活性方面胜出。有轨电车延迟预测问题是《使用结构化数据进行深度学习一书中扩展示例的主题,但其目的是有轨电车延迟预测问题的代码可以应用于各种各样的结构化表格数据集。特别是,如果表格数据集中的一列被标识为自由格式的文本列(例如,零售站点中的商品描述),那么将自动生成 Keras 模型,其中包含处理此类列的图层。XGBoost 没有这种能力来处理包含连续、分类和自由格式文本列的表格数据集。我认为 Keras 方法具有更好的灵活性,因为它可以处理更多种多样的表格数据集。
结论
在本文中,我描述了对街车延迟预测问题的两种解决方案的比较:一种使用 XGBoost 作为模型,另一种使用 Keras 深度学习模型。在这个比较中,我尽可能保持两个解决方案的代码接近;我只修改了与模型的训练和测试相关的部分代码。对比的结果表明,XGBoost 在原始性能,尤其是召回率上更好,Keras 深度学习更灵活。
以下是本文中描述的代码和初始数据集的链接:
- 完整回购:https://github . com/ryanmark 1867/deep _ learning _ for _ structured _ data
- 笔记本包含 XGBoost 的模型训练代码
- 包含 Keras 车型培训代码的笔记本
- 数据准备笔记本(XGBoost 和 Keras 方法通用)
- 原始输入电车延迟数据集
计算并绘制标准普尔 500 每日回报
使用 Python,Pandas 和 Matplotlib
大多数投资者总是试图找到一个简单问题的答案,即金融市场未来将如何表现。
显然,没有人知道答案,因此,投资者和金融分析师花费大量时间试图找出对未来股票价格的最佳估计。蟒蛇和熊猫可以成为一个伟大的盟友,帮助我们找到上述问题的最佳答案。在这个故事中,我们将编写一个 Python 脚本,它将让我们:
- 用 Python 和熊猫检索市场数据
- 计算市场日收益率
- 在图表中绘制市场日收益率
读完这篇文章后,你将能够分析你感兴趣的任何公司的市场回报。我们开始吧。
斯蒂芬·道森在 Unsplash 上拍摄的照片
用 Python 检索市场数据
首先,要进行任何分析,我们都需要数据。幸运是,使用 Python 我们可以在几秒钟内下载数百个数据点。对于我们的分析,我们需要检索股票价格形式的市场数据。
作为市场数据的代理,我将使用S & P 500 指数 来跟踪美国 500 家最大公司的表现。
标准普尔 500 日报的数据可以使用 Pandas 和 Pandas DataReader 提取。Pandas DataReader 是一个很棒的软件包,可以用 Pandas 远程访问数据。
在 Pandas DataReader 中,我们有多个来源可以下载数据,用 Python 执行多种财务分析。例如,我们可以从可靠的提供商那里获得股票数据或经济指标。查看 Pandas DataReader 文档了解更多信息。
为了我们的分析,我们将从 FRED 数据源中检索数据。首先,我们需要导入 Pandas 、 datetime 和 Pandas_datareader 包。
接下来,我们可以简单地定义一个日期范围并使用 web。DataReader 方法以 Pandas DataFrame 的形式下载数据,并将其存储在变量名 SP500 中。
我们将想要下载的数据集的名称(即 sp500)、数据的提供者或来源(“Fred”)以及开始和结束日期作为参数传递给了 DataReader 方法:
import pandas as pd
#if you get an error after executing the code, try adding below. pd.core.common.is_list_like = pd.api.types.is_list_likeimport pandas_datareader.data as web
import datetimestart = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2020, 1, 27)SP500 = web.DataReader(['sp500'], 'fred', start, end)
运行代码后,我们得到了下面的 Pandas DataFrame,显示了历史 S & P 500 每日价格:
计算标准普尔 500 的每日回报率
太好了,我们在熊猫数据框架中有过去 10 年的标准普尔 500 指数价格。现在,我们准备计算过去 10 年的 S & P 500 日收益率,并将它们作为一个新列添加到我们的数据框架中,我们将称之为 daily_return 。
为了计算回报率,我们可以使用下面的公式,其中 P1 指的是当前价格,而 P0 指的是初始价格或我们用来计算回报的参考价格。
收益率
SP500['daily_return'] = (SP500['sp500']/ SP500['sp500'].shift(1)) -1
#Drop all Not a number values using drop method.
SP500.dropna(inplace = True)
shift 方法所做的是将我们的索引移动作为参数提供的数字。在我们的例子中,我们将把 sp500 列中的每个值移动一位。这意味着我们将当天的价格降低到前一天的价格。
让我们打印 SP500 数据帧的最后五个值,看看我们得到了什么:
标准普尔 500 每日回报
策划标准普尔 500 每日回报
我们有我们的标准普尔 500 价格和回报准备用 Python 绘图。让我们先画出每日回报。
用 Python 和 Matplotlib 绘图超级简单,我们只需要从我们的 SP500 数据框架中选择 daily_return 列,并使用方法 plot 。
SP500['daily_return'].plot(title='S&P 500 daily returns')
策划 S&P500 每日回报
不错!我们可以很容易地从图表中找出一些非常有用的信息。例如,我们可以看到标准普尔 500 指数最差的日回报率是在 2011 年,日回报率为-7%。
同样,我们可以看到,标准普尔 500 指数最好的一天是在 2019 年年中,日回报率约为 5%。
除了每日回报,我们还可以绘制过去 10 年的标准普尔 500 价格演变图。这里我们可以观察到一个明显的上升趋势。
SP500['sp500'].plot(title='S&P 500 Price')
绘制标准普尔 500 价格
包扎
在这个关于 Python for Finance 的故事中,我们检索了 S & P 500 的历史价格,以便计算和绘制指数的每日回报。
绘制每日市场回报是一个很好的方法来可视化任何特定时期的股票回报。你可以用任何其他股票或指数来尝试。
我真的希望你喜欢这个故事!如果您有任何问题或不清楚的地方,请随时回复。我还有一个 Youtube 视频,一步一步地解释了本教程中使用的代码:
策划 SP500 每日回报
原载于 2020 年 2 月 8 日【https://codingandfun.com】。
计算你的点击预测的经济影响
超越准确性、AUC 或 Lift:一个衡量经济影响的模型
时代广场由安东尼·罗塞特在 Unsplash 拍摄
我们在IE data science boot camp学习期间,我和 m y 团队为一家拥有 2800 万 MAU 的公司做了一个点击率预测,以改善公司的广告分配。在 IE,他们明确强调了三个领域的重要性,即数学、编程和商业,数据科学家需要努力成功应对数据挑战。
我们的挑战是点击率预测。在互联网上,尤其是在这个博客里,有很多关于如何解决这个问题的内容。但是,它为什么重要呢?**为什么需要预测横幅广告的用户点击量?**你的模型什么时候值得?你的业务收入能提高多少?我们花了一半的时间来了解业务问题,并想办法评估我们不同模式的收入改善情况。
我们在 IE DS 训练营的顶点项目
这不是另一篇关于如何通过预测进行点击的文章(这里如果你感兴趣,你可以得到我们的完整过程代码),这是一篇关于为什么这个问题是值得的,以及我们如何计算收入提高的文章。
开始吧!
问题是
程序化广告是在线买卖广告的自动化交易。广告在网站上用横幅广告展示,其**表现用 CTR(点击率)**来衡量:
广告的点击率通常很低。如果是 1%,这意味着每 100 个接触过广告的访问者中只有 1 个点击了那个广告。
我们公司 60%的收入来自网站横幅广告。挑战在于尽可能地增加收入。横幅持有者根据点击量和印象数获得报酬——当用户看到横幅但没有点击时。横幅广告的盈利方式是在广告拍卖中出售,广告商为这些横幅广告出价。有很多拍卖提供商。在我们的例子中,该公司了解其更普通的用户,他们有一个为他们提供广告的付费提供商。这些广告给他们带来了更多的收入,但他们受到限制,因为他们需要事先与供应商谈判。
想象一下,广告每月限量 1000 万个。或者限制在一个月正常网站流量的 30%。我们将分配 30%的广告给一个优质供应商,其余 70%给一个标准供应商。但是,怎么做呢?我们如何优化分配以增加收入?这是我们的挑战。
目标是训练一个设定用户点击广告概率的模型。然后,我们将对这些概率进行排序,我们将只向概率最高的 30%的用户显示优质广告,而对于其余 70%的用户,我们将显示标准广告。我们模型的性能将用升力来衡量。
一个群体的提升是这个群体比平均水平好或差多少倍:
其中 i 是十分位数或组数。然后,我们将计算使用我们的模型可以提高多少收入,并与没有任何模型进行比较。
选择最佳 ML 模型
对于挑战,我们有两个各 100 万印象的数据集,这是 2019 年 10 月和 11 月流量的样本。数据来自一种谷歌分析引擎,我们只有 10 个非个人信息的特征。他们是:
- 行的唯一标识符。字符串。
- 横幅的名称。字符串。
- 服务器的日期。对象。
- 服务器的时间。对象。
- 印象之国。弦。
- 印象网站(来自英国的用户可以看到。es 网站的扩展)。弦。
- 印象的运作系统。弦。
- 浏览器:用于印象的浏览器。弦。
- RefererURL:点击横幅时,此人在网站的哪个部分。字符串。
- 点击:是否点击了横幅。二进制整型。
我们做了大量的可视化工作,然后通过特征工程来提高模型的性能。如果你想看看我们到底做了什么,这里有所有的代码。
我们的数据框架的负责人在数据之后,即数据争论、数据清理和特征工程
然后,我们拟合 9 种不同的算法,并使用 AUC 对它们进行基准测试。我们选择 AUC 来评估我们的模型,因为我们需要很好地预测 1 和 0——点击或未点击。这是因为与我们的优质提供商相比,我们通过点击赚取更多,但如果没有点击,我们会比标准提供商损失更多的钱。
我们使用的每个模型都有其评估指标
使用 Lightgbm 和 Catboost 型号**,我们实现了 0.757** 的 AUC。我们在最后选择了 Lightgbm ,因为预测速度更快,而且我们需要模型实时运行。
应用训练模型的结果
现在我们有了一个模型,我们如何利用它的结果呢?
我们的问题是,我们应该向哪些用户展示广告,不应该向哪些用户展示。给定测试集(不平衡,与我们的样本具有相同的点击率,4%),模型真正预测的是一个向量,其中给出了点击或不点击的概率。我们对点击概率最高的人感兴趣。确切地说,在我们的例子中,我们对 30%感兴趣。
出于这个原因,我们对点击的概率进行了排序,并将它们分成十分之一组。对于每个十分位数,我们计算了大小、实际点击数量*、实际十分位数(十分位数 _ 阈值)。然后,我们计算了十分位数内用户点击的概率和相关的提升*。**
*# fit the model
model=LGBMClassifier(random_state=101)
model.fit(X_train_trf,y_train)# we are interested in the probabilities
probs=model.predict_proba(X_test_trf)# create a DataFrame with the probs and set the deciles
probs_df=pd.DataFrame(probs)
probs_df[‘real_values’]=y_test
probs_df[‘decile’]=pd.qcut(probs_df[1], 10, labels=False)
probs_df[‘decile’]=(9-probs_df[‘decile’])%10# group by deciles to find the lift
lift=probs_df.groupby(‘decile’)[[‘real_values’]].sum()
lift[‘size’]=probs_df.groupby(‘decile’)[‘real_values’].count()
lift[‘decile_threshold’]=probs_df.groupby(‘decile’)[1].min()
lift[‘prob_click’]=lift[‘real_values’]/lift[‘size’]
lift[‘lift’]=lift[‘prob_click’]/0.0421
lift*
我们模型的结果按十分位数分组
*这个表格真的很重要,因为它意味着**在我们前 10%的印象中,点击的概率是 14.5%(prob _ click),比平均值高 3.45 倍( lift )。*如果来自我们的模型的点击概率高于 71.5%(十分位数 _ 阈值),则印象将在该十分位数中。为什么这两个概率不一样?第一个( prob_click )是在十分位数内的测试集中印象的实际概率。第二个( decile_threshold )是我们模型的概率输出。 Decile_threshold 用于将印象从最好到最差排序。 Prob_click 就是评价,这个排序有多好。
在我们的问题中,记住我们只有 30%的可能分配给额外费用广告。这意味着我们对十分位数 0,1,2 的人感兴趣。这些人点击的概率超过 5.7%(prob _ click表示十分位数 3),我们将在我们的模型预测点击概率超过 57.4%的印象中找到他们(十分位数 2 表示十分位数阈值*)。在下面的图表中,您可以看到结果(数字不匹配,因为这个图表是针对另一个模型的,但想法是相同的)。*
每十分位数的点击概率
*现在我们有了一个做决定的框架。**如果我们的模型预测用户的点击概率高于或等于 57%,它将位于印象的前 30%,因此我们将把横幅销售给我们的优质提供商。*如果对于给定的印象,我们的模型预测点击概率低于 57%,那么我们将把它卖给标准提供商。
经济模式
就收入而言,我们的模式有多好?
***我们并没有通过我们的模式来提高点击率,而是通过更有效地分配点击量来赚取尽可能多的钱。*如果我们没有任何溢价广告,我们将在标准竞价中分配每一个广告,赚取尽可能少的钱。如果我们只有溢价广告,分配将是最好的。相反,我们正处于这两种情况的中间。
想象一下,在我们的场景中,我们有两家供应商,价格如下:
- 高级提供商价格/点击: 5€
- 优质提供商价格/印象但不点击: 0.015€
- 标准提供商价格/点击: 0.5€
- 标准提供商价格/印象但不点击: 0.0024€
***如果没有模型,广告将随机分配。*假设整个数据集的点击率为 4%,我们可以拥有的优质广告比例为 30%,则收入将为:
- ***点击收入:*4% * 30% 广告总数高级广告价格+4% * 70% 广告总数标准广告价格
- 展示但未点击的收入: 96%(未点击广告) 30% 广告总数高级展示价格+96% * 70% 广告总数标准展示价格*
有了一个完美的模型——这是不可能的——我们可以完美地预测用户点击的概率,这样我们就可以尽可能地提高效率,收入将会是:
- *点击收入:**点击次数优质广告价格
- *印象而非点击的收入:(30% *广告数量-点击数量)*高级印象价格+70% 标准印象价格
使用我们的模型我们需要考虑十分位数 0、1、2 中的实际点击次数:
- 点击收入:**前 3 个十分位数的点击量高级广告价格+后 7 个十分位数的点击量标准广告价格
- *印象而非点击的收入:(前 3 个十分位数-前 3 个十分位数的点击次数)*高级印象价格+(后 7 个十分位数-后 7 个十分位数的点击次数)标准印象价格
这看起来有点乱,但它只是应用一些概率分布。为了方便地将它们应用于整个数据集,我们创建了函数 revenue_model 。这些输入是:
- probs_df :上面用来计算升力的数据帧
- fill_rate: 高级提供商可用的百分比。
- model1: 标准提供商的价格(_0 用于展示,_1 用于点击)
- 模型 2: 高级提供商的价格(0 为展示次数,1 为点击次数)
输出是三个数字,上面的模型给出了收入:随机,最优(你的)和完美。
*def revenue_model(probs_df, fill_rate, model1_0, model1_1, model2_0, model2_1):
limit=round(len(probs_df)*fill_rate)
#random model
random_df=shuffle(probs_df)
random2=random_df[:limit]
random1=random_df[limit:]
money_random2=random2[‘real_values’].sum()*model2_1+(len(random2)-random2[‘real_values’].sum())*model2_0
money_random1=random1[‘real_values’].sum()*model1_1+(len(random1)-random1[‘real_values’].sum())*model1_0
revenue_random=money_random1+money_random2
#optimized problem
probs_df=probs_df.sort_values(1,ascending=False)
probs_model2_opt=probs_df[:limit]
probs_model1_opt=probs_df[limit:]
money_model2_opt=probs_model2_opt[‘real_values’].sum()*model2_1+(len(probs_model2_opt)-probs_model2_opt[‘real_values’].sum())*model2_0
money_model1_opt=probs_model1_opt[‘real_values’].sum()*model1_1+(len(probs_model1_opt)-probs_model1_opt[‘real_values’].sum())*model1_0
revenue_opt=money_model1_opt+money_model2_opt
#perfect model
probs_df=probs_df.sort_values(‘real_values’,ascending=False)
probs_model2_perf=probs_df[:limit]
probs_model1_perf=probs_df[limit:]
money_model2_perf=probs_model2_perf[‘real_values’].sum()*model2_1+(len(probs_model2_perf)-probs_model2_perf[‘real_values’].sum())*model2_0
money_model1_perf=probs_model1_perf[‘real_values’].sum()*model1_1+(len(probs_model1_perf)-probs_model1_perf[‘real_values’].sum())*model1_0
revenue_perf=money_model1_perf+money_model2_perf
return revenue_random, revenue_opt, revenue_perf*
然后,我们将其应用于我们的结果,价格如下:
*# set the prices
provider1_1=0.5
provider1_0=0.0024
provider2_1=5
provider2_0=0.015# apply revenue_model function
revenue_random, revenue_opt, revenue_perf = revenue_model(probs_df, 0.3, provider1_0, provider1_1, provider2_0, provider2_1)*
这是我们的示例图片,其中 fill_rate=30% 。评估我们模型的全貌总是一个好主意。为此,我们只需应用相同的函数改变 fill_rate 并绘制结果。
*fill_rates=[]
rev_random=[]
rev_optimal=[]
rev_perfect=[]# apply the function for every fill rate
for fill_rate in range(0,110,10):
fill_rate=fill_rate/100
revenue_random, revenue_opt, revenue_perf = revenue_model(probs_df, fill_rate, provider1_0, provider1_1, provider2_0, provider2_1)
rev_random.append(revenue_random)
rev_optimal.append(revenue_opt)
rev_perfect.append(revenue_perf)
fill_rates.append(fill_rate)# plot the result
plt.figure(figsize=(15,10))
plt.plot(fill_rates,rev_random,label=’random model’,linewidth=3)
plt.plot(fill_rates,rev_optimal,label=’optimal model’,linewidth=3)
plt.plot(fill_rates,rev_perfect,label=’perfect model’,linewidth=3)
plt.legend(fontsize=14)
plt.xlabel(‘Fill rate’,fontsize=14)
plt.ylabel(‘Revenue ($)’,fontsize=14)
plt.xlim(xmin=0)
plt.ylim(ymin=0)
plt.show()*
在图表中,我们可以看到改变填充率时每个型号的收入。蓝线是随机型号*,绿线是完美型号,橙色是我们的型号。在这里,我们可以看到,如果你能把 10%到 50%的广告分配给付费提供商,那么拥有一个模型就更加重要。这是因为这两个数字之间的收入增长百分比比其他范围要高得多。*
对于 30%的额外费用广告(目前的情况),我们的收入几乎翻了一番。但是我们还有 45%的收入可以提高。
**
结论
数据科学家是懂数学和编程,但也有商业头脑的人。这种商业意识让我们不仅能交付优秀的模型,还能让它们适应公司的需求。用收入的术语来谈论总是能让你向非技术客户展示更清晰的结论。
因此,在本文中,我们探讨了点击问题的业务/收入评估。它可用于了解我们的 ML 模型的经济影响,并使用无任何模型(随机模型)和尽可能最大收益(完美模型)对其进行基准测试。
你也可以在这里找到整个项目👇
数据即,数据清洗,特征工程,建模和点击预测的经济影响…
github.com](https://github.com/myrthings/click-prediction)*
你觉得它有用吗?你在用吗?是不是我搞砸了,你什么都不懂?你还有哪些衡量收入的方法?
**在评论区告诉我吧!🤗