如何解释回归模型
高 R 平方值本身就好吗?为什么 R 平方越高,特征越多?回归系数的含义是什么?
艾萨克·史密斯在 Unsplash 上拍摄的照片
作者注:这篇文章是线性模型系列的一部分,它没有解释线性模型的所有属性,因为这会使文章太长。请务必继续阅读,以免错过本系列的下一篇文章。
我主要使用 statsmodels 包进行回归分析,因为它提供了开箱即用的回归模型的详细摘要。在本文中,我将解释摘要中基本术语的含义。
这里有几个你可能会感兴趣的链接:
- [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)
上面的一些链接是附属链接,如果你通过它们购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
什么总结?
当我们用 statsmodels 包训练一个模型时,我们可以调用 summary 函数来产生如下图所示的输出。输出类似于 R 在训练回归模型时产生的输出。
使用 statsmodels 训练的回归模型的摘要。
没听说过 statsmodels?
statsmodels 标志
statsmodels 是一个 Python 包,用于许多不同统计模型的估计,以及进行统计测试和统计数据探索。
如果您错过了我之前关于 statsmodels 的文章,我将它与 sklearn 进行了比较:
谈到 Python 中的经典机器学习算法,sklearn 是第一个首选包——还有其他包…
towardsdatascience.com](/are-you-still-using-sklearn-for-regression-analysis-fb06bb06ce96)
摘要的解释
statsmodels 索引页面显示了如何训练普通最小二乘回归模型的简单示例:
import numpy as npimport statsmodels.api as smimport statsmodels.formula.api as smf# Load data
dat = sm.datasets.get_rdataset("Guerry", "HistData").data# Fit regression model (using the natural log of one of the regressors)
results = smf.ols('Lottery ~ Literacy + np.log(Pop1831)', data=dat).fit()# Inspect the results
results.summary()
回归模型的详细总结。
以上术语是什么意思?
让我们从简单的术语开始:
- 离开变量是模型正在学习的目标变量(上面公式中的彩票),
- 模型是普通的最小二乘法,因为我们使用 smf.ols 函数,
- 观察值是训练集中的样本数,
- Df 模型显示了模型中特征的数量。上面模型中的识字率和 Pop1831。这不包括常数,该常数在将 statsmodels 与公式一起使用时自动添加。
r 平方
默认情况下,回归模型会报告 R 平方和可调 R 平方指标。
r 平方是衡量数据与拟合回归线接近程度的指标。r 平方可以是正数,也可以是负数。当拟合完美时,R 的平方为 1。注意,向模型添加特征不会减少 R 平方。这是因为当添加更多特征时,模型可以找到与之前相同的拟合。更多情况下,添加要素时,R 平方会偶然增加。
skearn 有一个计算 R 平方的函数。在以下情况下,R 平方为负:
from sklearn.metrics import r2_scorey_true = [1, 2, 3]
y_pred = [3, 2, 1]
r2_score(y_true, y_pred)-3.0 # r-squared
产生上述负 R 平方的数据点图。
调整后的 R 平方
调整后的 R 平方通过针对模型中的要素数量进行调整来解决 R 平方的问题。向模型中添加更多要素将增加 R 平方,但可能会减少调整后的 R 平方。经调整的 R 平方的这一属性可用于找到给出最佳准确度的特征。Adj. R-squared 介于 0 到 1 之间,其中 1 表示模型解释了响应数据在其平均值附近的所有可变性。
sklearn 没有计算调整后的 R 平方的函数,因为它也需要样本和特征的数量。我们可以用下面的函数来计算:
def adj_r2(r2, n_samples, n_features):
return 1-(1-r2) * (n_samples-1) / (n_samples-n_features-1)
注意,高调整的 R 平方并不意味着你的模型是好的。拟合回归模型时,我们需要检查残差图。线性回归的假设之一是同方差,这意味着残差的方差对于 x 的任何值都是相同的,我打算在下一篇关于回归模型的文章中写残差图。
系数是如何计算的?
普通最小二乘回归(OLS)通过计算获得解析解:
计算普通最小二乘回归系数的方程。
我们自己试着拟合一下模型吧。首先,我们需要转换功能:
dat.loc[:, 'intercept'] = 1
dat['Pop1831'] = dat['Pop1831'].apply(np.log)
然后我们分离特征和目标变量:
x = dat["intercept Literacy Pop1831".split()].values.T
y = dat['Lottery'].values.T
计算等式的第一部分:
a = np.inner(x, x)array([[8.60000000e+01, 3.37600000e+03, 5.04663925e+02],
[3.37600000e+03, 1.58156000e+05, 1.98401100e+04],
[5.04663925e+02, 1.98401100e+04, 2.97314045e+03]])
计算等式的第二部分:
b = np.inner(x, y)array([ 3741\. , 133414\. , 21572.9563115])
通过寻找线性矩阵方程的最小二乘解来计算系数:
coef = np.linalg.lstsq(a, b)[0]array([246.43413487, -0.48892344, -31.31139219])
我们可以确认这些系数与 OLS 模型中的相同。
系数是什么意思?
系数的符号告诉我们一个特征和一个目标变量之间是正相关还是负相关。
正系数表示当特征增加时,目标的平均值也增加。负系数表示随着特征值的减小,目标趋于减小。
让我们把系数形象化。
# Extract the coefficients from the model
df_coef = results.params.to_frame().rename(columns={0: 'coef'})# Visualize the coefficients
ax = df_coef.plot.barh(figsize=(14, 7))
ax.axvline(0, color='black', lw=1)
回归模型的系数。
在你走之前
在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的。
使用个体条件期望(ICE)图的模型不可知的局部解释
如何用 ICE 曲线解释和影响个人决策
理解机器学习决策
如果你的贷款申请被拒绝,你可能想知道两件事:
- 为什么我被拒绝了?
- 以后怎么做才能获得批准?
来自 Pexels 的 Karolina Grabowska 摄影
换句话说,你想要的解释是针对你自己的。特别是,你会想知道你的情况是如何影响结果的,如果可能的话,做点什么。例如,如果你在现在的地址住了一年多,你获得贷款的机会大大增加,那么你可以放心地在将来再次申请!
无论决策是由人类做出还是由机器学习算法做出,这种对对个人有意义的解释,或众所周知的“局部解释”的需求都适用。在可解释的机器学习领域,有许多众所周知的解释个体决策的技术(例如, SHAP 和莱姆)。这些技术不仅为梳理出“黑盒”机器学习模型的个体预测背后的原因提供了创新的想法,它们还通过以有趣的方式可视化它们来帮助我们理解结果(例如,参见我关于 SHAP 摘要情节的文章)。
一种流行的可视化技术是个体条件期望(ICE)图,这种技术通常与局部解释无关,但我认为在这种情况下可以有所贡献。传统上,冰图主要被视为支持全球解释的可视化;也就是说,解释模型在群体层面的作用。然而,通过对它们的可视化方式进行一些简单的修改,我认为它们在局部解释层面上也是有价值的。使用 ICE 图的好处是它是一种简单易懂的技术。它还提供了丰富的信息,观众可以利用这些信息了解当地的情况,并模拟如果情况发生变化会发生什么。
这篇文章的目的是检验 ICE 图如何帮助解释个人决策,并帮助说明影响决策的因素。我将首先详细描述 ICE 图(第 1 部分),然后使用它的修改版本,通过几个例子来探索它的实用性(第 2 部分)。
本文面向对统计学和机器学习(ML)有基本了解,并对可视化如何帮助解释和影响个人 ML 决策感兴趣的任何人。
什么是冰情节?
ICE 图是部分相关图(PDP)的扩展。PDP 可视化了特征值的变化如何影响 ML 模型的预测。这是通过绘制您感兴趣的某个特性的不同值的平均预测结果,同时保持其他特性值的值不变来实现的。这很有用,因为我们可以看到预测和我们感兴趣的特征之间的关系(通常一次一个或两个)。
例如,我们可以回答以下问题:
- 如果温度上升,冰淇淋需要多少库存?
- 与卧室数量相关的平均房价是多少?
此处显示的图是一个 PDP 示例,显示了来自流行的波士顿房价数据集的“RM”(每个住宅的平均房间数)特征。x 轴是卧室的平均数,y 轴是千片订量的中值。使用 scikit-learn PDP 功能创建图形。
冰图可视化个体差异
PDP 简单易懂。然而,它们的简单性隐藏了单个实例之间潜在的有趣关系。例如,如果一个实例子集的特征值趋势为正,而另一个子集趋势为负,则平均过程可以抵消它们。
冰图解决了这个问题。冰图显示了 PDP 中聚合过程的结果曲线。每条 ICE 曲线都显示了一个实例的不同特征值的预测,而不是平均预测。当它们一起出现在一个图中时,我们可以看到实例子集之间的关系以及单个实例行为的差异。
如下图所示,虽然大多数实例遵循之前显示的 PDP 中的曲线形状,但是在图的顶部有一小部分表现与 PDP 曲线相反;在 x 轴上,它们不是在 6–7 之间增加,而是实际上减少了。
波士顿房价数据集中“RM”要素的 ICE 图
创建一个冰情节很简单。有许多可用的包(例如在 Python 和 R 中)。当然,你自己创造也是可以的。
使用冰图进行局部解释
ICE 图传统上用于理解数据子集中的相互作用和差异,作为部分相关(PD)分析的一部分。然而,如前所述,由于 ICE 图描述的是单个观察结果,因此有可能使用它来关注您感兴趣的特定实例。
计算冰曲线的值
为了可视化实例,我们需要弄清楚如何计算曲线的值(或者能够在创建 ICE 图的工具中定位实例。例如,参见本教程关于在 PyCEbox 中访问 ICE 数据帧。这里有一个简单的例子来说明计算 ICE 曲线值的步骤:
1.找到您感兴趣的实例和特性。
2.查找特征的唯一值。
3.对于这些值中的每一个,用其他特征值创建一个实例。换句话说,固定其他特征值并置换感兴趣的特征值。
4.对每种组合进行预测。
5.获取每个实例的预测值,并绘制预测曲线。
实例#3 特征 B 的冰图
注意相关性
使用 ICE 图(和 PDP)时需要处理的一个潜在问题是特征之间的高度相关性。这在很多方面都有问题:
- 我们可能最终得到不太可能或不可能的特征值组合,然后输入到模型中。例如,在一个包含“怀孕状态”和“性别”特征的数据集中,我们可能最终得到一个怀孕的男性作为输入组合!
- 很难将影响归因于单个特征(即“共线性”或“多重共线性”的结果 ) 。换句话说,很难知道有多少预测影响是由于一个特征或另一个特征。
许多研究人员详细指出了这些问题,并提出了各种补救方法。在实践中,有一些简单的方法来处理高度相关的变量(如聚合、逐步消除)。关于如何处理相关性的详细示例,请参见下面的文章。
可视化冰的曲线
出于解释和影响预测的目的,有许多不同的方法来可视化单个实例。两种主要方法是:
- 独自一人。将单个实例单独可视化,不需要任何关于其余群体的附加信息(如上例所示)。这种方法的优点是生成的图易于理解。观众可以只关注他们试图解释和影响的例子。
- 在上下文中。在数据集中其他实例的上下文中可视化单个实例。这种方法的优点是,查看者可以检查单个实例,同时参考其他实例;以查看该实例是否是异常值,它如何符合或偏离其他实例等。缺点是情节可能会混乱不堪。
社会科学的研究表明,人们经常寻找对比和上下文相关的解释。因此,在上下文中突出感兴趣的实例的方法似乎具有潜在的好处,值得进一步探索。
然而,大多数可用的 ICE 绘图工具不加区别地显示所有实例。如果我们想关注某个特定的实例,我们需要做一些改变。在这方面,有两个变化特别重要:
- 将感兴趣的实例与数据集中的其他实例进行对比。可视化需要在其他实例的上下文中显示感兴趣的实例,但要以一种区别于其他实例的方式。
- 指出不同的特征值以帮助结果的假设模拟。它应该突出显示当前特征值和曲线中的变化值。这将有助于观众在上下文中看到感兴趣的实例,并在心理上模拟可能的理想变化方向。
以下修改后的 ICE 图显示了上例中常规 ICE/PD 图的相关实例。
感兴趣的实例的突出显示
关于这块冰地,有几点需要注意:
- 中间较粗的黑线是 PD 曲线。也就是说,它是所有实例的平均值。
- 所有其他的线都是冰曲线。也就是说,它们是它们的值因感兴趣的特征(即特征 B)而变化的实例。
- 带有标记的蓝线是感兴趣的实例。每个圆形标记代表一个变化的特征值(如 x 轴所示)和一个预测(如 y 轴所示)。
- 蓝线上的黄色菱形标记显示了我们感兴趣的实例的当前特征值和预测。
- 突出显示的实例遵循 PD 曲线的一般形状,但是预测概率水平更高。
通过在 ICE 图的上下文中高亮显示感兴趣的实例,我们可以看到在数据集中其他实例的上下文中改变感兴趣的实例上的特定要素的值的影响。然而,重要的是要注意,这是一个简单的例子,用于说明一个概念。这里所做的设计决策是否会在解释特征对个体决策的影响时导致不可管理的复杂性,还有待观察。
在第 2 部分中,我们将使用几个更现实的例子来说明之前的讨论,并进一步探索 ICE 曲线在为黑盒 ML 模型提供局部解释方面的效用。
参考
[1] Goldstein,a .,Kapelner,a .,Bleich,j .,和 Pitkin,E. (2014 年)。“窥视黑盒内部:用个体条件期望图可视化统计学习.” arXiv:1309.6392
[2]j . h .弗里德曼(2001 年)。"贪婪函数逼近:梯度推进机."统计年鉴,29 卷,第 1189-1232 页。
如何用 ICE 曲线解释和影响个人决策
在信贷申请和员工保留中使用个人条件期望图的示例
现在我们有办法在 ICE 图中突出显示感兴趣的单个实例(参见第一部分),让我们用两个更现实的例子来说明它们的用法:信用申请和员工保留。这些例子显示了可能需要局部解释的不同背景,并允许我们测试早期做出的设计决策是否能够使 ICE 图有助于解释和影响个人决策。这篇文章的代码可以在 GitHub 上找到。
示例 1:信用申请
方案
Andrea Piacquadio 拍摄于 Pexel
罗恩是靠固定收入生活的退休人员。他最近申请了汽车贷款,但被拒绝了。他很恼火,要求对他的拒绝做出解释。
您是贷款专家,负责与 Ron 一起审查自动决策。你渴望帮助他,因为得到他想要的也有利于你的生意。你与 Ron 会面,详细回顾他的拒绝,看看你能提供什么建议。
数据:贷款违约
本例的数据集是可从 Kaggle 获得的贷款违约数据。数据由 10 个特征和“过去 90 天的严重拖欠”的目标输出组成。我们将使用该目标作为贷款批准的建议。也就是说,如果“严重拖欠”的预测是真的,那么贷款被拒绝,否则它被批准。
贷款默认数据集的片段
数据探索
根据我们在第 1 部分中的讨论,我们应该首先看看是否有高度相关的特性。
所有变量的相关矩阵
数据显示了高度相关的三个实例:
- 30–59 天和 90 天:0.98
- 30 到 59 天以及 60 到 89 天的延迟时间:0.98
- 90 天和 60–89 天
换句话说,数据显示,所有时间段(即 30-59 天、60-89 天或 90 天)的逾期债务支付都高度相关。
为了处理这些相关性,尝试了分组和排除策略(即,将所有 3 个变量聚合为一个,并丢弃一个或多个高度相关的变量)。然而,在它们如何影响预测方面没有发现显著差异。为了简化对下游解释的理解,我删除了与目标变量相关性较低的特性,从而保留了特性“30–59 天”。
scikit-learn 的随机森林算法用于拟合具有这些特征的模型,以预测贷款批准(准确度= 0.93)。这些功能的相对重要性如下。
贷款审批的功能重要性
特征重要性分析表明,我们的模型最重要的特征是“利用率”。这一特征被定义为“信用卡和个人信用额度的总余额(除了房地产,没有分期付款债务,如汽车贷款)除以信用限额的总和”。换句话说,信贷余额与信贷限额的比率。这一特征的重要性紧随其后的是负债率和月收入。让我们使用修改后的 ICE 图来绘制这些特性,以更详细地了解我们的单个实例的情况。
冰原
使用我们修改的 ICE 图可视化的前 6 个特征如下。我使用 Python 中的 pyCEbox 包来计算 ICE 值,并对第 1 部分中描述的可视化函数进行了修改。这个的代码可以在 GitHub 上找到。
回想一下第 1 部分:
- 较粗的黑线是 PD 曲线(回想一下,这是所有实例的平均值)。
- 所有其他线都是单个实例的 ICE 曲线。这里的每个子图显示了来自数据集的 602 个单独的实例。
- 带有标记的蓝线是感兴趣的实例。
- 蓝色线上的黄色菱形标记显示了我们感兴趣的实例的当前特征值和预测值。
让我们依次检查这些子情节。提醒一下,预测值为 1 是好的(贷款批准),预测值为 0 是坏的(贷款拒绝)。
**利用:**ICE 图显示 x 轴值达到 1.0 时有相当大的湍流;此后,在稳定之前,在 1.0-1.1 之间的较低概率水平上有更多的波动。PD 曲线反映了这一点,但清楚地显示在值 1.0 附近有下降。
Ron 的 ICE 曲线(带圆形标记的蓝色)或多或少遵循 PD 曲线模式,直到 x 轴上的值为 1.0,之后有一个比 PD 曲线低得多的陡峭下降。此外,如黄色菱形标记所示,对 Ron 的预测接近该特征的 ICE 曲线的底部。因为这是最重要的特征,所以这是为什么 Ron 的贷款申请被拒绝的重要的部分解释。
修改了利用率特性的 ICE 图
根据罗恩的 ICE 曲线,为了增加获得贷款的机会,他可以提高或降低利用率。可视化显示降低这个比率看起来更有效(通过减少他的信用余额或增加他的信用限额大小)。换句话说,如果“利用率”降低,曲线的急剧下降将立即逆转,而增加“利用率”将导致更加平缓的上升。
除了短暂的初始颤振,PD 曲线和单个结冰曲线显示预测相对稳定。
**月收入:**罗恩的冰上曲线显示他接近曲线底部。如果他的月收入增加,那么他获得贷款的机会也会增加。
罗恩目前退休后每月有 5804 英镑的固定收入。ICE 曲线显示 Ron 的最佳水平需要高于 18,000。这比他目前的水平有了很大的提高。然而,ICE 曲线表明,即使 Ron 可以少量增加他的月收入(从而移动到曲线中黄色菱形标记的右侧),他获得贷款的机会也会增加。与 Ron 讨论后,得出的结论是这不是他可以立即做的事情。然而,这次谈话确实让他更多地考虑去做兼职。
**年龄:**虽然曲线有一些有趣的波动,但不幸的是,这是我们无法控制的变量之一。然而,好消息是罗恩的 ICE 曲线表明,随着年龄的增长,他获得贷款的可能性保持不变。
**OpenCreditLinesAndLoans:**PD 曲线和 ICE 曲线都比较平坦。对于 Ron,值在 20 以下时会有一些小的变化,之后会稳定下来。
30–59 天逾期时间:该特征被定义为“借款人逾期 30–59 天的次数,但在过去 2 年中没有恶化”。
ICE 曲线显示,如果罗恩能够减少他的逾期付款,那么他获得批准的机会将大大增加。PD 曲线还显示,随着逾期付款的增加,贷款批准概率呈下降趋势。
尽管罗恩在过去的两年中只迟到过一次,但这仍然对他获得贷款批准的机会产生了巨大的影响。虽然这不是罗恩能马上解决的事情,但这是未来的一个重要收获。
将相关变量聚合为一个变量:过期 30–90 天
回想一下,我还尝试了一种将高度相关的变量组合起来的策略(即,“30–59 天时间”、“60–89 天时间”和“90 天时间”)。结果表明,ICE 曲线的总体形状与上述曲线相似(在浅恢复之前有一个陡峭的下降),并证实了付款的任何延迟都可能增加贷款下降的可能性的结论。
摘要
分析表明,“利用率”是解释 Ron 贷款申请被拒的最重要特征。为了最大化他将来获得贷款的机会,罗恩应该考虑三件事:
- 降低他的“利用率”。
- 如果可能的话,以后增加他的月收入。
- 确保他以后不拖欠债务。
在回顾了这些设想并与您讨论后,Ron 觉得有一些具体的行动值得考虑,并对自己的贷款被拒感觉好多了。
示例 2:员工保留
方案
照片由 loly galina 在 Unsplash 上拍摄
Sourabh 是你们研发团队的明星员工。他 30 多岁,已经在公司工作 5 年了。
作为他的经理,除了奖励他的表现,你还想更好地了解你能做些什么来确保他有动力留在公司。您会见了您的人力资源专家,他们使用 ML 模型来帮助预测员工流失,来讨论这个问题。
会议开始时并不顺利。你的人力资源专员告诉你,根据 ML 模型,Sourabh 很可能会离开。当务之急是,你和你的人力资源专员仔细检查结果,以进一步了解它,看看你需要采取什么步骤来留住 Sourabh。
数据:员工流失
本例的数据集是 IBM 关于员工流失的流行数据集。在删除了一些多余的特征并将数据减少到仅研发团队之后,我们最终得到 1470 条记录、24 个特征和一个目标变量“流失”。请注意,与前面的例子相比,在我们的分析和可视化中,我们需要处理更多的特性。
IBM 员工流失数据集的片段
数据探索
该数据集中有如此多的要素,以至于很难在此处查看和详细检查相关矩阵。然而,可以看出有许多变量是高度相关的。
25 个变量的相关矩阵
特别是,有两组高度相关的功能:
- 月收入和工作水平:0.99
- 工作年限和工作级别合计:0.79
毫不奇怪,个人的工作级别和薪酬(“工作级别”和“月收入”)之间存在关联,因为在许多公司,更高的工作级别通常意味着更高的货币薪酬。同样,晋升到更高的职位级别通常需要时间,因此职位级别高的个人也可能意味着他们在特定公司工作了多年(“TotalWorkingYears”和“job level”)。
出于稍后将讨论的原因,为了处理这些相关性,我选择移除其中一个特性(“JobLevel”),而不是组合它们。与前面的示例一样,随机森林算法用于创建预测模型。这些功能的相对重要性如下:
剩余变量的相关矩阵
如上所示,“MonthlyIncome”是最终模型中最重要的特性。“MonthlyIncome”和下一个最重要的特性之间的差异比较大。之后,重要性会稳步下降。
冰原
由于有如此多的功能,我尝试了各种方法来显示尽可能多的 ICE 图,以提供这些功能的高级视图。我选定了一个 4x 4 的格子。结果是一个冰图的图标化呈现,从顶部最重要的特征开始,从左到右按重要性降序排列。
前 16 个特征的合成冰图
这个合成 ICE 图有效地概述了我们感兴趣的实例相对于前 16 个特征中的每一个的位置。尽管这些特征中的一些对预测的影响相对较低,但是看到它们的趋势仍然是有帮助的。回想一下,概率接近 1.0 意味着 Sourabh 更有可能离开,所以我们希望看到 Sourabh 的 ICE 曲线在 y 轴上更低。
让我们一次一行地检查这些特性,并详细关注更有趣的特性。
月收入
在最上面一行,除了“MonthlyIncome”之外,大多数特征都相对平坦。
“月收入”(较粗的黑线)的 PD 曲线显示,在稳定下来之前,月收入为 2,500 英镑(x 轴)时,流失概率下降到 0.15 左右(y 轴)。有趣的是,一旦大多数人的月收入达到 12500 英镑左右,自然减员的可能性就会增加,这表明月收入的增加只在一定程度上有效。之后,其他因素可能变得更加重要。
Sourabh 的 ICE 曲线反映了这种模式,只是它处于整体损耗概率的较高水平。他目前的月收入为 2313 英镑,接近 2500 英镑-3000 英镑可能会降低他离开的可能性。此后,在很长一段时间内,薪酬增加的回报可以忽略不计。
回想一下,为了处理“MonthlyIncome”和“JobLevel”之间的高度相关性,我们之前已经决定移除其中一个变量,而不是将它们合并。这被证明是正确的决定。否则,很难准确知道每月收入需要增加多少。
离家的距离
在复合冰图的第二行,有两个特征非常突出。首先是“离家的距离”功能:
PD 曲线表明“离家的距离”在 25 英里的范围内保持相对稳定,超过这个范围,损耗的可能性开始增加。ICE 曲线显示 Sourabh 处于离家距离的容许范围的边缘。如果这一距离增加,那么前往苏拉布的可能性也会增加。
如果通勤状况恶化,员工会考虑离开,这一事实并不令人惊讶。但是,ICE 图和突出显示单个实例的好处是,它允许我们以更高的精确度预测变化对单个员工的影响。
股票期权水平
这一行中另一个有趣的特性是“StockOptionLevel”。
Sourabh 目前没有获得任何股票期权。Sourabh 的 ICE 曲线表明,如果“股票期权水平”增加,那么自然损耗的可能性就会降低。ICE 曲线表明“StockOptionLevel”增加到 1.0 是最佳的,因为这是 Sourabh 的 ICE 曲线中的最低拐点。
在第三行,似乎没有任何值得调整的地方。自从 Sourabh 加入公司以来,他就一直和你——他的经理——在一起,这个模型表明,从减员的角度来看,这是一件好事。看起来,获得晋升(也许只是在工作层面)似乎不会影响自然减员的可能性。
最后,当我们移动到第四行中的较低重要性特征时,这些图上的曲线相对平坦。像其他图一样,Sourabh 的 ICE 曲线高于 PD 曲线,相对于其他人来说接近堆栈的顶部,支持他可能会离开的假设。
摘要
你从与人力资源专家的会面中得出的结论是,你需要尽快采取补救措施。分析表明,应考虑以下因素:
- “月收入”增加到 2,500-3,000 英镑。
- 提供“股票期权级别”为 1.0 的股票期权。
未来要考虑的另一个因素是,如果工作地点相对于员工的家有所增加,那么像 Sourabh 这样的员工流失的可能性将会受到影响。
在你的要求下,你的人力资源专员用新的数据再次进行预测。您发现调整“MonthlyIncome”(到 3,000)会使自然减员的概率达到 0.27。此外,增加“StockOptionLevel”(到 1.0)的额外调整会使损耗的概率更低,达到 0.22。
分析为您提供了一些要使用的参数的具体概念。会议结束后,你比开始时更加乐观。在您的预算允许的范围内,您渴望与 Sourabh 进行对话,并尽早采取适当的补救措施。
讨论和结论
这篇文章的目标是探索使用 ICE 图来帮助解释和影响个人决策的潜力。就我们为此做出的设计决策而言,我发现:
- 突出显示感兴趣的实例(通过带有圆形标记的蓝色冰曲线)和突出显示其当前特征值(通过黄色菱形标记)的组合使我们能够清楚地看到当前预测以及它如何随着不同的特征值而变化。
- 冰图的复合图标可视化提供了最重要特征的不同值如何影响预测结果的有用的高级视图。这种可视化有助于我们确定我们应该关注哪些特征来有效地影响变化;通常,当前特征值接近曲线上明显的方向变化。相反,如果 ICE 曲线相对平坦,则表明通过改变该特征的值,预测不太可能有任何显著变化。
- 在其他实例和 PD 曲线的上下文中突出显示单个实例不会导致难以管理的复杂性。回想一下第 1 部分,视觉复杂性是一个不确定的领域,我们想用更真实的例子来测试它。这里的分析表明,先前做出的设计决策是恰当的。ICE 图中剩余的实例提供了一个对比,从中我们可以看到我们的实例在总体中的位置。PD 曲线还用作参考,以查看当前实例是否偏离或符合数据集的平均值。
然而,需要指出的是,这种视觉清晰度可能是由于我们示例中的 PD 曲线和 ICE 曲线没有重叠(信贷申请示例中的“利用率”特征除外)。否则,两条曲线之间的细节差异可能会更加难以辨别。除了探索曲线的重叠和透明度级别的排序,未来可能的增强可能是提供一种交互地打开和关闭这些曲线的方法。这将允许更好地辨别图中有显著重叠的曲线。
关于分析过程,如以上示例所示,ICE 图的解释需要仔细导航。特别是,我们需要注意:
- 潜在动作的解释和推断需要关于特征特性的一般知识。在信贷申请示例中,知道我们能够控制一些功能(例如,“利用率”),但不能控制其他功能(例如,“年龄”),这使我们能够专注于我们能够做些什么的功能。一般来说,在决定采取什么样的潜在行动时,仔细考虑特性的特征是至关重要的,否则我们可能会做出错误的推断。
- 解释突出显示的 ICE 曲线可能需要专业领域知识。大多数人能够毫不费力地掌握信贷申请和人员保留等领域。但是,如果所涉及的特性属于需要大量学习和培训的领域,那么可能需要领域专家来解释结果,并推断可以采取什么潜在的行动。此外,向受影响的个人解释预测结果的任务,如我们的场景中所描述的,可能也更加困难。
汉斯·雷尼尔斯在 Unsplash 上的照片
- 使用 PDP 和 ICE 图时,要素工程和找出处理高度相关要素的最佳方法至关重要。在员工保留的例子中,归因的潜在困难意味着我们必须明智地决定放弃和保留哪些特征。在许多情况下,可能有必要采用试错法来测试处理高度相关特性的不同方法。
同样值得指出的是,在本文中,我们只使用了简单的方法来检测和处理线性关系。可以说,对于更复杂的关系(例如,非线性相关性),可能需要更广泛的技术来处理它们。如果梳理出特征之间的相关性变得难以管理,我们可能不得不考虑使用替代的局部解释可视化技术。例如,累积局部效应(ALE)图避免了相关性问题,并且对其创建的支持变得越来越普遍。在任何情况下,这里显示的可视化方法,即突出感兴趣的个体实例,应该有利于在这类解释工具中解释和影响个体决策。
总之,这项研究表明,当小心使用时,ICE 图的修改版本在试图解释个人决策时非常有用,并有助于我们理解影响决策的因素。
可视化是为最大似然预测提供解释并使黑箱模型更加透明的重要工具。因此,这是一个值得更多关注的领域。考虑到这次探索的发现,带有适当可视化的 ICE 图可以成为 ML 个人决策分析工具包的一个有价值的补充。
参考
[1] Apley,D.W .和 Zhu,j .在黑盒监督学习模型中可视化预测变量的效果。arXiv:1612.08468
如何在面试时解释每个机器学习模型
从回归到支持向量机再到 XGBoost 的模型综述
由卡特曼戈斯塔创作—www.freepik.com
- 如果你喜欢这个, 跟我上 Medium 了解更多
- 关注我Kaggle了解更多内容!
- 我们连线上LinkedIn
- 有兴趣合作?查看我的 [网站](http://Want to collaborate?) 。
- 查看 我的免费数据科学资源 每周都有新素材!
在准备任何采访时,我想分享一个资源,提供每个机器学习模型的简明解释。它们并不意味着广泛,而是相反。希望通过阅读这篇文章,您会对如何以简单的方式交流复杂的模型有所了解。
涵盖的型号
- 线性回归
- 里脊回归
- 套索回归
- 逻辑回归
- k 最近邻
- 朴素贝叶斯
- 支持向量机
- 决策树
- 随机森林
- adaboost 算法
- 梯度增强
- XGBoost
线性回归
线性回归包括使用最小二乘法找到代表数据集的“最佳拟合线”。最小二乘法包括寻找最小化残差平方和的线性方程。残差等于实际值减去预测值。
举个例子,红线比绿线更适合,因为它离点更近,因此残差更小。
作者创建的图像
里脊回归
岭回归,也称为 L2 正则化,是一种引入少量偏差以减少过拟合的回归技术。这是通过最小化残差的平方和加上惩罚来实现的,其中惩罚等于λ乘以斜率的平方。λ指的是惩罚的严厉程度。
作者创建的图像
没有惩罚,最佳拟合的线具有更陡的斜率,这意味着它对 x 的小变化更敏感。通过引入惩罚,最佳拟合的线对 x 的小变化变得不那么敏感。这是岭回归背后的思想。
套索回归
套索回归,也称为 L1 正则化,类似于岭回归。唯一的区别是,惩罚是用斜率的绝对值来计算的。
逻辑回归
逻辑回归是一种分类技术,也能找到“最佳拟合线”。但是,与使用最小二乘法找到最佳拟合线的线性回归不同,逻辑回归使用最大似然法找到最佳拟合线(逻辑曲线)。这样做是因为 y 值只能是 1 或 0。 查看 StatQuest 的视频,看看最大似然是如何计算的 。
作者创建的图像
k-最近邻
作者创建的图像
K-最近邻是一种分类技术,其中通过查看最近的分类点对新样本进行分类,因此称为“K-最近”。在上面的例子中,如果 k=1,那么未分类的点将被分类为蓝点。
如果 k 值太低,它可能会受到异常值的影响。但是,如果它太高,可能会忽略只有几个样本的类。
朴素贝叶斯
朴素贝叶斯分类器是一种受贝叶斯定理启发的分类技术,贝叶斯定理陈述了以下等式:
因为假设变量是独立的,我们可以将 P(X|y)改写如下:
此外,由于我们求解 y,P(X)是一个常数,这意味着我们可以将其从等式中删除,并引入一个比例。
因此,y 的每个值的概率被计算为给定 y 的 xn 的条件概率的乘积。
支持向量机
支持向量机是一种分类技术,它找到一个最佳边界,称为超平面,用于区分不同的类别。通过最大化类之间的间隔来找到超平面。
作者创建的图像
决策树
决策树本质上是一系列条件语句,它们决定了样本在到达底部之前的路径。它们直观且易于构建,但往往不准确。
随机森林
随机森林是一种集成技术,这意味着它将几个模型结合成一个模型,以提高其预测能力。具体来说,它使用自举数据集和随机变量子集(也称为 bagging)构建了 1000 个较小的决策树。对于数千个较小的决策树,随机森林使用“多数获胜”模型来确定目标变量的值。
例如,如果我们创建一个决策树,第三个,它会预测 0。但是如果我们依赖所有 4 个决策树的模式,预测值将是 1。这就是随机森林的力量。
adaboost 算法
AdaBoost 是一种增强算法,类似于随机森林,但有两个显著的区别:
- AdaBoost 通常制作树桩森林(树桩是只有一个节点和两片叶子的树),而不是树木森林。
- 每个树桩的决策在最终决策中的权重并不相等。总误差少(精度高)的树桩会有更高的话语权。
- 树桩创建的顺序很重要,因为每个后续树桩都强调在前一个树桩中被错误分类的样本的重要性。
梯度增强
梯度增强在某种意义上类似于 AdaBoost,它构建多棵树,其中每棵树都是基于前一棵树构建的。与 AdaBoost 构建树桩不同,Gradient Boost 构建的树通常有 8 到 32 片叶子。
更重要的是,Gradient 与 AdaBoost 在决策树的构建方式上有所不同。梯度增强从初始预测开始,通常是平均值。然后,基于样本的残差构建决策树。通过采用初始预测+学习率乘以残差树的结果来进行新的预测,并且重复该过程。
XGBoost
XGBoost 本质上与渐变增强是一样的,但是主要的区别是如何构建残差树。使用 XGBoost,通过计算叶子和前面的节点之间的相似性分数来构建残差树,以确定哪些变量被用作根和节点。
感谢阅读!
希望在读完这篇文章时,你会有一个想法,如何通过突出要点来总结各种机器学习模型。同样,这并不意味着是一篇深入的文章,解释每篇文章的复杂性。根据上面的总结,随意研究任何不完全有意义的模型!
特伦斯·申
- 如果你喜欢这个, 在 Medium 上关注我 获取更多
- 关注我的Kaggle了解更多内容!
- 我们连线上LinkedIn
- 有兴趣合作?查看我的 [网站](http://Want to collaborate?) 。
- 查看 我的免费数据科学资源 每周都有新素材!
如何导出 BigQuery ML 模型并将其部署用于在线预测
以 TensorFlow SavedModel 格式导出 BigQuery ML 模型并部署到云 AI 平台预测
在本文中,我将向您展示如何将 BigQuery ML 模型导出为 TensorFlow 的 SavedModel 格式。这将允许您将模型部署到任何支持 TensorFlow 服务的环境中。我将使用云人工智能平台预测来演示这一点,并向您展示如何调用在线预测。
1.训练 BigQuery ML 模型
当然,首先我们需要一个 BigQuery ML 模型。为了简单起见,我将在我们的书“ BigQuery:权威指南”中使用的同一个伦敦自行车数据集上使用一个简单的线性模型。
首先,在 EU 位置创建一个数据集来保存训练好的模型(可以在 CloudShell 中运行这个命令,也可以从 BigQuery 控制台执行这个操作;请确保选择 EU 作为地点):
bq show ch09eu || bq mk --location=EU ch09eu
接下来,在 BigQuery 控制台中运行这个查询:
CREATE OR REPLACE MODEL ch09eu.bicycle_model_linear
OPTIONS(input_label_cols=['duration'], model_type='linear_reg')
ASSELECT
duration
, start_station_name
, IF(EXTRACT(dayofweek FROM start_date) BETWEEN 2 and 6, 'weekday', 'weekend') as dayofweek
, FORMAT('%02d', EXTRACT(HOUR FROM start_date)) AS hourofday
FROM `bigquery-public-data`.london_bicycles.cycle_hire
这将创建一个名为 bicycle_model_linear 的模型,该模型采用 3 个输入(start_station_name、dayofweek、hourofday)来预测以秒为单位的持续时间。
2.在 SQL 中尝试批量预测
让我们试着调用 BigQuery 本身的模型。为此,运行以下查询:
SELECT * FROM ML.PREDICT(MODEL ch09eu.bicycle_model_linear,(
SELECT
'Vauxhall Cross, Vauxhall' AS start_station_name
, 'weekend' as dayofweek
, '17' AS hourofday)
)
这将返回:
如你所见,周末下午 5 点在沃克斯豪尔开始的一次骑行的预计持续时间是 1329 秒。
3.将模型导出到 Google 云存储
让我们从 BigQuery 下载这个模型作为 TensorFlow SavedModel。为此,从 CloudShell 运行以下命令:
PROJECT=$(gcloud config get-value project)
BUCKET=${PROJECT}-eu
gsutil mb -l eu gs://${BUCKET}
bq extract -m ch09eu.bicycle_model_linear \
gs://${BUCKET}/bqml_model_export/bicycle_model_linear
该命令的作用是创建一个名为 xyz-eu 的 bucket,其中 xyz 是您的项目名称。然后,我们调用 bq extract 将模型导出到 GCS。
命令完成后,检查导出了哪些文件:
gsutil ls gs://${BUCKET}/bqml_model_export/bicycle_model_linear/
当我这么做的时候,我得到了:
gs://ai-analytics-solutions-eu/bqml_model_export/bicycle_model_linear/
gs://ai-analytics-solutions-eu/bqml_model_export/bicycle_model_linear/saved_model.pb
gs://ai-analytics-solutions-eu/bqml_model_export/bicycle_model_linear/assets/
gs://ai-analytics-solutions-eu/bqml_model_export/bicycle_model_linear/variables/
这是 TensorFlow SavedModel 格式。您可以将它部署到任何 TF 服务环境中进行在线预测。在 GCP,TensorFlow/xgboost/PyTorch/etc 的全托管服务环境。models 是云 AI 平台(CAIP)的预测。
4.将模型部署到云人工智能平台预测
为了部署模型,从 GitHub 存储库中下载 deploy.sh 并运行它:
./deploy.sh gs://${BUCKET}/bqml_model_export/bicycle_model_linear \
europe-west1 london_bicycles bqml
deploy.sh 的作用是在 CAIP 预测中创建一个模型和模型版本,然后部署到其中。
部署模型可能需要 4-5 分钟,因此在进入下一步之前,请监控https://console . cloud . Google . com/ai-platform/models/London _ bicycles/versions以确保模型已部署。
5.尝试在线预测
用我们想要发送给模型的输入创建一个名为 input.json 的文件。您可以通过在 CloudShell 中键入以下内容来实现这一点:
cat > input.json
然后,在提示符下,键入:
{"start_station_name": "Vauxhall Cross, Vauxhall", "dayofweek": "weekend", "hourofday": "17"}
最后,按 Ctrl-D 返回到提示符。
使用以下方式将 input.json 发送到 CAIP 预测:
gcloud ai-platform predict --model london_bicycles \
--version bqml --json-instances input.json
当我这样做的时候,我回来了:
PREDICTED_LABEL
[1329.178180269723]
这与我们在 BigQuery ML 中进行批量预测时获得的持续时间相同。
CAIP 预测公开了一个采用 JSON 的 REST API,因此可以从任何能够进行 web 服务调用的语言中调用它。
尽情享受吧!
后续步骤:
如何将数百万条记录从 Mysql 导出到 AWS S3?
构建自我恢复和可扩展的系统
Apache Spark 生态系统信用:数据块
在 Twilio ,我们每天处理世界各地发生的数百万个电话。一旦通话结束,就会被记录到 MySQL 数据库中。客户能够通过 API 查询 调用 的详细信息。(是的,Twilio 是 API 驱动的公司)
我最近做的一个任务是建立一个系统,允许客户导出他们的历史通话数据。这将允许他们导出直到最近的所有历史通话记录
乍一看,这似乎是微不足道的,但是如果我们更深入地思考,一个系统将如何为从一开始就与我们合作的一些最大的客户进行扩展,这个问题可以归类为构建一个可扩展的系统。我们典型的客户规模从每天打几百个电话到几百万个不等。
当一个每天打 100 万个电话的大客户请求过去 5 年的数据时,这个问题突然变成了一个大数据问题。呼叫总数可以在 1,000,000 * 5 * 365 的范围内。
我不得不考虑如何优化从 Mysql 读取数据,并高效地向 S3 发送数据,以便下载文件。
可能的解决方案
1.编写一个 cron 作业,查询 Mysql 数据库中的特定帐户,然后将数据写入 S3。这对于获取较小的记录集可能很有效,但是为了使作业能够很好地存储大量记录,我需要构建一种机制来在失败时重试,并行读取和写入以实现高效下载,添加监控来衡量作业的成功。我将不得不编写连接器或使用库来连接 MySql 和 S3。
2.使用 火花流
我决定使用 Apache Spark 来处理这个问题,因为在我的团队中( Voice Insights )我们已经大量使用它来进行实时数据处理和构建分析。 Apache Spark 是一个用于构建可扩展实时处理应用的流行框架,在行业中广泛用于解决大数据和机器学习问题。Spark 的一个关键特性是它能够从 Kafka、Kinesis、S3、Mysql、文件等各种来源产生/消费数据。
Apache Spark 也是容错的,并提供了一个处理失败和优雅地重试的框架。它使用检查点机制来存储所执行任务的中间偏移量,以便在任务失败的情况下,任务可以从最后保存的位置重新开始。为水平扩展配置作业效果很好。
假设读者对 Spark 有基本的了解(Spark 官方 文档 是一个很好的起点)。我将深入研究代码。
让我们看看如何从 MySQL 数据库中读取数据。
**val** jdbcDF **=** spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:port/db")
.option("driver", "com.mysql.jdbc.Driver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.load()
与 JDBC 连接的另一种方法是将配置作为地图。
**val** dbConfig = Map("username" -> "admin",
"password" -> "pwd",
"url" -> "http://localhost:3306")
**val** query = "select * FROM CallLog where CustomerId=1"**val** jdbcDF **=** spark.read
.format("jdbc")
.options(dbConfig)
.option("**dbtable**", s"${query} AS tmp")
.load()
**OR****val** jdbcDF **=** spark.read
.format("jdbc")
.options(dbConfig)
.option("**query**", s"${query} AS tmp")
.load()
使用查询和 **dbtable 有细微的区别。**这两个选项都会在 FROM 子句中创建一个子查询。上述查询将被转换为
SELECT * FROM (SELECT * FROM CallLog where CustomerId=1) tmp WHERE 1=0
这里最重要的一点是query
不支持partitionColmn
,而dbTable
支持分区,这通过并行实现了更好的吞吐量。
比方说,如果我们必须为我们的一个大客户导出通话记录,我们将需要利用分而治之的方法,并且需要一种更好的方法来并行化这项工作。
按列值对 SQL 查询进行分区
这意味着 Spark 可以同时对同一个表执行多个查询,但是每个查询通过为一个列(分区列)设置不同的范围值来运行。这可以在 Spark 中通过多设置几个参数来实现。让我们再看几个参数:
numPartitions
选项定义了表中可用于并行读取的最大分区数。这也决定了并发 JDBC 连接的最大数量。
partitionColumn
必须是相关表中的数值、日期或时间戳列。这些参数描述了在多个工作线程并行读取时如何对表进行分区。
lowerBound
和upperBound
只是用来决定分区步距,而不是用来过滤表中的行。因此表中的所有行将被分区并返回。此选项仅适用于阅读。
fetchSize
JDBC 提取大小,决定每次往返要提取多少行。这有助于提高默认为低读取大小的 JDBC 驱动程序的性能(例如,Oracle 有 10 行)。此选项仅适用于阅读。
上例中的partitionColumn
可以是CallId
。让我们试着把所有的参数联系起来。
**val** dbConfig = Map("username" -> "admin",
"password" -> "pwd",
"url" -> "http://localhost:3306",
"numPartitions" -> 10,
"paritionColumn" -> "CallId",
"lowerBound" -> 0,
"upperBound" -> 10,000,000)
**val** query = "select * from CallLog where CustomerId=1"**val** jdbcDF **=** spark.read
.format("jdbc")
.options(dbConfig)
.option("dbtable", s"(${query}) AS tmp")
.load()
上述配置将导致运行以下并行查询:
SELECT * from CallLog where CustomerId =1 AND CallId >=0 AND CallId <1,000,000
SELECT * from CallLog where CustomerId =1 AND CallId >= 1,000,000 AND CallId <2,000,000
SELECT * from CallLog where CustomerId =1 AND CallId>= 2,000,000 AND CallId <3,000,000
....
SELECT * from CallLog where CustomerId =1 AND CallId>= 10,000,000
上述查询并行化将有助于更快地从表中读取结果。
一旦 Spark 能够从 Mysql 读取数据,将数据转储到 S3 就变得轻而易举了。
jdbcDF.write
.format("json")
.mode("append")
.save("${s3path}")
结论:
上面的方法让我们有机会使用 Spark 来解决一个经典的批处理作业问题。我们正在用 Apache Spark 做更多的事情,这是众多用例中的一个。我很想听听你用火花在做什么。
如何将熊猫数据帧导出为 CSV 格式
在这篇文章中,我们将讨论如何将数据帧写入 CSV 文件。
简短回答
最简单的方法是:
df.to_csv('file_name.csv')
如果想不带索引导出,只需添加index=False
;
df.to_csv('file_name.csv', index=False)
如果得到UnicodeEncodeError
,简单加encoding='utf-8'
;
df.to_csv('file_name.csv', encoding='utf-8')
概述熊猫数据框架
熊猫数据框架创建了一个带有标签轴(行和列)的 excel 数据结构。要定义一个数据帧,至少需要数据行和列名(标题)。
这里有一个熊猫数据帧的例子:
熊猫数据框架是类似 Excel 的数据
生成数据帧的代码:
将数据帧导出到 CSV 文件中
Pandas DataFrame to_csv()
函数将数据帧导出为 CSV 格式。如果提供了文件参数,输出将是 CSV 文件。否则,返回值是类似字符串的 CSV 格式。
以下是一些选项:
path_or_buf :文件或字符串的字符串路径
dt.to_csv('file_name.csv’) # relative position
dt.to_csv('C:/Users/abc/Desktop/file_name.csv')
sep :为 CSV 输出指定一个自定义分隔符,默认为逗号。
dt.to_csv('file_name.csv',sep='\t') # Use Tab to seperate data
na_rep :类似 NaN 的缺失值的字符串表示。默认值为“”。
dt.to_csv('file_name.csv',na_rep='Unkown') # missing value save as Unknown
float_format: 浮点数的格式字符串。
dt.to_csv('file_name.csv',float_format='%.2f') # rounded to two decimals
**表头:**是否导出列名。默认值为 True。
dt.to_csv('file_name.csv',header=False)
列:要写入的列。默认值为 None,每一列都将导出为 CSV 格式。如果设置,只有列会被导出。
dt.to_csv('file_name.csv',columns=['name'])
索引:是否写行索引号。默认值为 True。
dt.to_csv('file_name.csv',index=False)
附录
写入 CSV 文件的常见场景
DataFrame to_csv()的语法是:
DataFrame.to_csv(
self,
path_or_buf,
sep: str = ',',
na_rep: str = '',
float_format: Union[str, NoneType] = None,
columns: Union[Sequence[Union[Hashable, NoneType]], NoneType] = None,
header: Union[bool, List[str]] = True,
index: bool = True,
index_label: Union[bool, str,
Sequence[Union[Hashable, NoneType]], NoneType] = None,
mode: str = 'w',
encoding: Union[str, NoneType] = None,
compression: Union[str, Mapping[str, str], NoneType] = 'infer',
quoting: Union[int, NoneType] = None,
quotechar: str = '"',
line_terminator: Union[str, NoneType] = None,
chunksize: Union[int, NoneType] = None,
date_format: Union[str, NoneType] = None,
doublequote: bool = True,
escapechar: Union[str, NoneType] = None,
decimal: Union[str, NoneType] = '.')
使用 to_csv 的常见场景
如何扩展 Keras 模型
使用 Keras 模型时传递实例键和特征
通常,您只需要 Keras 模型返回预测值,但是在某些情况下,您希望您的预测保留一部分输入。一个常见的例子是在执行批量预测时转发唯一的“实例键”。在这篇博客和对应的笔记本代码中,我将演示如何修改一个经过训练的 Keras 模型的签名,以将特性转发到输出或传递实例键。
通过实例键排序。照片由 Samantha Lam 在 Unsplash 上拍摄
如何将实例键转发到输出
有时,您会有一个与每一行相关联的唯一实例键,并且您希望该键与预测一起输出,以便您知道该预测属于哪一行。当使用类似云人工智能平台批量预测的服务执行分布式批量预测时,您需要添加密钥。此外,如果您正在对模型执行连续评估,并且想要记录有关预测的元数据以供以后分析。 Lak Lakshmanan 展示了如何使用张量流估值器实现这一点,但是 Keras 呢?
假设您有一个以前训练过的模型,它已经用tf.saved_model.save()
保存了。运行以下代码,您可以检查模型的服务签名,并查看预期的输入和输出:
tf.saved_model.save(model, MODEL_EXPORT_PATH)!saved_model_cli show — tag_set serve — signature_def serving_default — dir {MODEL_EXPORT_PATH}The given SavedModel SignatureDef contains the following input(s):
inputs['image'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 28, 28)
name: serving_default_image:0
The given SavedModel SignatureDef contains the following output(s):
outputs['preds'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 10)
name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict
要传递唯一的行键和先前保存的模型,请加载您的模型,创建一个替代的服务函数,然后重新保存,如下所示:
loaded_model = tf.keras.models.load_model(MODEL_EXPORT_PATH)@tf.function(input_signature=[tf.TensorSpec([None], dtype=tf.string),tf.TensorSpec([None, 28, 28], dtype=tf.float32)])
def keyed_prediction(key, image):
pred = loaded_model(image, training=False)
return {
'preds': pred,
'key': key
}# Resave model, but specify new serving signature
KEYED_EXPORT_PATH = './keyed_model/'loaded_model.save(KEYED_EXPORT_PATH, signatures={'serving_default': keyed_prediction})
现在,当我们检查模型的服务签名时,我们会看到它将键作为输入和输出:
!saved_model_cli show --tag_set serve --signature_def serving_default --dir {KEYED_EXPORT_PATH}The given SavedModel SignatureDef contains the following input(s):
inputs['image'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 28, 28)
name: serving_default_image:0
inputs['key'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_key:0
The given SavedModel SignatureDef contains the following output(s):
outputs['key'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: StatefulPartitionedCall:0
outputs['preds'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 10)
name: StatefulPartitionedCall:1
Method name is: tensorflow/serving/predict
您的模型服务现在将在任何预测调用中同时期待一个image
张量和一个key
,并将在其响应中输出preds
和key
。这种方法的一个好处是,您不需要访问生成模型的代码,只需要访问序列化的 SavedModel。
如何利用多个服务签名
有时保存具有两个服务签名的模型是方便的,或者是出于兼容性原因(即默认签名是未加密的),或者是为了使单个服务基础结构可以处理加密和未加密的预测,并且用户决定执行哪一个。您需要从加载的模型中提取服务函数,并在再次保存时将其指定为服务签名之一:
inference_function = loaded_model.signatures['serving_default']loaded_model.save(DUAL_SIGNATURE_EXPORT_PATH, signatures={'serving_default': keyed_prediction,
'unkeyed_signature': inference_function})
如何将输入要素转发到输出
出于模型调试的目的,您可能还希望转发某些输入要素,或者计算特定数据切片的评估指标(例如,根据婴儿是早产还是足月来计算婴儿体重的 RMSE)。
本例假设您使用了多个命名输入,如果您想利用 TensorFlow 特性列,您可以这样做,如这里的所述。您的第一个选择是像往常一样训练模型,并利用 Keras Functional API 创建略有不同的模型签名,同时保持相同的权重:
tax_rate = Input(shape=(1,), dtype=tf.float32, name="tax_rate")
rooms = Input(shape=(1,), dtype=tf.float32, name="rooms")x = tf.keras.layers.Concatenate()([tax_rate, rooms])
x = tf.keras.layers.Dense(64, activation='relu')(x)
price = tf.keras.layers.Dense(1, activation=None, name="price")(x)# Functional API model instead of Sequential
model = Model(inputs=[tax_rate, rooms], outputs=[price])# Compile, train, etc...
#
#
#forward_model = Model(inputs=[tax_rate, rooms], outputs=[price, tax_rate])
另一种方法,如果您没有生成模型的代码,则特别有用,就是像使用键控预测模型一样修改服务签名:
@tf.function(input_signature=[tf.TensorSpec([None, 1], dtype=tf.float32), tf.TensorSpec([None, 1], dtype=tf.float32)])
def feature_forward_prediction(tax_rate, rooms):
pred = model([tax_rate, rooms], training=False)
return {
'price': pred,
'tax_rate': tax_rate
}model.save(FORWARD_EXPORT_PATH, signatures={'serving_default': feature_forward_prediction})
尽情享受吧!
感谢 拉克什马南 帮我把他原来的估计器帖子更新到 Keras。
如何从熊猫的现有序列和数据框架中提取数据
探索地图的力量()并应用()
准备数据集的一个关键操作是从现有数据中提取信息。熊猫的两个重要功能是专门为完成这一任务而设计的——map()
和apply()
。我注意到,许多现有的教程都专注于介绍如何使用这些函数,而没有设置适当的上下文,以至于许多初学者仍然不知道在自己的项目中何时使用这些函数。在本文中,我想通过为这些功能设置适当的使用场景来解决这个问题,希望能够让您更容易地将这些用例直接转化为您自己特定的业务需求。
出于各种演示的目的,我们将在适用的地方使用以下系列和 DataFrame 对象。
抽样资料
场景 1。从现有系列创建系列
假设您从一个 Series 对象开始,并且您想要创建另一个具有基于相应值的单个值的序列。最好简单地在系列对象上使用map()
功能。有多种方法可以使用map()
函数,如下面的代码片段所示。
现有系列的映射
- 以上三种用法产生了一系列相同值的对象。
- 您可以使用另外一个参数—
na_action
,它指定了映射如何处理现有序列的NaN
值。您可以选择‘ignore’
,这将在新系列中创建一个NaN
值,或者选择None
(默认选项),这将把 NaN 值传递给映射字典或函数。你可以在这里了解更多。 - 因为 DataFrame 对象的行和列是 Series 对象,所以这个用例可以用来从现有的列创建 DataFrame 对象的新列(它也可以用于行)。以下代码向您展示了这样的用法—通过映射创建新行和新列。
数据框架映射新列
场景 2。从数据帧中的多个系列创建系列
有时需要从多行或多列中提取数据。为了简化本教程,我们假设需要从其他列创建一个列。在这种情况下,我们可以对 DataFrame 对象使用apply()
函数。就像map()
函数一样,你可以为apply()
函数设置一个 lambda 函数或者一个常规函数。
数据框架创建列
- 参数
axis
设置为 1,这意味着我们正在处理行,并且想要创建列。 - 当 axis=1 时,lambda 函数或常规函数的默认参数是行序列,其值可以使用键来访问(例如,
[‘col 0’]
)。 - 当需要指定额外的参数时,可以设置
args
参数,这些参数除了行数据之外,还可以发送给映射函数。在示例中,我们将 5 设置为映射函数的额外参数的n
。
场景 3。从现有系列创建多个系列
假设您需要从现有系列创建多个系列。您可以对 Series 对象使用apply()
方法。请注意,尽管它与上一节提到的apply()
函数同名,但这个函数是一个系列对象的方法,而前一个函数是 DataFrame 的方法。鉴于它们在功能上的相似性,它们只是碰巧有相同的名字。下面的代码向您展示了这种用法的一个简单例子。
从一个系列创建多个系列(即数据帧)
如前所述,因为 DataFrame 的列是 Series 对象,所以我们可以从 DataFrame 列创建多个列。下面的代码向您展示了它是如何工作的。
从一个列创建新列
- 正如前面的代码示例,Series 对象上的
apply()
方法必须返回一个 Series 对象(注意 lambda 函数创建了一个 Series 对象)。这里,我们创建了一个包含两个值的 Series 对象,因为我们创建了两列。 - 您必须在等式的左侧指定您正在创建的列,以便新创建的列可以知道去哪里。
场景 4。从多个系列创建多个系列(即数据帧)
在 Pandas 中,DataFrame 对象可以被认为在两个轴上都有多个系列。因此,本节标题中描述的场景本质上是从现有列创建新列或从现有行创建新行。最好的方法是在 DataFrame 对象上使用apply()
方法。为了简单起见,让我们只考虑在下面的例子中从现有的列创建新的列,然后进行一些说明。
多列中的多列
- lambda 函数(也可以使用常规的定义函数)正在创建一个包含两项的列表,因为我们创建了两列。
- lambda 函数中的 x 表示行数据,我们可以使用列名来访问各个值。
- 这里重要的是将
result_type
参数指定为‘expand’
,这将扩展 lambda 函数的结果以形成新的列。换句话说,这里的 lambda 函数创建了一个包含两项的列表,该列表将被扩展为两列。
值得注意的是,result_type
论点还有其他一些选择。例如,默认选项是None
,它不扩展结果并保持不变。另一个选项是‘reduce’
,它通过返回一个序列对象完成与‘expand’
选项相反的工作。要了解关于这些不同选项的更多信息,您可以在这里查阅文档。 - 示例中没有包括的一件事是,正如第 2 节中使用
apply()
方法显示的结果一样,我们可以提供将在映射函数中使用的附加位置和关键字参数。
结论
在本文中,我们介绍了如何以 Series 和 DataFrame 对象的形式从现有数据创建新的 Series 对象(例如,行和列)。我们确定了您在项目中可能遇到的四种最常见的使用场景,这将允许您根据自己的需要修改这里的代码。
如何使用 Python 从 PDF 表单中提取数据
理解用于数据挖掘的 PDF 文档的对象模型
莱昂·德维耶在 Unsplash 上拍摄的照片
介绍
PDF 或可移植文档文件格式是当今最常用的文件格式之一。它广泛应用于企业、政府机构、医疗保健和其他行业。因此,存在大量 PDF 格式的非结构化数据,提取和分析这些数据以生成有意义的见解是数据科学家的共同任务。
我在一家金融机构工作,最近遇到一种情况,我们必须从大量 PDF 表单中提取数据。虽然有大量的工作可以用来描述从 PDF 文档中提取简单的文本,但是我很难找到一个全面的指南来从 PDF 表单中提取数据。我写这篇文章的目的就是开发这样一个指南。
有几个专门处理 PDF 文档的 Python 库,其中一些比另一些更受欢迎。出于本文的目的,我将使用 PyPDF2 。PyPDF2 是一个纯 Python 库,作为 PDF 工具包构建。作为纯 Python,它可以运行在任何 Python 平台上,没有任何依赖或外部库。您可以通过执行下面的代码来使用 pip 安装这个库。
pip install PyPDF2
一旦您安装了 PyPDF2,您应该已经准备好了。我们将快速浏览一下 PDF 文件的结构,因为这将帮助我们更好地理解从 PDF 表单中提取数据的编程基础。我将简要讨论广泛使用的两种 PDF 表单。然后,我们将直接进入示例,从两种类型的 PDF 表单中提取数据。
PDF 文件的结构
不要把 PDF 文档看作一个整体,而应该把它看作一个对象的集合。所有这些物体都以一种固定的模式排列。如果您在文本编辑器(如记事本)中打开 PDF 文件,内容可能没有多大意义,看起来像垃圾。但是,如果您使用一个工具来提供对 PDF 对象的低级访问,您可以看到并欣赏底层结构。例如,请看下面的图 1。我用 iText RUPS 打开了一个简单的 PDF 文档。左边的图片是我在阅读器应用程序(Acrobat Reader)中打开的一个简单的 PDF 文档。中间的图像显示了由 RUPS iText 渲染的该文档的低级对象模型。右边的图像显示了捕获 PDF 第一页内容的数据流。正如您所看到的,对象模型(中间的图像)有一个固定的模式,并且封装了独立于软件、硬件、操作系统等呈现文档所需的所有元数据。这种结构是 PDF 如此通用和受欢迎的原因。
图 1—PDF 文件的结构
PDF 表单
有两种主要类型的 PDF 表单。
- 基于 XFA (XML 表单架构)的表单
- Acroforms
Adobe(开发 PDF 格式的公司)有一个名为 AEM(Adobe Experience Manager)Forms Designer 的应用程序,旨在使客户能够创建和发布 PDF 表单。Adobe 使用术语 PDF 表单来指代使用 AEM Forms Designer 创建的交互式和动态表单。这些 PDF 表单基于 Adobe 的 XML Forms Architecture (XFA ),后者基于 XML。这些表单本质上可以是动态的,可以根据用户输入重排 PDF 内容。
还有另一种类型的 PDF 表单,称为 Acroform。Acroform 是 Adobe 在 1996 年作为 PDF 1.2 规范的一部分引入的较早的原始交互表单技术。Acroforms 是定义静态布局的传统 PDF 与固定在顶部的交互式表单域的组合。首先,使用 Microsoft Word、Adobe InDesign 或 Adobe Illustrator 等设计表单布局。然后添加表单元素——字段、下拉控件、复选框、脚本逻辑等。
从基于 XFA 的 PDF 表单中提取数据
下面的图 2 显示了一个基于 XFA 的 PDF 表单的截图,我们将用它作为这个练习的例子。这是银行和其他机构用来向监管机构报告某些金融交易的货币交易报告表。这是一个动态表单,您可以根据需要报告的信息量来添加和删除部分。我已经用一些虚拟数据部分地填写了这个表格。
图 2 — XFA 表单示例
图 3 显示了这个表单的对象模型。图像右侧显示的 XML 文档构成了 XFA,它作为 XFA 键的值存储在 AcroForm 字典中(请看图像左侧的对象模型)。Acroform 字典是目录字典的子元素,目录字典位于 PDF 文件的根目录中。我们需要做的就是使用 PyPDF2 从这个文件的对象结构中访问 XML 文档。一旦我们访问了 XML,就很容易解析出 XML 文档来访问各种表单元素的值,然后可以将这些值存储到 Python 列表、Numpy 数组、Pandas dataframe 等中。为了分析的目的。
图 3 —示例 XFA 的对象模型
下面是提取组成这个表单的 XML 的代码。
import PyPDF2 as pypdfdef findInDict(needle, haystack):
for key in haystack.keys():
try:
value=haystack[key]
except:
continue
if key==needle:
return value
if isinstance(value,dict):
x=findInDict(needle,value)
if x is not None:
return xpdfobject=open('CTRX_filled.pdf','rb')pdf=pypdf.PdfFileReader(pdfobject)xfa=findInDict('/XFA',pdf.resolvedObjects)
xml=xfa[7].getObject().getData()
在第一行中,我只是导入 PyPDF2 库,并为它提供一个别名——pypdf。第二行是函数定义的开始,通过提供字典键来查找字典的元素。您可能还记得我们上面的讨论,我们的 XML 嵌入在一个由键“/XFA”引用的字典中。这个函数帮助我导航 PDF 文件的复杂对象模型,它基本上是嵌入在多组字典中的一组字典。在函数定义之后的一行中,我正在读取 PDF 表单并创建一个 PdfFileReader 对象。该类的 resolvedObjects 方法将 PDF 对象模型分解为一组 Python 字典。然后,我调用 find submit 函数提取“/XFA”字典的元素,这是一个数组,如下面的图 4 所示。
图 4 — XFA 阵列
这个数组的第七个元素是组成表单的实际 XML 内容。它是一个间接对象。IndirectObject 是指向实际对象的别名。当同一对象出现在多个位置时,此引用有助于减小文件的大小。代码最后一行中使用的 getObject()方法检索实际的对象。如果对象是一个文本对象,使用 str()函数应该会给出实际的文本。否则,需要使用 getData()方法来呈现对象中的数据。下面是在上面代码的最后一行中检索到的一部分 XML 的快照。您可以看到我在示例表单中输入的一些虚拟地址数据。您可以很容易地从 XML 中解析出这些数据,并将其用于进一步的分析。
图 5 —从 XFA PDF 表单中检索到的 XML 的快照
从 Acroforms 中提取数据
这一个相对容易,因为我们已经在上面的章节中讨论了与 PDF 对象模型相关的大部分概念。下面是一份所得税表格的样本,我将用它作为例子。我在里面放了一些假数据。
图 6 — Acroform 示例
下面的图 7 显示了这个表单的对象模型。
图 7 — Acroform 示例对象模型
各个表单字段的值由嵌入在“/Fields”中的键“/V”引用,而键“/V”又嵌入在“/AcroForm”中。“/AcroFrom”是此 PDF 文件的根目录字典的子目录。我们可以使用我们在 XFA 表单中使用的方法,使用‘find submit’函数来检索’/Fields '字典,然后检索各个字段的值。幸运的是,PyPDF2 提供了一种更直接的方法来实现这一点。PdfFileReader 类提供了一个 getFormTextFields()方法,该方法返回所有表单值的字典。下面是简短的代码。图 8 显示了输出。dictionary 对象可以很容易地转换成一个列表或一个熊猫数据帧,以便进一步处理。
import PyPDF2 as pypdfpdfobject=open('incometaxform_filled.pdf','rb')pdf=pypdf.PdfFileReader(pdfobject)pdf.getFormTextFields()
图 8 — AcroForm 示例输出
结论
一旦您理解了底层对象模型,从 PDF 表单中提取数据就很容易了,PyPDF2 是一个强大的库,使您能够访问它。享受数据带来的乐趣!
如何从任何 Youtube 视频中提取面部表情、头部姿势和凝视
数据科学教程
使用 Google Colab & OpenFace 从 Youtube 视频中提取面部特征的教程,无需在笔记本电脑上安装任何程序。
通过研究人们的面部表情、头部姿势和凝视信息,可以研究和分析人们的感受、想法和兴趣。有许多公司和计算机视觉算法可以帮助从面部视频中提取这些面部特征,包括 Emotient 和 Affectiva(它们的算法对比这里、这里),但很少有公司免费提供这些服务,大多数公司要求用户购买订阅或按视频分钟付费。
在这篇文章中,我分享了一个免费的、易于使用的、健壮的面部特征提取付费服务的替代方案,它使用了 OpenFace ,这是一个最先进的面部动作单元识别、凝视估计、面部标志检测和头部姿势估计工具。在这里,我分享如何使用 Google Colab Jupyter 笔记本的说明,它允许你设置 OpenFace 并从任何 Youtube 视频中提取面部特征,而不必在你的笔记本电脑上安装一个软件包。
1.设置
您不需要在您的笔记本电脑上安装任何东西,但是您仍然需要在您的 Colab 实例上安装 OpenFace 包。不幸的是,这一部分可能需要一段时间(大约 40 分钟),这段时间非常适合你看一些 Youtube 视频,以确定你想从哪个视频中提取面部特征。哦,你可能需要一个谷歌账户。
2.找个 Youtube 视频分析一下。
找一个你想分析的 Youtube 视频。它可以是一个人的面部视频,也可以是多个人的面部视频。只是要小心避免视频中的人脸太小,这使得大多数算法很难找到人脸。在本教程中,我们将从我和我的同事为 Pioneer.app 推出的一个应用创意 TasteSpace 中提取面部特征。下面的代码将向您展示感兴趣的视频。
这是我们将要使用的视频…我们正在描述一个名为 TasteSpace 的项目。
接下来的几行代码下载视频并剪辑视频的前几秒(10 秒)。这只是为了节省处理时间,所以如果你想处理整个视频,可以随意移除第五行的-t 10
标志。
如果你想从整个视频中提取特征,你可以去掉“-t 10”标志(这会花更长时间)。
3.使用 OpenFace 处理视频
现在我们将使用可以同时从多张人脸中提取面部特征的FaceLandmarkVidMulti
。
如果你在视频中一次只有一张脸,那么你可以使用FeatureExtraction
来代替,或者如果你想从图像中提取特征,可以使用FaceLandmarkImg
。单击此处查看命令行函数及其参数的完整列表。
4.可视化结果!
您可以使用下面的代码来可视化结果,如果输出有意义,您可以直接从笔记本上检查。
5.下载输出。
你现在可以通过打开你的 Colab 笔记本左边菜单上的文件标签来下载提取的面部特征,并将文件下载到processed/videos.csv
文件夹中。
展开文件选项卡并下载结果。
结论
希望这是一个有趣的练习,教你如何使用 Google Colab 和 OpenFace 在几分钟内(安装后)从任何 Youtube 视频中提取面部特征。如果你有兴趣了解更多关于如何在这种面部表情数据中分析个体之间的同步性,请随时查看我以前关于如何做到这一点的帖子。
用于计算同步指标的样本代码和数据,包括皮尔逊相关、时滞交叉相关…
towardsdatascience.com](/four-ways-to-quantify-synchrony-between-time-series-data-b99136c4a9c9)
额外学分
如果你还在读这篇文章,你可能会对如何处理 OpenFace 的输出感兴趣,这里有一些额外的代码可以帮助你入门。
加载数据
首先,我们将数据加载到 Pandas 数据帧中,重命名列以消除空白,评估数据帧的形状、数据的最高帧数,并绘制数据的头部。
从视频中计数唯一个体的数量
您可能会注意到第face_id
列,它试图区分视频中的个人。
看起来我们有 4 张不同的脸,而不是 3 张!
从视频中检测人脸的平均模型置信度
我们可以使用以下函数进一步评估该算法检测每个人脸的置信度。
可视化视频中人脸的位置
我们看到face_id==3
具有最低的置信度,这可能是被检测到的伪造人脸。让我们通过在整个剪辑中绘制人脸的位置来进一步检查这一点。
我们可以看到,在左边的图中,face_id==3 的脸确实在某个不存在脸的地方。我们可以根据任意置信水平(这里我们使用 80%)设定输出阈值,在左侧的图中我们可以看到,我们已经消除了伪脸。
分析面部肌肉随时间的运动
现在让我们画出每张脸的每个动作单元预测的轨迹随时间的变化情况。然后,我们将打印出视频中人们在一段时间内是如何相似地微笑的(动作单元 12)。
每个 face_id 的 AU 强度预测随时间的时间序列
每对个体微笑的相关性(AU12)。
随着时间的推移分析眼睛凝视
最后,我们可以画出每个人在看哪里。这可能不是画弧度角的最好方法,但是你仍然可以感觉到每个面在看哪里。这通过了完整性检查,即左边的面(face_id2)主要从原点(0,0)看向右边,右边的面(face_id0)看向左边,中间的面看向两边。
如果你想了解更多关于不同输出的信息,我强烈推荐你在 OpenFace wiki 中阅读更多关于每个输出代表什么的信息。
在媒体上阅读金贤昌的作品。人类行为和数据科学爱好者||认知神经科学博士…
medium.com](https://medium.com/@jinhyuncheong)
如何使用值从 Python 字典中提取键
从 python 字典给定值中提取键的四种方法
如果我们有钥匙,提取价值就像用钥匙开锁一样简单。但是,反过来就没那么简单了,像“开锁”,可能!
有时候提取键变得很重要,尤其是当键和值是一对一的关系时。也就是说,当它们中的任何一个是唯一的,因此可以充当键时。
在研究各种方法之前,首先我们将创建一个字典来进行说明。
currency_dict 是以货币缩写为键,货币名称为值的字典。
currency_dict={'USD':'Dollar',
'EUR':'Euro',
'GBP':'Pound',
'INR':'Rupee'}
如果有键,只需将键加在方括号中就可以得到值。
例如, currency_dict[‘GBP’] 将返回 'Pound '。
方法 1:使用列表
步骤 1:将字典键和值转换成列表。
第二步:从值列表中找到匹配的索引。
步骤 3:使用索引从密钥列表中找到合适的密钥。
key_list=list(currency_dict.keys())
val_list=list(currency_dict.values())
ind=val_list.index(val)
key_list[ind]Output: 'GBP'
所有这三个步骤可以合并为一个步骤,如下所示:
list(currency_dict.keys())[list(currency_dict.values()).index(val)]
方法 2:使用 For 循环
方法 1 可以使用一个 for 循环稍微修改一下,如下:
步骤 1:将字典键和值转换成列表。
第二步:遍历值列表中的所有值,找到需要的值
第三步:从键列表中返回对应的键。
def return_key(val):
for i in range(len(currency_dict)):
if val_list[i]==val:
return key_list[i]
return("Key Not Found")return_key("Rupee")Output: 'INR'
方法 3:使用项目()
items()将字典元素保持为键值对。
步骤 1:遍历 item()中的所有键值对。
步骤 2:找到与所需值匹配的值
步骤 3:从键-值对中返回键。
def return_key(val):
for key, value in currency_dict.items():
if value==val:
return key
return('Key Not Found')return_key('Dollar')Output: 'USD'
方法 4:使用 Pandas 数据框架
在我看来,在转换成数据帧后获取密钥是最简单易懂的方法。
然而,这并不是最有效的方法,在我看来,这应该是方法 1 中的一行程序。
字典可以转换成如下熊猫数据帧:
df=pd.DataFrame({'abbr':list(currency_dict.keys()),
'curr':list(currency_dict.values())})
所有键都在列’*缩写’中,所有值都在数据帧’ df’ 的’ curr’ 列中。
现在查找值非常简单,只需从【curr】列的值为所需值的行返回【缩写】*列的值。
df.abbr[df.curr==val]Output: 2 GBP
比听起来简单多了!
注意,输出也包含索引。输出不是字符串格式,但它是熊猫系列对象类型。
可以使用许多选项将 series 对象转换为 string,下面是几个选项:
df.abbr[df.curr==val].unique()[0]
df.abbr[df.curr==val].mode()[0]
df.abbr[df.curr==val].sum()Output : 'GBP'
资源
这篇文章的代码可以在我的 GitHub Repo 中找到。
如果你对视觉格式更感兴趣,你可以看看我的 YouTube 视频
作者的 YouTube 教程
成为会员
我希望你喜欢这篇文章,我强烈推荐 注册中级会员 来阅读更多我写的文章或成千上万其他作者写的各种主题的故事。
你的会员费直接支持我和你看的其他作家。你还可以在 Medium 上看到所有的故事。
这里是我的一些其他文章,你可能会觉得有趣…干杯!
在你的媒体文章中嵌入代码的两种简单方法。
abhijithchandradas.medium.com](https://abhijithchandradas.medium.com/how-to-embed-code-in-medium-4bd380c8102d) [## 如何在 Matplotlib/ Seaborn 中向散点图添加文本标签
使用 Seaborn 或 Matplotlib 库时,如何在 python 中向散点图添加文本标签的分步指南。
towardsdatascience.com](/how-to-add-text-labels-to-scatterplot-in-matplotlib-seaborn-ec5df6afed7a) [## 新冠肺炎酒吧比赛图表使用繁荣
竞赛条形图是一个非常简单的工具,可以用来比较随时间变化的数量。简单来说,就是一个条形图…
towardsdatascience.com](/covid-19-bar-race-chart-using-flourish-89136de75db3)
照片由 Hitesh Choudhary 在 Unsplash 上拍摄
如何从维基百科中提取知识,数据科学风格
WikiData 和 SPARQL 查询语言简介
作为数据科学家,人们倾向于认为他们所做的是开发和试验复杂的算法,并产生最先进的结果。这在很大程度上是真实的。这是数据科学家最引以为豪的,也是最具创新性和回报最大的部分。但是人们通常看不到的是他们为收集、处理和整理数据而付出的汗水,这些数据带来了巨大的成果。这就是为什么你可以看到 SQL 出现在大多数数据科学家的职位要求上。
SPARQL 是什么?
T 这是另一种查询语言,在从多个来源和数据库获取数据时可能非常有用,维基百科是其中最大的一个。查询语言叫做 SPARQL 。根据维基百科:
SPARQL (读作" sparkle ",是 SPARQL 协议和 RDF 查询语言的递归缩写词)是一种 RDF 查询语言——也就是说,一种用于数据库的语义 查询语言——能够检索和操作存储在资源描述框架(rdt23)中的数据
这不是一个很好的定义。它几乎没有告诉你它能做什么。把它翻译成人类可读的语言:
SPARQL 是一种语法上类似于 SQL 的查询语言,但它工作在像 Wikipedia 这样的知识图数据库上,允许您通过定义一系列过滤器和约束来提取知识和信息。
如果这对你来说还是太抽象,请看下图:
获得诺贝尔化学奖
这是一个诺贝尔化学奖的时间表,由维基数据查询服务网站使用以下代码生成:
#Awarded Chemistry Nobel Prizes
#defaultView:Timeline
SELECT DISTINCT ?item ?itemLabel ?when (YEAR(?when) as ?date) ?pic
WHERE {
?item p:P166 ?awardStat . # … with an awarded(P166) statement
?awardStat ps:P166 wd:Q44585 . # … that has the value Nobel Prize in Chemistry (Q35637)
?awardStat pq:P585 ?when . # when did he receive the Nobel prize
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
OPTIONAL { ?item wdt:P18 ?pic }
}
任何熟悉 SQL 的人都会发现上面的代码非常直观。我将使用另一个例子来解释基本上如何制定类似的查询来获得您感兴趣的结果。
起点:维基百科页面
PARQL 在多个知识图数据库上工作。要知道什么是知识图谱,先从大家都熟悉的东西说起:维基百科。当大多数人想要研究一个主题时,维基百科是他们的首选。如果你去 Python 创始人吉多·范·罗苏姆的页面,你会看到一个详细的页面,里面有各种有用的信息。
组织页面:维基数据
这个页面的问题在于它没有条理。你可以搜索关键词,但是你不能轻易地找出信息节点之间的关系。这就是知识图表发挥作用的地方。上面页面上的红色矩形拼写为“Wikidata Item”,单击它会将您带到同一页面的知识图表视图:
开始查询
在我们看到之前,所有关于 Guido 的信息都被很好地组织成类别,每个类别都有多个条目。使用 SPARQL,您可以很容易地查询这些信息。为此,维基百科提供了另一个页面,一个用户友好的查询服务,名为维基数据查询服务:
这是我们可以试验 SPARQL 的地方。在 WikiData 页面上,我们观察到 Guido 是一名程序员(显然!),现在如果我们想知道在维基百科上有条目的其他程序员呢?让我们看看 SPARQL 代码:
SELECT ?personWHERE {?person wdt:P106 wd:Q5482740 .}
这里我们定义了一个?person
作为感兴趣的主题,这也是我们的查询结果中的一列。然后我们用WHERE
指定一些约束。约束是wdt:P106
需要是wd:Q5482740
。什么?你说。让我更详细地解释一下。wdt
是主语的“谓语”或“属性”的前缀,而wd
是属性的值(SPARQL 术语中的对象,但这并不重要)的前缀。wdt:
表示我将在这里指定主题的一个属性,wd:
表示我将指定这个属性的值。那么什么是P106
和Q5482740
?这些只是特定属性和值的代码。P106
代表‘职业’,Q5482740
代表‘程序员’。这行代码的意思是,我想让?person
主题有一个‘程序员’的‘职业’属性。没那么可怕了,对吧?你可以在上面提到的维基数据页面上很容易地找到这些代码。
运行查询,您将获得以下结果:
从代码到名称
我们得到了一堆person
不同wd:value
的物品。如果你仔细观察这个值,它们实际上是另一个人的代码。比如第一个wd:Q80
是WWW 的发明者蒂姆·伯纳斯·李。这是不直观的,我们希望能够直接看到名字。为此,我们添加了一个 WikiData“标签服务”,帮助我们将代码转换为名称,如下所示:
SELECT ?person ?personLabelWHERE { ?person wdt:P106 wd:Q5482740 .
?person rdfs:label ?personLabel .
FILTER ( LANGMATCHES ( LANG ( ?personLabel ), "fr" ) )
}
类似的语法,我们希望person
有一个‘label’属性,我们定义了一个personLabel
值变量来保存这些值,这样我们就可以在查询结果中显示它们。此外,我们将personLabel
添加到我们的SELECT
短语中,因此它将被显示。请注意,我还在下面添加了一个过滤器,只显示法语语言标签,否则将为一个人显示多个语言标签,这不是我们想要的:
缩小范围
从上面的结果中,我们可以看到我们有大约 790 个结果。这太多了。让我们把范围缩小到那些在行业中“重要”的人。具有“值得注意的工作”属性的人:
SELECT ?person ?personLabel ?notableworkLabelWHERE {?person wdt:P106 wd:Q5482740 .
?person rdfs:label ?personLabel .
FILTER ( LANGMATCHES ( LANG ( ?personLabel ), "fr" ) )
?person wdt:P800 ?notablework .
?notablework rdfs:label ?notableworkLabel .
FILTER ( LANGMATCHES ( LANG ( ?notableworkLabel ), "fr" ) )
}
再次,wdt:P800
表示‘值得注意的作品’属性,其他都类似。然后我们得到以下结果:
组合多个标签
现在我们只有 175 个结果,每个人值得注意的工作也列出来了。但是等等,为什么我们有五个理查德·斯托尔曼?原来,理查德有不止一部著名的作品,因此在搜索结果中多次出现。让我们通过将所有值得注意的工作归入一个属性来解决这个问题:
SELECT ?person ?personLabel ( GROUP_CONCAT ( DISTINCT ?notableworkLabel; separator="; " ) AS ?works )WHERE {?person wdt:P106 wd:Q5482740 .
?person rdfs:label ?personLabel .
FILTER ( LANGMATCHES ( LANG ( ?personLabel ), "fr" ) )
?person wdt:P800 ?notablework .
?notablework rdfs:label ?notableworkLabel .
FILTER ( LANGMATCHES ( LANG ( ?notableworkLabel ), "fr" ) )
}GROUP BY ?person ?personLabel
这里用的是‘T1’。还有,GROUP_CONCAT
函数用于将多个notableworkLabel
串联成一个新列works
( 我不会解释这些函数是如何工作的,只是想快速向您展示 SPARQL 能做什么。如果你想了解更多,请随时谷歌,那里有大量的教程文章和视频):
表面
现在我们有一个 90 个结果的列表,包括软件工程世界中所有的“名人录”。但是 SPARQL 可以做得更多。让我们给这些名字添加一些面孔:
SELECT ?person ?personLabel ( GROUP_CONCAT ( DISTINCT ?notableworkLabel; separator="; " ) AS ?works ) ?imageWHERE {?person wdt:P106 wd:Q5482740 .
?person rdfs:label ?personLabel .
FILTER ( LANGMATCHES ( LANG ( ?personLabel ), "fr" ) )
?person wdt:P800 ?notablework .
?notablework rdfs:label ?notableworkLabel .
FILTER ( LANGMATCHES ( LANG ( ?notableworkLabel ), "fr" ) )
OPTIONAL {?person wdt:P18 ?image}
}GROUP BY ?person ?personLabel ?image
同样的模式,我们只是添加了一个OPTIONAL
关键字 prior,因为我们不想排除那些在个人资料中没有图片的人。我们还将视图切换到“图像网格”:
他们在哪里?
哇!这样好多了。我看到了一些熟悉的面孔!也许你想知道这些家伙在哪里?让我们来看看:
#defaultView:ImageGridSELECT ?person ?personLabel ( GROUP_CONCAT ( DISTINCT ?notableworkLabel; separator="; " ) AS ?works ) ?image ?countryLabel ?coodWHERE {
?person wdt:P106 wd:Q5482740 .
?person rdfs:label ?personLabel .
FILTER ( LANGMATCHES ( LANG ( ?personLabel ), "fr" ) )
?person wdt:P800 ?notablework .
?notablework rdfs:label ?notableworkLabel .
FILTER ( LANGMATCHES ( LANG ( ?notableworkLabel ), "fr" ) )
OPTIONAL {?person wdt:P18 ?image} OPTIONAL {?person wdt:P19 ?country .
?country rdfs:label ?countryLabel .
?country wdt:P625 ?cood .
FILTER ( LANGMATCHES ( LANG ( ?countryLabel ), "fr" ) )
}}GROUP BY ?person ?personLabel ?image ?countryLabel ?cood
你也许可以破译你上面的密码。基本上就是说我要这个人有一个属性country
,放入一个变量country
,然后找出国家的coordinates
,放入一个变量cood
。有了坐标,我们可以激活“地图”视图:
我们可以看到,美国有很多,欧洲有一些,世界其他地方也有一些。
更多示例
通过几行代码,我们找出了软件行业中的重要影响者,他们为人所知,他们在哪里,他们看起来怎么样。如你所见,这里的潜力是无限的。
你可以点击维基数据页面上的“示例”按钮,找到更多有趣的例子。
作为本文的一项任务,您能想出如何添加“出生日期”属性并生成一个类似本文开头的时间线图吗?
结论
在这篇文章中,我们使用 WikiData 作为知识图示例来介绍 SPARQL 查询语言。还有其他知识图表,如 DBpedia 等。这篇文章绝不是一个全面的教程。我只是想把这种语言介绍给更多的人,这样知识和信息的提取就能更有效地进行。
觉得这篇文章有用?在 Medium 上关注我(李立伟)或者你可以在 Twitter @lymenlee 或者我的博客网站wayofnumbers.com上找到我。你也可以看看我下面最受欢迎的文章!
为什么 CS50 特别适合巩固你的软件工程基础
towardsdatascience.com](/this-is-cs50-a-pleasant-way-to-kick-off-your-data-science-education-d6075a6e761a) [## 一枚硬币的两面:杰瑞米·霍华德的 fast.ai vs 吴恩达的 deeplearning.ai
如何不通过同时参加 fast.ai 和 deeplearning.ai 课程来“过度适应”你的人工智能学习
towardsdatascience.com](/two-sides-of-the-same-coin-fast-ai-vs-deeplearning-ai-b67e9ec32133) [## 你需要了解网飞的“朱庇特黑仔”:冰穴📖
是时候让 Jupyter 笔记本有个有价值的竞争对手了
towardsdatascience.com](/what-you-need-to-know-about-netflixs-jupyter-killer-polynote-dbe7106145f5)
解决基于人工智能的搜索引擎的最大挑战之一:相关性
让我们学习如何实现点击模型,以便从点击流数据中提取相关性。
图片作者:约书亚·戈德
构建搜索引擎系统通常遵循一些众所周知的步骤:
- 为搜索操作选择合适的数据库。
- 保存一组文档。
- 将转换应用到文档字段(删除重音符号、过滤复数、断开空格……)。
- 创建检索这些文档的查询规则。
这些步骤往往是为给定应用程序实现足够有效的搜索引擎系统所必需的。
最终,可能需要升级系统以提供定制的结果。这样做应该很简单。人们可以从一组机器学习排序算法中进行选择,训练一些选定的模型,为生产做准备并观察结果。
事实上,除了一个缺失的部分之外,它可能就是这么简单:不管选择的排名模型是什么,我们仍然需要以某种方式准备一个能够教授算法如何正确排名的训练数据集。无论如何,一定会有一个数据集告诉算法什么是好文件,什么是坏文件。
这将是这篇文章的重点。为了用人工智能算法推动搜索引擎更上一层楼,一个“教导”算法如何正确排列结果的训练数据是根本。
我们将讨论如何使用 ClickModels ,一个使用概率图形模型 (PGM)的字段,来开发一组解释用户和检索到的文档之间的交互的变量。这些变量将为我们提供相关性(或判断,也在文献中已知)的概念,它基本上作为一个标记,表明一个文档对于给定的搜索查询有多少价值。
用于从点击流数据推断相关性的图形模型示例。图片摘自 clickmodels 图书公开发售。
我们的挑战将是创建一个概率模型,从用户交互中学习每个查询和上下文有多少相关文档。基于 Cython 构建的最终代码可以在 pyClickModels 存储库中找到(Cython 是必需的,因为这些算法的优化过程可能需要相当长的时间才能收敛)。
所以,事不宜迟,让我们看看如何将搜索引擎提升到一个新的水平。
那么,相关性为什么?
弄清楚什么对人们是相关的可能是相当具有挑战性的。想象一下,为一个电子商务商店建立一个搜索引擎。
搜索查询“智能手机”的搜索结果示例。图片作者。
在这种环境下(我们可以说大多数检索引擎在相似的环境下工作),观察到的数据包含:
- 用户在搜索什么。
- 搜索的背景(用户的地区、人口统计数据、他们的偏好等等)。
- 他们点击的产品。
- 他们点击后购买的产品。
我们期望从搜索结果页面购买的产品是非常相关的,所以它们应该有一个良好的相关性得分。但是后来我们意识到,可能有一些产品没有展示给用户(例如,在第 2 页或更高的页面上的产品),他们最终会享受到更多!
不仅如此,在向用户排列项目时,往往会观察到几个模式。例如,结果页面上的第一个文档往往比其他文档获得更多的点击,这不一定是因为它是适合查询的产品,而仅仅是因为它位于目录的第一个位置(也称为“位置偏差”)。
现在事情开始变得棘手了。
找到什么与人们相关的一个方法就是简单地问他们。有趣的是,这实际上是一些公司使用的一种可用的解决方案。但是这种方法的缺点是,它不能很好地扩展,而且通常不太准确。
另一种方法,也是我们感兴趣的方法,从点击流的数据中推断出隐含的相关性。点击流数据基本上是用户与搜索引擎系统本身的浏览交互的记录。这里有一个例子:
点击流数据示例。
我们可以使用这些信息来模拟每个文档与每个查询的相关程度。
点击救援模型!
从点击流数据中提取相关性的一种方法是使用由 PGM 组成的点击模型,以推断用户点击文档的可能性。我们可以假设点击的概率越高,相应地,文档可能越相关。
接下来,这里讨论的想法和概念是从 Aleksandr Chuklin 和其他人的书网络搜索的点击模型中摘录的。
我们有许多方法来模拟用户与文档排序列表的交互。这里,[动态贝叶斯网络](https://en.wikipedia.org/wiki/Dynamic_Bayesian_network#:~:text=A%20Dynamic%20Bayesian%20Network%20(DBN,other%20over%20adjacent%20time%20steps.) (DBN)方法将被选为讨论和实现的方法。请记住,一旦您理解了模型背后的概念和理论,您就可以使用您认为合适的任何变量来推断这些知识。例如,亚历山大的书讨论了其他几种模型。
首先,这里是用于从数据中提取相关性的 DBN 的图形表示:
为查找与搜索引擎结果相关联的文档的相关性而实现的图形模型的示例。图片作者。
这个模型中的所有变量都遵循伯努利分布,这意味着它们可以是 0 或 1,有一定的概率 p。这些是从网上掌握的主要概念:
r
表示与搜索页面中给定文档相关联的位置;r=0
表示第一个文件,r+1
表示从r
位置开始的下一个文件。u
是文档的标识符。E_r
是一个被称为“考试”的随机变量。顾名思义,它决定了用户是否检查了文档(即 E=1)或 E=0)。如果没有经过检查,文档就不会有点击和购买。A_u
表示对应文档u
对结果是否有吸引力。如果文档是吸引人的(A=1),则观察到点击事件。S_ur
表示位置 r 的文件是否令客户满意。当他们满意时(S=1),他们停止检查新文档。购买的文件被认为是令人满意的。C_r
是观察到的点击变量,来自点击流数据集。P_r
与观察到的购买事件相关。如果 P=1,那么 S=1。这个变量只有在文档出售时才有意义。- γ 是用户在不满意时继续检查大于
r
位置的文档的概率。
使用我们之前的智能手机示例,以下是 DBN 的表示方式:
与智能手机搜索结果关联的 DBN 模型。图片作者。
请注意,对于每个文档,我们都关联了一组潜在变量(At 吸引力, S 满意度, E 检查),这些变量模拟了用户如何以及为什么与引擎结果交互。点击和购买用灰色填充,因为它们是观察变量(点击流数据)。
这里有一个问题:如果我们指定代表每个潜在变量的概率的值,我们可以使用这些相同的值来推断每个文档与每个搜索查询的相关性。
例如,假设我们将 α 与 σ 相关联,以表示给定文档对用户有吸引力的概率。如果我们使用一些优化技术从数据中学习这些值应该是什么,我们可以找到每个文档的相关性。
为此,让我们开始用一组规则来描述我们的网络(这些规则将用于优化过程):
DBN 主要方程用来描述优化过程应该如何操作。
以下是对每条规则的简要解释:
(1) 表示在r-1
处的先前文档未被检查的情况下,用户检查给定等级r
处的给定文档的概率为零。
(2) α是决定吸引力概率等于 1 的参数。
(3) 如果一个文档被检查并且有吸引力,我们必须观察点击。
(4) 如果一个文档没有被点击也没有被购买,那么对于给定的查询,它不能被认为是满意的。
(5) 如果一个文档被点击但没有被购买,文档满意的概率是σ。
(6) 如果观察到点击和购买,满意度为 1。
(7) 如果之前的文档令人满意,用户将不会继续检查新产品。
(8) 如果一份文件不符合要求,且之前的文件已经过检查,则客户将继续检查新文件,可能性为 γ。
(9) 观察到点击的概率由点击给定检查的概率乘以由α * ε给出的检查概率(贝叶斯规则,其扩展为与被点击和检查的概率相同)给出。
有了支配 DBN 模型的方程,可以使用一些技术来找到最好地解释观察到的数据的α、σ和 γ 的值。
第一种技术是最大似然估计( MLE )的直接实现。它基本上包括找到模型可能性的表达式(用对数表示),即在给定模型变量的情况下观察到数据的概率。
在我们的例子中,我们的 DBN 具有以下对数似然表达式:
- X 是用于描述数据的每个伯努利变量(在我们的例子中,是“A”、“S”和“E”)。
- C 和 P 是观察到的点击量和购买量。
- ψ 是我们要寻找的描述数据的变量集合(α,σ和 γ )。
求和发生在代表会话的“ s 上,它代表用户与搜索引擎的交互。
在 MLE 方法中,我们可以简单地对每个潜在变量取这个表达式的导数,并使其等于零。但是这种方法效果不太好。问题是,由于潜在的变量,最终的表达式很难求解。
这实际上是一个已知的问题。事实证明,除了 MLE,另一种技术是期望最大化算法(EM)(它的工作方式有点像流行的 kMeans 算法)。
它首先将随机期望值分配给潜在变量α、σ和 γ 。然后,通过使用特定的成本函数,继续迭代优化过程。为变量分配新值,并重复该过程,直到达到收敛或总迭代次数。
用作优化参考的成本函数由下式给出:
它类似于前面看到的对数似然表达式,但它用随机变量的期望值代替了表达式的一部分,这使得求导变得容易得多(但它最终也是最优解的近似值)。
这是我们的模型中定义的成本函数 Q :
Par(X)= p指变量 X 的双亲。例如,在我们的 DBN 中,给定网络的边连接,变量 S (满意度)将点击和购买作为其父变量。变量 θ 代表我们试图寻找的潜在参数(α等)。 I 是指示函数, Z 只是与 θ 无关的值的参考,在推导过程中会被丢弃。
通过使用随机变量的期望值,我们所完成的是,现在推导这个方程要简单得多。这是我们已经得到的 θ 的隔离结果:
这基本上是期望最大化算法的本质。我们首先将对数似然表达式中的随机变量替换为它们的期望值,然后推导出使其等于零的方程。我们获得了用于每个变量的优化规则(等式 10 ),该优化规则应该缓慢地收敛到局部或全局最小值。
让我们看看如何使用等式 10 的定义来调整每个变量。
吸引力——α
首先,吸引力变量被定义为:
q 表示查询,而 u 表示文档。在我们的 DBN 表示中,注意α没有任何父代,所以它是直接定义的。
为了开发它的优化方程,首先我们需要如下描述与文档检查相关联的概率:
其中cr
是给定查询q
的给定文档u
的转化率,定义为总销售额除以该文档在给定查询 q 的结果页面中出现的总次数。它只在文件出售时定义,否则它被认为是零。
到目前为止,我们知道:
其中|S|是查询 q 的搜索结果页面返回文档 u 的所有会话的基数。
注意,给定我们的 DBN 的架构,变量C
和P
是独立的给定C
,这意味着我们只需要考虑前者:
等式 13 可以进一步展开如下:
如果在r
上方观察到任何点击,则C_{>r}
为 1,否则为 0。
对于分子 14,我们可以进一步展开为:
分母有点复杂:
等式 14.4 应该递归实现。你可以在 pyClickModels 上看到它是如何完成的,这里有一个例子:
最后,我们可以使用所有这些等式,并将它们融合在一起,得出调整吸引力变量的最终规则:
您可以在这里看到这个规则是如何在 pyClickModels 上实现的:
满意度——σ
在我们的 DBN 中,满意度变量σ确实有双亲。因此,根据等式 10,我们只需要在定义变量的地方使用会话,给定适当的父变量。
具体来说,等式 5 已经描述了它。我们有:
因此,使用等式 10,我们得到:
S'_{uq}
包含文档u
被点击但未被购买的所有会话。
(16)的分子可以进一步展开为:
这直接归结为满足的适应规则:
这比吸引力更直接。这个等式是如何实现的:
坚持——𝛾
现在,最具挑战性的变量出现了。
注意,正如我们的 DBN 中所定义的,持久性是全局定义的,也就是说,它不依赖于要定义的查询或文档。
如前所述,它由下式给出:
为了获得𝛾的更新规则,我们将使用以下预期充分统计(ESS):
其中E_r
和S_ur
是E_{r+1}
的父母。
为了进一步开发 19,可以实现辅助功能φ。我们会有:
其中:
策略是将等式 20 分成 3 个主要部分:
第三个发展为:
为了发展内部概率方程,我们有:
还有一点:
用 22 和 23 乘以 21,我们最终得到:
第一个公式为(注意可变转换率在这里被称为“w”):
最后,第二个等式是等式 1 至 9 的直接实现。
你可以在这里看到这三个等式是如何实现的:
更新参数很简单:
最后,这就是实现前面定义的 DBN 所需的全部工作。
好吧,现在回到我们的主要目标,我们如何从中提取相关性?
最后…相关性
现在很简单了。在使用点击流数据训练模型之后,我们将获得吸引力和满意度的优化值(记住这些值仍然可以指局部最优值)。
排名相关性或判断仅仅是两者的产物,即:
在 pyClickModels 中,可以在拟合模型后导出判断值。为每个搜索查询/上下文和所有相应的文档创建一个换行符分隔的 JSON 文件。
将所有这些放在一起:编码时间
现在让我们来看看所有这些概念的实际应用。
事实证明,我们可以使用谷歌大查询上的公共数据集来测试这些想法。在实践中,我们将查询 Google Analytics 的一个样本,从中我们可以提取客户,他们搜索、点击和购买了什么(尽管如此,我们只能访问很少的数据,所以这仍然是一个简单的实验)。
下面是我们测试所需的代码:
它需要 GCS 客户端和 pyClickModels,两者都可以安装:
pip install pyClickModels google-cloud-storage
只需将代码复制并粘贴到您的本地,然后用 Python 运行它。文件将在/tmp/pyclickmodels/model/model.gz
保存。打开该文件,您应该看到几行 JSON 代码,如下所示:
请注意,库返回整个搜索上下文作为关键字(在这种情况下,它使用用户通过哪个渠道组访问网站以及他们的平均消费券作为信息)。值是该搜索上下文的每个文档以及相关联的相应判断,范围从 0 到 1。
结论
差不多就是这样了!
通过使用 PGMs,我们可以使用尽可能多的潜在变量来描述观察数据的行为。正如我们已经看到的,我们这样做的方式是,我们可以提取一些概念,如一个文档可能有多吸引人,以及用户在看到该文档时有多满意。
有了这些相关性值,我们可以训练学习来排列模型,使搜索引擎进入下一个操作级别,使它们能够为每个用户及其各自的上下文检索个性化结果,只要这些已经在模型中训练过。
从那时起,可以在搜索引擎内部定制更复杂的算法,从简单的决策树到从数据中完全捕捉统计细微差别的深度学习网络。不过,只有在相关性数据可用的情况下,这才是可能的,否则就没有办法教授学习算法如何正确排序。
完整的代码实现可以在 pyClickModels 开源存储库中找到:
ClickModels 的 Cython 实现,使用概率图形模型来推断用户在交互时的行为…
github.com](https://github.com/WillianFuks/pyClickModels)
参考
[2]https://clickmodels.weebly.com/
[3]https://github.com/varepsilon/clickmodels
https://www.cs.ubc.ca/~murphyk/Thesis/thesis.html
https://en.wikipedia.org/wiki/Maximum_likelihood_estimation
[7]https://static . Google user content . com/media/research . Google . com/en//pubs/archive/46485 . pdf
https://en.wikipedia.org/wiki/Conditional_independence
如何用 Python 从图像中提取文本
学习用 3 行代码从图像中提取文本
肖恩·林在 Unsplash 上的照片
在这篇短文中,我将向您展示如何使用 Python 从图像中提取文本。这项技术的应用是无止境的。一些例子包括:
- 机器学习(ML)项目的数据挖掘
- 拍摄收据照片并读取内容进行处理
Python 库
为了解决这个问题,我们将使用一个名为 Python Tesseract 的库。来自图书馆的网站:
Python-tesseract 是 Python 的光学字符识别(OCR)工具。也就是说,它将识别并“读取”嵌入图像中的文本。
Python-tesseract 是 Google 的 Tesseract-OCR 引擎的包装器。它作为 tesseract 的独立调用脚本也很有用,因为它可以读取 Pillow 和 Leptonica 图像库支持的所有图像类型,包括 jpeg、png、gif、bmp、tiff 等。此外,如果用作脚本,Python-tesseract 将打印识别的文本,而不是将其写入文件。
设置事物
当设置要使用的 Python 库时,通常是一步到位的过程。然而,对于 PyTesseract,我们需要做两件事:
- 安装 Python 库
- 安装宇宙魔方应用程序
首先,要安装 Python 库,只需打开命令行窗口并键入:
pip install pytesseract
然后,前往这个网站,下载并安装宇宙魔方 OCR 可执行文件。在撰写本文时,我使用的是 2020 年 3 月 28 日编译的 64 位 Alpha Build v5.0.0。
我们需要知道我们在哪里安装它,因为我们需要让你的 python 脚本知道。
一旦你完成了以上步骤,你就可以开始了。
Python 代码
正如所承诺的,用 3 行代码,你就能从一幅图片中读出文字:
import pytesseractpytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract'print(pytesseract.image_to_string(r'D:\examplepdf2image.png'))
如果您喜欢上面的文章,您可能也会喜欢:
最后,你可以在 10 分钟内找到一个图书馆
towardsdatascience.com](/learn-how-to-quickly-create-uis-in-python-a97ae1394d5) [## 估算一个软件的最后期限真的很难——让我们来谈谈为什么
规划时你需要知道的 5 条法则
medium.com](https://medium.com/better-programming/estimating-a-software-deadline-is-really-hard-lets-talk-about-why-44687a6baf9d)
如何从 PDF 中提取文本
学习使用 Python 从 pdf 中提取文本
卡尔·海尔达尔在 Unsplash 上拍摄的照片
在这篇博客中,我们将研究用 Python 处理 pdf 的最流行的库。很多信息都是以 PDF 的形式分享的,往往我们需要提取一些细节做进一步的处理。
为了帮助我识别最流行的 python 库,我查看了 StackOverflow 、 Reddit 以及大量的谷歌搜索。我识别了许多包,每个包都有自己的优点和缺点。具体来说,整个互联网的用户似乎都在使用:PyPDF2,Textract,tika,pdfPlumber,pdfMiner。
然而,在我的研究中,由于这样或那样的原因,我只能让其中的 3 个库正常工作。对于其中一些库来说,设置太复杂了(缺少依赖项,奇怪的错误信息,等等。)
让我们快速回顾一下所有这些库。
PyPDF2
评分:3/5
PyPDF2 的好消息是安装起来很容易。文档有些缺乏容易理解的例子,但是如果你足够注意,你最终会明白的。
然而,坏消息是结果并不好。
如您所见,它识别了正确的文本,但出于某种原因,它将文本分成了多行。
代码:
import PyPDF2fhandle = open(r'D:\examplepdf.pdf', 'rb')pdfReader = PyPDF2.PdfFileReader(fhandle)pagehandle = pdfReader.getPage(0)print(pagehandle.extractText())
Textract
评分:0/5
许多人对这个图书馆赞不绝口,这是一个有希望的开始。文档也不错。
不幸的是,最新版本有一个 bug,每次你试图从 PDF 中提取文本时都会抛出一个错误。通过图书馆的开发论坛跟踪这个 bug,可能会有一个修复。手指交叉。
阿帕奇蒂卡
评分:2/5
Apache Tika 有一个 python 库,显然可以让你从 pdf 中提取文本。安装 Python 库非常简单,但是除非安装了 JAVA,否则它无法工作。
至少理论上是这样。我不想安装 JAVA 因此我停留在:*“runtime error:无法启动 Tika 服务器。”*错误。
根据这个媒体博客(无关联),然而,一旦你让它工作,它是了不起的。所以,我们用 2/5 评级吧。
该代码看起来像这样:
from tika import parserfile = r'D:\examplepdf.pdf'file_data = parser.from_file(file)text = file_data['content']print(text)
pdf 木材
评分:5/5
正当我开始对从 pdf 中挖掘文本的简单易用的 python 库的存在失去信心时,出现了 pdfPlumber。
文档不算太差;几分钟之内,整个事情就开始了。结果好得不能再好了。
然而,值得注意的是,该库确实明确表示,它在机器生成的 pdf 上工作得最好,而不是扫描文档;我用的就是这个。
代码:
import pdfplumberwith pdfplumber.open(r'D:\examplepdf.pdf') as pdf:
first_page = pdf.pages[0]
print(first_page.extract_text())
pdfMiner3
评分:4/5
我会诚实;以典型的 pythonic 方式,我扫了一眼文档(两次!)并且不明白我应该如何运行这个包;这包括 pdfMiner(也不是我在这里讨论的版本 3)。我甚至安装了它,并尝试了一些没有成功的事情。
唉,来救我的是一个善良的陌生人。一旦你看完了提供的例子,实际上就很容易理解了。哦,结果和你预期的一样好:
代码可以在链接的堆栈溢出帖子中找到。
PDF -> JPEG ->文本
解决这个问题的另一种方法是将 PDF 文件转换成图像。这可以通过编程或截取每个页面的屏幕截图来完成。
一旦有了图像文件,就可以使用 tesseract 库从其中提取文本:
学习用 3 行代码从图像中提取文本
towardsdatascience.com](/how-to-extract-text-from-images-with-python-db9b87fe432b)
在你离开之前,如果你喜欢这篇文章,你可能也会喜欢:
4 个不同库的介绍(命令行和用户界面)
towardsdatascience.com](/learning-to-use-progress-bars-in-python-2dc436de81e5) [## 构建用于比较数据的 Python UI
如何快速让您的非技术团队能够比较数据
towardsdatascience.com](/building-a-python-ui-for-comparing-data-13c10693d9e4)
如何有效提取 Web 数据:4 种方法
这些被忽视的方法将为你节省时间和金钱
卢卡斯·布拉塞克在 Unsplash 上的照片
作为一名程序员和经常使用数据的人,我经常很难找到好的完整数据集来使用。开源数据库是有限的,API 使用起来可能很昂贵——更不用说每分钟、每天、每月调用次数的限制了。
在几个项目的过程中,我总结了一些为 Python(和 Excel)用户提取和导入 web 数据的基本方法。我非常依赖这些方法来完成任何需要自己获取数据并将其导入工作空间的项目。
最后,对于非编码项目,我将演示一个有价值的 Excel 工具,它允许您从网页中抓取格式化数据,自动将值填充到电子表格中。
以下是四种方法。我将用同样的目标数据集来说明它们:截至 2020 年 3 月的 ATP 网球运动员排名。
1.使用熊猫:read_html
网球数据的一个奇妙来源是 tennisabstract.com 的 T4。这是 ATP 官方排名的网页。
ATP 排名更新 2020 年 3 月 9 日,tennisabstract.com
检查 HTML 后,结构看起来很简单——有四个 table 标记,最后一个包含逐行列出的玩家排名。
当数据已经被很好地格式化成 HTML 表时,检索它的最快方法是使用 Pandas 的 read_html 。这个方法只是将一组 HTML 表读入一个 DataFrame 对象列表。
注意:有一个字符串参数, match ,它确保只返回包含与给定字符串匹配的文本的表。这对于包含大量 HTML 表格的页面非常有用。
import pandas as pdtables = pd.read_html("[http://tennisabstract.com/reports/atpRankings.html](http://tennisabstract.com/reports/atpRankings.html)")rankings = tables[-1]
rankings.iloc[:200]
以下是前 200 名选手。
Top 200 强选手排名,http://tennisabstract.com
2.使用 HTML 解析器:美丽的汤
然而,事情并不总是那么简单。根据配置的不同,一些网站禁止使用 read_html 函数直接访问,导致 HTTP 错误 403。无论如何,如果您想抓取表中没有格式化的数据,该怎么办呢?
这就是像 Beautiful Soup 这样的 HTML 解析器派上用场的地方。
我们试试用美汤从 ATP 官方网站提取排名。安装说明可以在这里找到。
import requests
from bs4 import BeautifulSoupurl = "[https://www.atptour.com/en/rankings/singles"](https://www.atptour.com/en/rankings/singles)
response = requests.get(url)
page = response.text
soup = BeautifulSoup(page, 'lxml')
有了这段简短的代码,我们现在有了网页的 HTML。我们可以使用 soup.find_all(“table”) 获得所有表的列表。可以通过传入 id 来定位一个特定的表——就此而言,页面上的任何对象都可以通过它的 HTML 标签和传入唯一的属性来访问(参见 docs )。
table = soup.find(class_="mega-table")
[row.text.split() for row in table.find_all("tr")]
嵌套列表,包含(1)标题列和(2)播放器行
经过一点清理后,我们可以将数据组织成一个标题列表和另一个播放器行列表。剩下的工作就是将信息存储在数据帧中。
header = [j for j in [i.strip(" ") for i in table.find_all("tr")[0].text.splitlines()] if j != ""]
header.remove("Country")
header.remove("Move")data = []
for row in table.find_all("tr")[1:]:
x = row.text.split()
name = " ".join(i for i in x if i.isalpha() or "-" in i)
res = [i for i in x if not (i.isalpha() or "-" in i)]
res.insert(1, name)
if len(res) == 8:
res.pop(2)
data.append(res)rankings2 = pd.DataFrame(data, columns=header)
rankings2
ATP 排名前 100,https://www.atptour.com
3.使用 JSON 请求
第三种方法是提取 JSON 格式的数据。作为一个例子,我们将从ultimatetennisstatistics.com检索排名。
如果您愿意右键单击并检查页面,您会在“Network”选项卡下看到一个 GET 请求是由 JSON 类型构成的。
只需点击相关的链接,就会产生下面的 JSON 输出页面。
使用请求和 json 库可以很容易地将 JSON 数据读入 Python,然后导入到 Pandas 数据帧中。这个简单的函数完成了这个任务。
import requests
import jsondef get_json(url):
response = requests.get(url)
rows = json.loads(response.text)['rows']
data = pd.DataFrame.from_dict(rows)
return datarankings3 = get_json(["https://www.ultimatetennisstatistics.com/rankingsTableTable?current=1&rowCount=-1&sort%5Brank%5D=asc&searchPhrase=&rankType=RANK&season=&date=&_=1589249780003](https://www.ultimatetennisstatistics.com/rankingsTableTable?current=1&rowCount=-1&sort%5Brank%5D=asc&searchPhrase=&rankType=RANK&season=&date=&_=1589249780003)")rankings3
ATP 排名前 500,ultimatetennisstatistics.com
4.额外收获:使用 Excel 下载 HTML 数据
无需一行代码,您就可以将任何 HTML 文件下载到 Excel 电子表格中。我将使用来自tennisabstract.com的相同排名数据集来演示这一点。
Excel for Windows
- 找到包含所需数据的网页。复制网址。
- 打开 Excel,导航到“数据”选项卡,然后单击“从 Web”。
- 将网站的 URL 粘贴到弹出框中,并按照提示匿名连接到该页面。
- 打开“导航”菜单,在“显示选项”下找到所需数据。检查数据是否正确显示,并将其“加载”到电子表格中。
ATP 排名(tennisabstract.com),导入 Windows Excel
苹果电脑版 Excel】
- 当在网页上时,右键单击,您应该会看到一个类似于“另存为…”或“将页面另存为…”的选项,这取决于您的浏览器。继续将文件以 HTML 格式保存在本地。
- 打开 Excel,导航到“数据”选项卡,然后单击“来自 HTML”。注意,该选项可能位于子菜单“获取外部数据”中。
- 从弹出菜单中找到并打开保存的 HTML 文件。按照提示将数据加载到电子表格中。
ATP 排名【tennisabstract.com,导入 Excel for Mac
就是这样!现在,数据已经被导入并格式化,每个值都在单独的单元格中。
事后思考
这些方法对于抓取网络数据并将其导入到一种更易处理的格式中是必不可少的——从这种格式中,你可以根据需要对数据进行清理、过滤、建模和可视化。
因此,如果您的第一反应是使用 API,您可能需要再考虑一下。尽管在某些情况下这可能是不可避免的,但是许多在线数据可以在不使用 API 的情况下被访问,这样就省去了您获取 API 密钥和浏览文档的精力和费用。
我希望这些工具对你的下一个数据分析项目有用。
感谢阅读!