TowardsDataScience-博客中文翻译-2020-八十二-

TowardsDataScience 博客中文翻译 2020(八十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

奥斯陆证券交易所的市场异常现象

原文:https://towardsdatascience.com/market-anomalies-on-the-oslo-stock-exchange-40ce29886ed7?source=collection_archive---------18-----------------------

用 Python 分析挪威股票市场的日历效应

致谢:乔治·雷克斯,Flickr

有效市场假说

EMH 是一个经济假说,认为资产价格完全反映在可获得的信息中。假设这是真的,我们不能用过去来预测未来,因为所有的运动都是新信息的结果。更有可能的是,人类行为效应导致了市场的低效率,尽管价格发现更快的发达市场加剧了这种低效率。

市场异常

市场异常是指如果 EMH 是真实的,就不会发生的任何可见的影响。有数不清的可能异常,一些比另一些有更多的研究支持。与日历相关的影响得到了很好的研究,其中包括:

  • 万圣节效应(在万圣节和 1。5 月份,今年剩余时间出售)
  • 圣诞老人集会(圣诞节和新年之间价格飙升)
  • 岁末效应(股票价格从年末到下一年上涨的趋势,类似于圣诞老人涨势)
  • 一月效应(建立在一年之交的基础上,股票在一月份表现优于其他月份的趋势)
  • 周末效应(周一的市场回报低于前一个周五)
  • 月末效应(股票价格在月末上升到下个月的趋势)

如果这些异常情况存在,为什么?可能与机构何时重新平衡投资组合有关。发薪日可能会有影响,在接近发薪日时增加销售,而在发薪日之后增加销售。投资者想要在年底买入或卖出可能有与税收相关的原因。在挪威,你可以根据股票市场的损失获得减税,并为收益缴税。因为这是按 31 计算的。12 月份,有利于在年底前出售失败者,更快地获得税收优惠,并在新的一年出售获胜者,让你等待一年的纳税。如果这些影响大到足以创造一个有利可图的异常,那就是另一个问题了,需要进一步研究。

关于这些影响的更多信息,请查看 Investopedia:
https://www.investopedia.com/terms/a/anomaly.asp

工作日、月份、月份中的某一天

我们将使用奥斯陆证券交易所指数(OSEBX)的每日股票价格来探索 Python 中可能的季节性趋势。比较每个工作日的回报,每月的回报,以及每月的一天。我们使用每日收盘,因此回报将是从前一天收盘到当天收盘的价格变化百分比。如果我们发现异常,这能为我们所用吗?

用 Python 获取和处理数据

数据从奥斯陆证券交易所的网站下载:

[## Markedsaktivitet

奥斯陆仪表、衍生和租赁生产商

www.oslobors.no](https://www.oslobors.no/markedsaktivitet/#/details/OSEBX.OSE/overview)

在导入适当的库之后,我们将数据加载到 pandas 数据框架中。该数据包括 1996 年以来的每日收盘数据。这不是最长的时间序列,但在处理金融时间序列时,更长的时间框架并不总是更好。50 年前发生的任何异常现象现在可能都已经消失了。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mplimport warnings
warnings.filterwarnings(“ignore”)# Import osbx (Oslo stock exchange index, OSEBX)
osbx = pd.read_excel(“osbx.xlsx”)
osbx.head()

OSE 指数的价格数据,请原谅挪威人

# revese the order of the DataFrame
osbx = osbx.iloc[::-1]# only keep daily close
osbx = osbx[[“OSEBX”, “Siste”]]# rename columns
osbx.rename(columns={“OSEBX”: “Date”, “Siste”: “Close”}, inplace=True)# change the index to Date
osbx.set_index(“Date”, inplace=True)# calculate daily returns and add to the DataFrame
osbx[“return”] = osbx[“Close”].pct_change()# remove the first row, as it is nan
osbx.dropna(inplace=True)
osbx.head(10)

绘制整个时期的价格序列

osbx[“Close”].plot(figsize=(15,6), title=”Oslo stock exchange index price since 1996")

展开数据框架以包括工作日、月份和年份。

# Exclude 2020 onwards, only keeping the whole years 1996 through 2019
osbx = osbx[“1996”:”2019"]# Determine the weekday and add it as a new column to the DataFrame
osbx[“Weekday”] = osbx.index.weekday.values
osbx[“Weekday”] = osbx[“Weekday”].apply(lambda x: calendar.day_name[x])# Determine the month and add it as a new column to the DataFrame
osbx[“Month”] = osbx.index.month.values
osbx[“Month”] = osbx[“Month”].apply(lambda x: calendar.month_name[x])# Determine the year, convert it to string, and add it as a new column to the DataFrame
osbx[“Year”] = osbx.index.year.values
osbx[“Year”] = osbx[“Year”].astype(str)osbx.head(10)

平日

首先,我们想探索一种趋势的可能性,这种趋势取决于一周中的某一天。若要计算平均值,请按工作日列分组并计算平均值。然后在周一到周五重新排序。

# Mean return for each weekday
osbx_weekday_mean = osbx.groupby(“Weekday”).mean()# Reorder
osbx_weekday_mean = osbx_weekday_mean.reindex([“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”])
osbx_weekday_mean

周一、周二和周四的平均回报率都差不多,而周三的回报率接近于零,周五的回报率更高。让我们用两种不同的方式来绘制它,以便更好地了解分布情况。首先让我们单独查看工作日的平均值,然后使用散点图来查看每个工作日的回报是如何分布的。

x = osbx[“Weekday”]
y = 100*osbx_weekday_mean[“return”]# reorder
osbx_weekday_mean = osbx_weekday_mean.reindex([“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”])
osbx_weekday_mean# barplot of the average return for each week day
import seaborn as sns
sns.set_palette(“pastel”)
fig, ax = plt.subplots(figsize=(15,6))
ax = sns.barplot(x=osbx_weekday_mean.index, y=y, data=osbx_weekday_mean)
ax = plt.ylabel(“Return (%)”, size=15)
ax = plt.title(“Average daily return for each weekday in 1996 through 2019”, size=20)
plt.savefig(‘osbx1.png’)
plt.show()

带有彩色调色板的 Seaborn 绘图库

# Scatter plot of all observations to see the variations for each weekday
x = osbx[“Weekday”].values
y = 100*osbx[“return”].valuesdays = [‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’]
points = [[x[i], y[i]] for i in range(0,len(x))]
for i in range(0,len(points)):
 points[i][0] = days.index(points[i][0])+1

x = [points[i][0] for i in range(0,len(points))]
y = [points[i][1] for i in range(0,len(points))]fig = plt.figure(figsize=(15,6))
ax = plt.scatter(x, y, color=”green”, linewidths=3, marker=”x”, s=30)
ax = plt.scatter([1,2,3,4,5], osbx_weekday_mean[“return”], color=”blue”, marker=”*”, s=100)
ax = plt.ylabel(“Return (%)”, size=15)
ax = plt.title(“Daily returns for each weekday for 1996 through 2019”, size=20)
plt.savefig(‘osbx2.png’)
plt.show()

散点图显示按工作日排序的每日回报分布。请注意,星期一是最后一天

现在计算波动率,并计算每个工作日的观察次数

# Volatility of the returns for each weekday
osbx[“return”] = osbx[“return”]
weekday_vol = osbx[[“Weekday”, “return”]].groupby(“Weekday”).std()
print(weekday_vol)
print()# Number of weekdays
print(osbx[[“Weekday”, “return”]].groupby(“Weekday”).count())

一周中每一天的波动性和计数

由于市场在此期间增长了 800%以上,我们预计每个工作日的平均日回报都是正的,并且有大致相同的回报。周一有点特殊,因为它紧接在周末之后,这意味着周末的风险会延续到周一,因此它应该有 3 天的风险。隔夜风险使投资者暴露于国际市场的事件,这表明周五将有更多抛售,这将推动价格下跌。由于市场在此期间随着时间的推移而上涨,我们也应该期待看到从周五收盘到周一收盘价的更高回报,以及更高的波动性。然而,相反的事情正在发生。周一的波动性比预期的要高,但回报率却没有提高。一个可能的原因可能是临近周末时人们的情绪,乐观情绪的增加会导致更多的购买,但我对此一点也不自信。

为了解释周五和周一之间比一周其他时间更长的时间,一个更准确的分析将改为查看每天从开盘到收盘的回报。

统计学意义?

现在,我们想使用 t 检验来测试每个工作日的平均回报是否与所有工作日的平均回报在统计上有显著差异。假设μᵢ是工作日 I 的所有回报的平均值。将零假设定义为μᵢ与大平均值相同,即所有日期的平均每日回报:

H₀: μᵢ =大平均
H₁: μᵢ ≠大平均

# Perform statistical analysis
from scipy import statsaverage_return = osbx_weekday_mean[“return”].mean()for day in osbx_weekday_mean.index.values:
 sample = np.array(osbx[osbx.Weekday == day][“return”])
 print(day,”:”, stats.ttest_1samp(sample, average_return))

周五的 p 值为 0.0696,对应的置信度为 93.04%。虽然这在大多数实际情况下不会被认为是重要的,但深入研究这种机制并看看这背后是否有什么东西会很有趣,但它可能只是噪音。运行 5 次测试,我们只有大约 70%的概率看不到低于 0.0696 的 p 值(0.9304⁵= 0.6972……)。

我们来逐年比较一下。模式一致吗?

years = range(1996, 2020)
nr_rows = 6
nr_cols = 4
fig, axs = plt.subplots(nr_rows, nr_cols, figsize=(nr_cols*4,nr_rows*3), squeeze=False)axis = []
for r in range(0,nr_rows):
 for c in range(0,nr_cols):
 axis.append(axs[r][c])count = 0
for year in years:
 osbx_year = osbx[str(year)]
 # Mean return for each weekday
 osbx_year = osbx_year.groupby(“Weekday”).mean()
 # reorder
 osbx_year = osbx_year.reindex([“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”])
 # plot
 sns.barplot(x=[1,2,3,4,5], y=”return”, data=osbx_year, ax=axis[count])
 plt.ylabel(‘Number of Occurrences’, fontsize=12)
 axis[count].legend([str(years[count])])
 count = count + 1fig.suptitle(“Average OSBX returns for each weekday by year from 1996 through 2019”, size=20)
plt.tight_layout()
fig.subplots_adjust(top=0.93)
plt.savefig(‘osbx3.png’)
plt.show()

周一至周五,每年所有交易日的平均值

24 年中只有 7 年星期五比其他日子好。由于一年有 52 周,减去一些公共假期,我希望看到“星期五效应”更加一致。

周五的表现排名:

  • 最佳表演:7 次
  • 2.最佳表演:6 次
  • 中等表现者:4 次
  • 2.表现最差:6 次
  • 表现最差:1 次

月度回报

我们分析的第二步是比较每月的回报。某些月份的回报比其他月份好吗?

剩下的代码类似,但是你可以在我的 github 找到完整的笔记本。

几乎像波浪状分布。虽然一月似乎不是很高,但十二月表现良好。也许是圣诞老人集会推高了 12 月份的价格?从历史数据来看,万圣节效应似乎是有利可图的,因为唯一的负回报发生在 6 月至 9 月。

每个月的分配情况如何?

除了经历大幅下跌的几个月,每个月的波动性看起来都差不多。让我们看看每年的月回报

从 1996 年到 2019 年的月度回报柱状图,x 轴标注为 1-12,代表 1-12 月

# average monthly return over all months
average_return = osbx_month_returns.mean()
average_return[0]

输出:0.00928467867

约 1%的平均月回报率。让我们用 t 检验来测试每个月相对于平均值的表现。通过运行 12 个测试,请注意,我们需要一个较低的 p 值来拒绝空值。使用临界值 0.05,假设空值为真,我们在至少一个测试上拒绝空值的概率实际上是 1-0.95 ~46%。为了达到 95%没有错误拒绝,我们实际上需要大约 0.004 的个体 p 值。

for month in months:
 sample = osbx_returns[osbx_returns.Month == month][“return”]
 print(month,”:”, stats.ttest_1samp(sample, average_return))
 print()

4 月的 p 值最低,为 0.0297,12 月为 0.0538。其余月份的值不重要。但是如前所述。当我们进行如此多的测试时,0.0297 并没有低到有意义的程度。

月度回报分析的一个明显缺陷是缺乏样本。我们只有 24 次观察,每年一次。使用更长的时间框架可能是有趣的,但范式会改变,如果市场异常变得众所周知,它会很快被利用和消除。随着市场变得越来越有效,找到这样的模式变得越来越困难。

一月中的某一天

最后,让我们看看一个月中的某一天。

# mean return of each day of the month (note that 31 will have a smaller sample size)
day_of_month_return = osbx[[“return”]].groupby(osbx.index.day).mean()
day_of_month_return.head()

在每月的某一天进行 T-test

在对所有 31 天进行 t 检验后,p 值最低的三天是:

  • 2.:0.07163584(回报率高于平均值)
  • 12.:0.0114696(回报率低于平均值)
  • 29.:0.08354356(回报率高于平均值)

通过 31 天的测试,我们预计平均至少有一次测试会拒绝零假设,事实也确实如此。

我们观察到一个轻微的 U 型回报。月初和月末的天数比月内天数的回报率稍高。这些年的曲线似乎没有非常一致的模式,这让我对 U 形的预测能力不太有信心。

结论

观察异常的一个问题是,我们总是会发现一些模式,如果我们足够努力的话,甚至可以进行显著的测试。然而,如果我们使用定量的方法来发现一些可能的异常,我们可以更深入地研究这些机制,以确定这种模式是否有一些价值。更好的是,首先,找到一些关于市场的有趣的工件,然后进行定量测试,以确定其有效性。这是一个有趣的练习,但仅此而已。我不建议用这个作为策略的基础,因为有限的重要性和巨大的变化会导致一个工作日或一个月的收益来自不相关的事件。

进一步分析:

  • 寻找样本量较大的异常情况,如工作日
  • 更高粒度的数据。日内异常?
  • 欠发达市场可能会有更明显的异常
  • 查看各种因素(如公司规模)是否会导致异常的显著变化

GitHub 上提供完整的笔记本:

[## RunarOesthaug/奥斯陆证券交易所分析

该存储库将包含对来自挪威股票市场的数据进行的分析。主要是奥斯陆股票…

github.com](https://github.com/RunarOesthaug/Oslo-stock-exchange-analysis)

如果您有任何问题,请随时留言。

感谢阅读!

购物篮分析 101:关键概念

原文:https://towardsdatascience.com/market-basket-analysis-101-key-concepts-1ddc6876cd00?source=collection_archive---------15-----------------------

在您的数据中找到客户或用户的行为模式。市场篮子分析可以提供这些新的见解。

马达林·图多塞Unsplash 上的照片

我一年只做一次绿豆砂锅。尽管这是一种对烹饪的嘲弄,但出于感情的原因,我们仍然把它作为感恩节晚餐的一部分。它的主要成分是青豆、罐装奶油蘑菇汤,最重要的是,撒在上面的所谓“法式油炸”洋葱(也是罐装的)。所有这三种成分通常在节日前后被集中在杂货店里。

图片来自 GIPHY

但是杂货店怎么知道把这些东西放在一起展示呢?他们也对绿豆砂锅有感情吗?

不,商店正在充分利用他们的顾客数据——你也可以。一种叫做购物篮分析的分析方法揭示了买家一起购买的物品。除其他目的外,这种分析可以向零售商展示如何将产品放在一起,以及如何交叉促销和推荐客户经常同时放入购物车的商品。营销信息和促销可以突出那些经常一起出现的项目,并且可以识别经常与额外购买相关的关键产品。无论商店和购物车是实体的还是数字的,这种方法都是可行的。购物篮分析还可以用来分析网页浏览历史,检测欺诈和管理库存。

让我们在这里浏览一下市场篮子分析的基本概念。

图片来自 GIPHY

购物篮分析的关键概念

尽管作为消费者,它的结果在我们的生活中随处可见,但购物篮分析起初听起来有点陌生:“先验”?“前因”和“后果”?一个叫做“信念”的指标?不要担心,我们将一起学习这些术语。

首先,我们假设您有一个事务信息数据集,其中标识了每个事务的组件,如下所示:

交易数据

给定这些数据,我们想找出哪些商品经常一起购买。(看起来交易 3 的客户在晚餐菜单上有绿豆砂锅!)我们可以观察这四个交易,其中两个包括火鸡、青豆和法式炸洋葱。然而,一名火鸡购买者没有购买其他两种物品,还有一名购买者没有购买绿豆和其他砂锅配料。

我们可能会从这四个事务中猜测这三种砂锅配料之间存在某种关系,但是很难确定在更大的数据集中是否存在这种关系。

图片来自 吉菲

做出这一决定的市场篮子方法是建立“关联规则”“规则”这个词听起来非常权威或确定,但实际上这些只是将“前因”项与“后果”项联系起来的陈述。关联规则也没有暗示因果关系,只有共现,不要被那些小箭头欺骗。在我们的例子中,我们可能想知道青豆是否是法式炸洋葱的先行项。

{前因}➡️{后果}

青豆 ➡️ 法式炸洋葱

为了查明情况是否如此,我们首先从事务数据中创建“项目集”。一个项目集可能是{青豆,法式炸洋葱}

在上面的小数据集中,我们看到四个事务中的两个包含那个项目集;但是两个也包含项目集{火鸡,青豆} 。如果我们有一个更大的数据集,我们如何知道那些项目集的关系中哪一个更重要,并且应该是我们如何组织我们的杂货店的基础?如果想象一下我们的四笔交易中包含的 10 种不同商品的所有可能组合,情况会更复杂。

(有趣的事实:根据食品工业协会的数据,2019 年,普通杂货店的货架上有 28112 件商品。即使创建 10 个项目集,他们仍有大约 8.5 x 1037 或 84,812,357,987,507,064,681,676,153,306,904,737,896 个项目集要检查。谢天谢地,软件甚至可以帮助一个部门进行计算!)

接下来我们需要做的不仅是测量我们在所有事务中识别的项目集的频率,还要评估这些项目之间的关联强度。我们将使用一些不同的衡量标准来衡量该强度,并且我们将“修剪”(丢弃)不符合我们设置的阈值的规则。保留下来的关联规则应该具有高水平的(那是一个真实的术语!).

图片来自 GIPHY

评估关联规则的度量标准

您可以将一些不同的兴趣度指标应用于关联规则:

  • 支持:这是最容易计算的指标,因为它只是包含关联规则的所有事务的比例。

➡️* 的交易笔数*

除以

交易总数

在我们上面的数据集中,我们发现对➡️* 的支持是 0.5(4 个事务中的 2 个)。这里的数字越接近 1 越好。*

Support 很容易计算,但是想象一下,尝试对商店中更受欢迎的商品进行这样的计算。有多少人在购物时会买* ?可能很多。对于关联规则,您可能会获得很高支持度,但是它不会增加您对客户习惯的理解的细微差别。*

图片来自 GIPHY

  • 信心:信心给你对这个关联规则的判断带来更多的特异性。在这种情况下,它是包含项目集中所有项目的所有事务与只包含其中一项的事务的比例。(是的,这相当于将➡️* 的支持度除以仅{青豆} 的支持度。)*

➡️* 的交易比例*

除以

绿豆交易的比例

在我们上面的数据集中,4 个交易中有 2 个包含这两种商品,4 个交易中有 3 个包含青豆。也就是 0.5 / 0.75,或者 0.67。同样,这里的数字越接近 1 越好。

假设顾客购买了青豆(我们的先行词),信心给了我们顾客购买结果的可能性,即关联规则右侧的项目——法式炸洋葱。正如您所看到的,这个指标提供了一个不同的、也许更有用的对客户行为本质的洞察;我们得到的不仅仅是频率,还有可能性的度量。

图片来自 吉菲

  • :有人会买绿豆。有些人会买法式炸洋葱。有些人会两样都买。如果我们想象这两样东西之间没有关系,那么我们可以看到当人们买下两样东西时,我们实际上超出了预期多少。这个计算叫做升力

➡️* 的交易比例*

除以

(与* 的交易比例)(与* 的交易比例)*

对于我们的迷你数据集,这得出 0.5 / (0.75 * 0.5)或 1.33。以下是评估 lift 的方法:

  • 如果 lift 大于 1,前提事实上增加了结果也出现在交易中的可能性(对青豆是,更可能对法式炸洋葱是,这就是我们这里的情况)。
  • 如果 lift 小于 1,则相反;前一个因素降低了后一个因素的可能性(对青豆说是,更有可能对法式炸洋葱说不)。满足相同需求的产品可能就是这种情况;例如,如果我在购物时买了一瓶我常用品牌的洗发水,很可能我不会再买另一个品牌的。
  • 如果 lift 等于 1,那么前因不会影响购买后果的机会。

提升指标让我们知道,我们关于项目之间“没有关系”的假设——它们是独立的——是否成立。

想要更多指标吗?支持、信心和提升是这种分析最常见的指标,你会在 Alteryx Designer 的市场购物篮工具中看到它们。你可能还会在互联网上看到关于影响力和信念的讨论。这些是用于评估关联规则中表达的同现关系的强度的附加选项。

图片来自 GIPHY

关联规则挖掘的 Apriori 和 Eclat 算法

显然,如果您有多个项目,那么对于基于许多潜在项目集的许多潜在关联规则,需要进行大量的潜在计算。如何在这个过程中高效的消耗你的计算能力,也就是常说的关联规则挖掘

最常用的方法是应用 Apriori 算法 ,该算法首先为您的数据生成最少项目数 k 的频繁项目集,您可以设置最少项目数。它通过要求项目集满足最低支持级别来决定哪些项目集是频繁的(如上所述)。然后,这些频繁项集被重复地划分(分割)和重新组合,并为每个组合计算支持度,直到不能再创建更多的项集。

通过将频繁项集分为前件和后件,从频繁项集生成关联规则,然后计算每条规则的置信度。只有满足最低置信水平的关联规则将被保留,而其他的将被丢弃。

削减项目集(从而减少要评估的关联规则的数量)的过程是修剪。修剪对于减少重复检查数据和计算许多潜在项目集的度量的计算需求非常重要。

eclat 算法也用于建立关联规则。ECLAT 实际上是代表等价类聚类和自底向上格遍历的首字母缩写词(尽管单词 éclat 本身实际上意味着“炫耀的展示”或“炫目的效果”……它的创建者设定了一些很高的期望!).

éclat…而不是 eclat 算法。图片来自 吉菲

与 Apriori 算法用来识别频繁项集的广度优先方法不同,eclat 使用的是深度优先方法。它查看每一项,确定该项出现的事务的事务 id,并列出这些 id。然后,它在这些列表中查找各个项目的交集,并基于交集计算支持度。

eclat 算法可能更快,但是它也可能是内存密集型的,因为它在这些中间步骤中构造和使用列表。(要了解这些算法之间的更多比较和对比,请查看这些幻灯片。)

限制需要分析的关联规则数量的另一种方法是在构建规则之前,通过项聚集到更大的类别中。例如,在我们上面的杂货交易中,我们可以将火鸡和比萨饼放入“冷冻食品”类别,并将两个馅饼放入更大的“甜点”类别。然后我们会得到关联规则,它可以告诉我们在这些更大的类别中发生购买的频率。然而,虽然我们在聚合这些项目时获得了效率,但我们会丢失可能有用的细节。

分析我的篮子!

我希望你受到启发,尝试一下这种分析方法。您可以使用多种工具来实现这种分析:如果您更喜欢 R,请查看 arules 包;如果是 Python,试试 mlxtend 包。Alteryx Designer 中还内置了用于购物篮分析的工具。无论你是否使用 Designer,你都可以阅读这篇博文中的关于如何使用 pandas 和 seaborn Python 包来可视化你的市场购物篮分析,并使其更容易理解你所发现的关系。

原载于Alteryx 社区 及精选于Alteryx 数据科学门户

Python 中的关联规则挖掘:完全指南

原文:https://towardsdatascience.com/market-basket-analysis-using-association-rule-mining-in-python-pyshark-412aa6b4d0ea?source=collection_archive---------38-----------------------

在本文中,我们将使用 Python 中的各种关联规则挖掘算法来探索购物篮分析。

照片由玛利亚·林·金Unsplash 上拍摄

目录:

  • 介绍
  • 关联规则挖掘(概述)
  • 概念
  • Apriori 算法
  • 喝彩
  • F-P 增长
  • 算法比较
  • Python 中的关联规则挖掘(示例)
  • 结论

介绍

随着电子商务网站的快速增长和跨行业(尤其是零售业)转向数据答案的普遍趋势,每个组织都在努力寻找更多机会,以获得最佳产品组合来进行折扣和促销。

对这些决策的回报是期望销售的增长和库存水平的降低。

对“一起买了什么”进行分析通常会产生非常有趣的结果。

零售业的一个经典故事是关于一家沃尔玛商店,其中一家商店的同事开始将商品捆绑在一起,以便更容易找到。例如,他们把面包和果酱放在一起,牛奶和鸡蛋,等等。

这些是我们在商店购物时马上想到的例子。

他们没想到的是,在分析了每个顾客的收据后,他们发现了一个规律,美国爸爸在一张收据上有尿布和啤酒(尤其是在周五)。

市场购物篮分析(或相似性分析)主要是一种数据挖掘过程,有助于识别用户组执行的某些事件/活动的同现。在我们的例子中,我们将通过使用 Python 中的关联规则挖掘来分析个人的收据,从而关注个人在零售店中的购买行为。

关联规则挖掘(概述)

关联规则学习是一种基于规则的方法,用于发现大型数据集中变量之间的关系。对于零售 POS(销售点)交易分析,我们的变量将是零售产品。它本质上发现了具有某种“强”水平的强关联(规则),这由几个参数表示。

现在我们将转向一些数学,以技术的方式解释关联规则。

以下是 Agrawal、Imieliński、Swami 在他们的论文(以此为基础)中描述关联规则学习的总结,以及我们的一些补充:

  1. I = i_1,i_2,…,i_n 为一组 n 的商品(在一个零售例子中:让我们把它想象成商店中所有可用产品的列表:香蕉、牛奶等等)。
  2. D = t_1,t_2,…,t_m) 为一组 m 的交易(在一个零售的例子中:姑且认为是客户收据)。

中的每笔交易 t_m 都有一个唯一的 ID(在一个零售例子中:每张收据都有一个唯一的编号)。

同样,每笔交易 t_m 由集合 I 中的商品子集组成(在零售示例中:每张收据包含来自商店的产品)。

一个 规则 被定义为形式y->x其中xIyI(相当于

这些数学术语的含义如下:

  • xI是指 XI 的子集(在一个零售例子中: X 可以是商店中所有可用产品列表中的 1 个或多个产品)。
  • yI的意思是 Y 也是 I 的子集(解释同上)。
  • XY= 0 表示 XY 没有公共元素(两个项集不能有相同的乘积)。

为了便于理解,我们来看下面的例子:

  1. 你去购物,你的收据上有以下商品:{面包、牛奶、鸡蛋、苹果}。
  2. 我们来创建一个任意项集X:{面包,鸡蛋}。
  3. 让我们创建一个任意项集Y:{ apple }。

回头看看规则的定义,你会发现你已经满足了所有的假设。项目集 X 中的每个项目都是收据上产品列表中的一个产品。项目集 Y 中的每个项目都是收据上产品列表中的一个产品。 XY 中的产品不重复(在您的收据上的产品列表中是唯一的)。

使用这些项目集,规则的一个例子是:{面包,鸡蛋}→{苹果} ,这意味着买面包和鸡蛋的人可能会买苹果。

到目前为止,我们只处理了作者选择的两个项目集。然而,我们的收据有 4 个项目,所以我们可以创建更多的项目集,从而创建更多的规则。例如,另一个规则可能是 {milk}→{eggs}{bread,milk}→{eggs}

概念

正如您在上一部分中看到的,我们能够提出几个任意的 规则 ,这些规则甚至可以从一个非常小的包含几个项目的交易样本中导出。

我们现在要做的是确定几个有用的度量,允许我们评估可以作为潜在关联规则提出的规则的“强度”。我们基本上会努力寻找最有意义和最重要的规则。

首先,让我们从杂货店创建一个任意的交易数据库:

作者图片

在上面的数据库中,每一行都是来自客户的唯一收据。其他列中的值为布尔值(1 表示真,0 表示假)。这张表格显示了我们在什么收据上买了什么。

现在我们都准备好做一些计算了。

假设两个单项集 XY ,其中 X 包含牛奶( X : {Milk})和 Y 包含鸡蛋( Y : {Eggs})。

我们要探讨的是X->Y,即“购买牛奶的顾客也购买鸡蛋的规则有多强?”

我们需要熟悉购物篮分析中最常用的一组概念。

支持

一个项集 X 的支持度定义为数据库中包含 X 的事务的比例。

理论:

作者图片

那么我们来统计一下看到 X (奶)出现的交易数量。这是 3 个事务(id:001,002,003)。交易总数为 4。

因此,我们的计算如下:

作者图片

信心

置信度是对规则为真的指示的显著性的度量。简单来说,就是计算项集 Y 被项集 X 购买的可能性。

理论:

作者图片

首先,我们需要计算项目集 XY 的联合支持度。这是牛奶和鸡蛋同时出现的交易数(交易的交集)。

这是两个事务(id:001,002)。交易总数为 4。

因此,我们的计算如下:

作者图片

从上一部分我们知道 supp(X)= 0.75。

使用上面的数字,我们得到:

作者图片

这表明,每次顾客购买牛奶,有 66%的机会他们也会购买鸡蛋。

也可以称为 YX 的条件概率:P(Y|X)= 0.66。

电梯

如果 XY 是独立的,则提升是观察到的支持与预期支持的比率。

换句话说,它告诉我们 规则 在计算结果时,同时考虑到项目集 Y 的流行度有多好。

理论:

作者图片

  • 如果 lift(X->Y)= 1,那么这就意味着项目集 X 和项目集的出现概率是相互独立的,也就是说 规则 不显示任何**
  • 如果 lift(X->Y)>为 1,则意味着项目集 XY 的出现概率是正相关的。它还会告诉我们依赖程度的大小。提升值越高,依赖性越高,这也可以称为项目集是互补的。
  • 如果 lift(X->Y)<为 1,那么这就意味着项目集 XY 出现的概率是相互负相关的。提升值越低,依赖性越低,这也可以称为项目集相互替代。

到目前为止,我们已经计算了我们需要的大部分值。

作者图片

作者图片

现在,让我们找到第三块:supp( Y )

我们需要鸡蛋出现的交易数量。这是 3 个事务(id:001,002,004)。交易总数为 4。

因此,我们的计算如下:

作者图片

将所有这些代入一个公式,我们得到:

作者图片

我们发现升力有一个有趣的值。当我们看表时,似乎很明显牛奶和鸡蛋经常一起买。我们还知道,从本质上讲,这些产品通常会一起购买,因为我们知道有多种菜肴同时需要这两种产品。

注意:即使从统计学上来说,它们不是互补的,我们用我们的判断来评估关联 规则 。这是我们需要强调领域知识的时刻。公式不知道我们知道什么,我们可以获得很多信息,公式做的一切都基于数字。计算这些值是对你决策的补充,而不是替代。评估关联规则时,由您来设置最小阈值。在 Python 中执行关联规则挖掘之前,理解这一部分很重要。

Apriori 算法(举例说明)

Apriori 算法(最初由 Agarwal 提出)是购物篮分析中最常用的技术之一。它用于分析事务数据库中的频繁项集,然后用于生成产品之间的关联规则。

我们来举个例子。回想一下我们在“概念”课程中介绍的数据集:

以下是 Apriori 算法如何探索牛奶关联规则的示例树:

作者图片

在本例中,算法首先查看级别 1(牛奶)并找到其频率,然后移动到下一个深度层并查看[牛奶、鸡蛋]、[牛奶、苹果]和[牛奶、面包]的频率。在分析了第二个深度级别后,它会移动到下一个深度级别。这将一直持续到最后一个深度级别,这意味着一旦不再有新的项集,算法将停止计算。

作为说明,考虑上面的图表,但是现在我们将标记算法采取的步骤,而不是项目:

作者图片

上图显示了算法在执行搜索时所采取的步骤(1:16)。

因此,它计算对所有可能的项集组合的支持。请记住,由我们来设置支持的最小参数。如果我们将它设置为 0.01,我们显然会看到比设置为 0.4 更多的可能规则。

结果输出将是一个关联规则列表,这些规则是在满足我们设置的参数值时发现的。

ECLAT(举例说明)

ECLAT 算法是另一种流行的购物篮分析工具。它代表等价类聚类和自底向上的格遍历。它被称为“更有效”的 Apriori 算法。

这是一种深度优先搜索(DFS)方法,通过数据集结构进行垂直搜索。该算法从树根开始搜索,然后探索下一个深度级别节点,并继续向下搜索,直到到达第一个终端节点。然后,它后退一步(到 n-1 级),探索其他节点,并向下到达终端节点。

当我们把它作为一棵树来探索时,它更有意义。回想一下我们在“Apriori 算法”部分中使用的数据集(在本课中进一步添加以供参考)。下面是 DFS 将如何分析它:

作者图片

逻辑的总结是:

  • 找到根(方框 1)。
  • 探索下一个深度级别节点,直到到达一个终端节点(框 2:4)。
  • 一旦到达终端节点(框 4),后退一步到先前的深度级别,并查看是否有其他节点可供探索(框 3 级别没有)。
  • 再后退一步(回到方框 2 的层次),现在有另一条“路径”可用(方框 5)。
  • 向下走,直到到达终点(方框 6)。
  • 不断重复上述步骤,直到不再有节点需要探索。

如果我们将其与广度优先搜索(BFS)进行比较,计算速度将取决于树的宽度和深度(顶点排序的不同属性)。

回到 ECLAT 算法的技术部分,其流程如下:

  • 在第一次运行中,ECLAT 查找所有单个项目集(k=1)的事务 id。
  • 在第二次运行时,ECLAT 查找所有两项项目集(k=2)的事务 id。

我们再举个例子。这是我们的数据集:

作者图片

下面展示了 ECLAT 算法将对该数据集执行的所有运行:

  • 对于 k=1:

作者图片

  • 对于 k =2:

作者图片

  • 对于 k =3:

作者图片

  • 对于 k =4:
    一旦我们到达四项项目集,我们可以从我们的数据中看到没有任何一项。在这种情况下,ECLAT 算法将在 k =3 时停止搜索。

需要注意一些事情:

  • 如果两个项目没有一起出现在任何交易上(比如{牛奶,苹果}),它就不会出现在矩阵中。
  • 该矩阵不包含重复项({牛奶、鸡蛋}与{鸡蛋、牛奶}相同)。

结果:

现在,假设我们已经为 ECLAT 搜索预设了最小支持计数要求等于 2(支持计数=2)。
这意味着一个规则要符合输出条件,它必须至少有两个出现这些项目的交易:

作者图片

注意:支持计数和支持是两个不同的概念。支持计数(σ)是项目发生的事务计数。Support 是项目出现的事务占事务总数的分数(支持计数除以事务总数)。

F-P 增长(举例说明)

F-P 增长(或频繁模式增长)算法是购物篮分析中另一种流行的技术(首先由韩介绍)。它产生与 Apriori 算法相同的结果,但由于数学上不同的技术(分治),计算速度更快。

  1. 首先,它计算事务数据集中每个项目的出现次数。
  2. 然后,它使用事务创建一个搜索树结构。

F-P 增长遵循两步数据预处理方法:

与 Apriori 算法不同,F-P Growth 在将事务插入到树中之前,根据事务出现的频率从大到小对事务进行排序。这是它比 Apriori 算法具有显著计算优势的地方,因为它在早期就进行频率排序。不符合最低支持(频率)要求(我们可以设置)的项目将从树中丢弃。

另一个优点是重复的频繁项集将具有相同的路径(不像 Apriori 算法,每个项集具有唯一的路径)。

这里有一个例子:

作者图片

左手边是 Apriori 算法,它通过以下步骤查看两个单独的序列:

  1. 牛奶->鸡蛋->苹果
  2. 牛奶->鸡蛋->面包

右手边是 F-P 生长算法,它查看两个序列,其中公共部分[牛奶、鸡蛋]被压缩:

  1. 【牛奶、鸡蛋】->苹果
  2. 【牛奶、鸡蛋】->面包

这允许对树的根进行更高的压缩和更少的计算步骤(在这种情况下是 2 步),这意味着计算比 Apriori 算法快得多(在这种情况下是 4 步)。

算法比较

本节旨在通过比较和对比的方式,向您简要介绍本课程中学习的三种算法。

请参考下表:

作者图片

上表表明,主要的速度优势是由于不同的计算技术和数据格式。因为 F-P 增长只遍历数据库两次,所以在大量项目集上要快得多。在我们使用的例子中,整个数据库只包含 4 个唯一的条目,计算速度的差异很小,不明显。

Python 中的关联规则挖掘(示例)

在这一节中,我们将创建一些 Python 中关联规则挖掘的例子。

让我们回忆一下我们在本课程的第一节课中创建的数据集:

我们将把它作为模型的输入。

为了继续学习本教程,我们需要两个 Python 库:pandas 和 mlxtend。

如果您没有安装它们,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它们:

**pip install pandas
pip install mlxtend**

一旦下载并安装了库,我们就可以继续 Python 代码实现了。

步骤 1:创建包含所需数据的列表

上面的代码创建了一个我们将使用的事务列表。

让我们来看看结果:

**[['Milk', 'Eggs', 'Bread'], ['Milk', 'Eggs'], ['Milk', 'Bread'], ['Eggs', 'Apple']]**

步骤 2:用布尔值将列表转换成数据帧

我们首先导入所需的库。然后我们将 TransactionEncoder()函数保存为局部变量 te
下一步是从
数据集列表中创建一个具有真/假值的数组( te_array )。
然后,我们使用条目作为列名,将这个数组转换成 dataframe ( df )。

让我们来看看结果:

**Apple  Bread   Eggs   Milk
0  False   True   True   True
1  False  False   True   True
2  False   True  False   True
3   True  False   True  False**

这向我们显示了在所有事务处理中,哪些项目会/不会出现在特定的收据上。

步骤 3.1:使用 Apriori 算法找到频繁出现的项目集

首先,我们从库中导入 Apriori 算法函数。
然后,我们将该算法应用于我们的数据,以提取具有最小支持值 0.01(该参数可以改变)的项目集。

让我们来看看结果:

**support             itemsets
0     0.25              (Apple)
1     0.50              (Bread)
2     0.75               (Eggs)
3     0.75               (Milk)
4     0.25        (Eggs, Apple)
5     0.25        (Eggs, Bread)
6     0.50        (Bread, Milk)
7     0.50         (Eggs, Milk)
8     0.25  (Eggs, Bread, Milk)**

步骤 3.2:使用 F-P 增长找到频繁出现的项目集

首先,我们从库中导入 F-P 增长算法函数。
然后,我们将该算法应用于我们的数据,以提取最小支持值为 0.01 的项目集(该参数可以根据具体情况进行调整)。

让我们来看看结果:

**support             itemsets
0     0.75               (Milk)
1     0.75               (Eggs)
2     0.50              (Bread)
3     0.25              (Apple)
4     0.50         (Eggs, Milk)
5     0.50        (Bread, Milk)
6     0.25        (Eggs, Bread)
7     0.25  (Eggs, Bread, Milk)
8     0.25        (Eggs, Apple)**

注意:您所观察到的是,无论您使用何种技术,您都会得到相同的项目集和支持值。唯一的区别是它们出现的顺序。你应该注意到,F-P 增长的产出是以降序出现的,因此证明了我们在理论部分提到的这个算法。

第四步:挖掘关联规则

在最后一步中,我们将找到在第三步中计算的频繁项集的关联规则。

首先,我们从页面导入所需的函数,使用一些参数集来确定给定数据集的关联规则。然后,我们将它应用于我们在步骤 3 中创建的两个频繁项目数据集。

注意:“metric”和“min_threshold”参数可以根据具体情况进行调整,这取决于业务问题的需求。

让我们来看看这两套规则:

**antecedents consequents  antecedent support  consequent support  support  confidence      lift  leverage  conviction
0        (Apple)      (Eggs)                0.25                0.75     0.25         1.0  1.333333    0.0625         inf
1        (Bread)      (Milk)                0.50                0.75     0.50         1.0  1.333333    0.1250         inf
2  (Eggs, Bread)      (Milk)                0.25                0.75     0.25         1.0  1.333333    0.0625         inf**
**antecedents consequents  antecedent support  consequent support  support  confidence      lift  leverage  conviction
0        (Bread)      (Milk)                0.50                0.75     0.50         1.0  1.333333    0.1250         inf
1  (Eggs, Bread)      (Milk)                0.25                0.75     0.25         1.0  1.333333    0.0625         inf
2        (Apple)      (Eggs)                0.25                0.75     0.25         1.0  1.333333    0.0625         inf**

从上面的两个例子中,我们看到两种算法都找到了系数相同的关联规则,只是顺序不同。

结论

本文是一个用 Python 实现用于购物篮分析的关联规则挖掘的基本示例的演练。我们关注最常见算法的理论和应用。

事情远不止如此:

  • 更多算法
  • 更多参数调整
  • 更多的数据复杂性

本文的目的是展示这种数据挖掘技术在 Python 中应用于购物篮分析的可能性,这肯定可以进一步探索。

如果你有任何问题或对编辑有任何建议,请随时在下面留下评论,并查看更多我的统计文章。

推荐人:

  • 阿格拉瓦尔河;t .伊梅利斯基;Swami,A. (1993 年)。“挖掘大型数据库中项目集之间的关联规则”。1993 年 ACM SIGMOD 数据管理国际会议记录—SIGMOD’93。第 207 页。citeserxT910 . 1 . 1 . 40 . 6984。doi:10.1145/170035.170072。国际标准书号978–0897915922
  • 韩(2000)。挖掘无候选生成的频繁模式2000 年 ACM SIGMOD 数据管理国际会议论文集。西格蒙德 00。第 1-12 页。citeserx10 . 1 . 1 . 40 . 4436doi:10.1145/342009.335372

原载于 2020 年 3 月 24 日 https://pyshark.com/。****

市场篮子分析和预测

原文:https://towardsdatascience.com/market-basket-analysis-using-associative-data-mining-and-apriori-algorithm-bddd07c6a71a?source=collection_archive---------7-----------------------

使用关联数据挖掘和 Apriori 算法

布鲁克·卡吉尔在 Unsplash 上的照片

简介

最近,我们都越来越多地从在线电子商务网站购物,这可能是因为世界上大多数地方都实行了封锁。你一定注意到了一个名为' 的追加销售功能,在大多数网站上经常一起购买 ',例如亚马逊,它会预测所有商品的价格,以及你刚刚添加到购物车中的商品。客户可以选择将该功能下显示的所有商品添加到购物车中,或者选择所需的商品。亚马逊通过他们所谓的“商品对商品的协同过滤”来实现这一点,它根据顾客的商品搜索历史来运行推荐算法,以改善购物体验。对于线下零售商来说,情况也差不多。让我们考虑面包和果酱的基本例子。如果零售商发现面包的销量有所增加,他可以通过在果酱价格上打折来进一步向上销售,这样一来,更多的顾客势必会一起购买。

这个分析顾客购物趋势的全过程被称为“ 购物篮分析 ”。这是一种分析技术,基于这样一种想法,如果我们购买一件商品,那么我们必然会购买或不购买一组(或单个)商品。例如,如果顾客正在购买面包,那么他/她购买果酱的机会就更大。这由以下等式表示:

关联挖掘规则

这个等式被称为关联挖掘规则。这可以被认为是一种如果-那么的关系。如果商品 A 被一个顾客购买,那么商品 B 在同一交易中被同一用户购买的机会被发现。这里 A 称为前因,B 称为后果。先行项是在购物篮中找到的主要项目,而结果项是与先行项/一组先行项一起找到的项目。衡量关联性的指标包括:

支持:告诉我们经常一起买的物品组合。它给出了包含 A 和 b 的交易部分。

我们可以使用支持过滤掉不经常出现的项目集。

置信度:它告诉我们 A 和 B 一起被购买的频率,因为 A 被购买的次数。

Lift: 表示一个规则对 A 和 B 一起被买的随机性的强度。它基本上衡量了任何关联规则的强弱(下面我们会讲到关联规则)。

升力越大,规则的力量就越大。如果 A -> B 的升力是 3,那么这意味着如果我们买 A,买 B 的机会是 3 倍。

因此,这个过程是为每个项目集制定规则,以找出其关联的度量标准,从而决定是否将它包括在分析中。但是考虑具有数百万用户和事务大型数据集,从而产生大量的项目集。因此,为所有这些制定规则将是一项艰巨的任务。这就是 Apriori 算法的用武之地。

Apriori 算法使用频繁购买的项目集生成关联规则。它建立在频繁购买项目集的子集也是频繁购买项目集的思想上。如果频繁购买的项目集的支持值高于最小阈值支持值,则判定频繁购买的项目集。

为了演示该算法的工作原理,考虑以下事务:

交易详细信息

总共有 5 种商品 A、B、C、D 和 E,在每笔交易中以不同的组合一起购买。让我们将项目集的最小阈值支持值固定为 2。

迭代 1: 形成具有 1 个项目的项目集,并计算它们的支持度。

迭代 1

从每个项目集的支持度值可以看出,D 的支持度为 1,小于阈值。因此,我们将忽略该项目集。

迭代 1 最终版

迭代-2: 接下来,我们创建所有可能的包含 2 个项目的项目集。表 F1 中的所有项目都用于此。

迭代 2

在此迭代中,支持度小于 2 的项目集再次被忽略,{A,B}。

迭代-3: 列出了所有包含 3 个项目的可能项目集。然后,我们将把这些项目集分成它们的子集,并省略那些支持值小于阈值(即 2)的项目集。这个过程叫做修剪

迭代 3 和修剪

我们将省略{A,B,C}和{A,B,E},因为它们都包含迭代 2 中省略的{A,B}。这个剪枝部分是 Apriori 算法的关键部分。

迭代 3 最终版

迭代-4 :使用 F3,我们将创建包含 4 个项目的项目集。

迭代 4

我们可以看到,只有 4 个项目的项目集的支持度小于 2。所以我们在这里停止迭代,最终的项目集是 F3。

如果 I={A,C,E}那么子集是{A,C},{A,E},{C,E},{A},{C},{E}。

如果 I={B,C,E},则子集为{B,C},{B,E},{C,E},{B},{C},{E}。

规则:为了过滤掉相关的项目集,我们将创建某些规则,并将其应用于子集。假设最小置信度值为 60%。

对于 I 的每个子集 S,我们制定规则

S →(I-S) (表示如果 S 那么 I 减去 S)如果

支持度(I)/支持度(S) ≥最小置信值即 60%。

考虑{A,C,E}

规则 1 : {A,C} →({A,C,E}- {A,C})也就是{A,C} → {E}

信心=支持{A,C,E }/支持{A,C} = 2/3 = 66.6% > 60%

所以选择了规则 1,即{A,C} → {E}。

规则二 : {A,E} →({A,C,E}- {A,E})也就是{A,E} → {C}

信心=支持{A,C,E }/支持{A,E} = 2/2 = 100% > 60%

所以选择了规则 2,即{A,E} → {C}。

规则三 : {C,E} →({A,C,E}- {C,E})哪个是{C,E} → {A}

信心=支持{A,C,E }/支持{C,E} = 2/3 = 66.6% > 60%

所以选择了规则 3,即{C,E} → {A}。

规则 4 : {A} →({A,C,E}- {A})也就是{A} → {C,E}

信心=支持{A,C,E }/支持{A} = 2/3 = 66.6% > 60%

所以选择了规则 4,即{A} → {C,E}。

规则 5 : {C} →({A,C,E}- {C})也就是{C} → {A,E}

置信度=支持{A,C,E }/支持{C} = 2/4 = 50% < 60%

So rule 5 i.e., {C} → {A,E} is rejected.

规则 6 : {E} →({A,C,E}- {E})即{E} → {A,C}

信心=支持{A,C,E }/支持{E} = 2/4 = 50% < 60%

So rule 6 i.e., {E} → {A,C} is rejected.

Same steps can be done to {B,C,E}. Lift is not being used as the size of the input data-set is small and there is no need of further filtering. But in the case of larger data set further filtering is done by imposing a minimum lift value for the rules. The values of all three of the association metrics can be tweaked as per requirement.

Lets consider an actual data-set and see how the analysis is done.

The link to the data-set being used is given below

[## transaction_data.csv

Edit description

drive.google.com](https://drive.google.com/file/d/1vE3xyM-hbZMB5RS8c3H13Ll1PnFXJ7Ui/view?usp=sharing)

We are going to sue python and pandas. We are also going to use Mlxtend lib as it contains inbuilt functions for Apriori algorithm and Associaction rules.

Load the necessary libraries:

import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np

Ingest the data into a pandas data-frame and try to know about the features.

read_df = pd.read_csv(‘transaction_data.csv’)
df = read_df.copy()
df.info()

Further description of the features are as follows:

UserId — Unique identifier of a user.

TransactionId — Unique identifier of a transaction. If the same TransactionId is present in multiple rows, then all those products are bought together in the same transaction.

TransactionTime — Time at which the transaction is performed

ItemCode — Unique identifier of the product purchased

ItemDescription — Simple description of the product purchased

NumberOfItemsPurchased — Quantity of the product purchased in the transaction

CostPerItem — Price per each unit of the product

Country — Country from which the purchase is made.

EDA and data cleaning is done as follows:

df = df[df.UserId>0] # usedid <=0 : 25%
df = df[df.ItemCode>0]
df = df[df.NumberOfItemsPurchased>0]
df = df[df.CostPerItem>0]
df = df[df.ItemDescription.notna()]
df = df[df.TransactionTime.str[-4:] != ‘2028’]

The following data-frame is obtained:

First five rows of the data-frame

EDA:

现在让我们做一些探索性的数据分析。让我们来看看在一年的每一段时间里完成的交易数量。

df.TransactionTime = pd.to_datetime(df.TransactionTime)
df[‘month_year’]= pd.to_datetime(df.TransactionTime).dt.to_period(‘M’)
df.sort_values(by = [‘month_year’], inplace = True)
Ser = df.groupby(‘month_year’).TransactionId.nunique()
x = np.arange(0,len(Ser),1)
style.use(‘ggplot’)
fig = plt.figure(figsize = (10,10))
ax1 = fig.add_subplot(111)
ax1.plot(x, Ser, color = ‘k’)
ax1.fill_between(x, Ser, color = ‘r’, alpha = 0.5)
ax1.set_xticks(x)
ax1.set_xticklabels(Ser.index)
plt.xlabel(‘Time period’)
plt.ylabel(‘No. of transactions’)

基本上,我们创建一个名为 month_year 的列,将数据点划分到它们发生的月份。然后,我们取每个月发生的唯一事务的数量,并使用 matplotlib 绘制它。

每月完成的交易

我们可以看到,随着时间的推移,在线零售商的购买量越来越多,在 2019 年 1 月达到了峰值。

让我们来看看每笔交易中购买的商品数量。

Ser = df.groupby(‘TransactionId’).ItemDescription.nunique()
Ser.describe()

Ser 的描述

正如我们所见,项目的最小数量是 1,最大数量是 540。因此,我们需要绘制直方图,如下所示:

bins = [0,50,100,150,200,250,300,350,400,450,500,550]
fig = plt.figure(figsize = (10,10))
plt.hist(Ser, bins, histtype = 'bar', rwidth = 0.5)
plt.xlabel('No. of items')
plt.ylabel('No. of transactions')
plt.show()

哎呀!我们可以看到,大多数交易包括 0–100 之间的项目,也有一些是 100–200 之间的项目。上面显示的最大项目交易可能是一个异常值,或者是一个大规模购买的客户。所以我们需要重新调整直方图。

bins = [0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200]
fig = plt.figure(figsize = (10,10))
ax1 = fig.add_subplot(111)
ax1.hist(Ser, bins, histtype = 'bar', rwidth = 0.5)
ax1.set_xticks(bins)
plt.xlabel('No. of items')
plt.ylabel('No. of transactions')
plt.show()

正如我们所见,大多数交易包括不到 10 个项目。

让我们找出市场上最畅销的商品。这可以有多种解释,如带来最大收入的项目、在最大交易数中发现的项目等。我们将考虑能带来最大收益的项目。

df[‘total_cost_item’] = df.NumberOfItemsPurchased*df.CostPerItem
Ser = df.groupby(‘ItemDescription’).total_cost_item.sum()
Ser.sort_values(ascending = False, inplace = True)
Ser = Ser[:10]
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111)
ax.barh(Ser.index, Ser, height = 0.5)

从上图显示的前 10 项商品中,我们可以看到“retrospot lamp”商品的销售价值最高。

发现唯一 TransactionId 的编号为 18334,唯一 ItemDescription 的编号为 3871。

既然我们在所有的预处理之后有了数据,让我们用 TransactionId 作为索引,用 ItemDescriptions 作为列,用在每个项目的每个交易中购买的项目总数作为数据点来排列它。

df_set = df.groupby(['TransactionId', 'ItemDescription']).NumberOfItemsPurchased.sum().unstack().reset_index().fillna(0).set_index('TransactionId')

获得以下数据帧:

我们需要确保任何正值被编码为 1,所有负值(如果有的话)被编码为零。

def encode(x):
 if x <= 0:
 return 0
 else:
 return 1
df_set = df_set.applymap(encode)
df_set

当数据框架准备好了,我们可以应用 Apriori 算法得到频繁购买的项目集。

frequent_itemsets = apriori(df_set, min_support = 0.015, use_colnames = True)

这里,最小阈值支持值被设置为 1.5%。我们得到以下项目集。

然后,我们按照支持值的降序排列项目集,这就给出了

frequent_itemsets = apriori(df_set, min_support = 0.015, use_colnames = True)
top_items = frequent_itemsets.sort_values('support', ascending = False)[:20]
for i in range(len(top_items.itemsets)):
    top_items.itemsets.iloc[i] = str(list(top_items.itemsets.iloc[i]))
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111)
ax.bar(top_items.itemsets, top_items.support)
for label in ax.xaxis.get_ticklabels():
    label.set_rotation(90)
plt.xlabel('Item')
plt.ylabel('Support')

然后,我们将关联规则应用到这些由 Apriori 算法形成的项目集上。

rules = association_rules(frequent_itemsets, metric = 'confidence', min_threshold = 0.2)

这里使用的度量是置信度,其最小阈值设置为 0.2。

获得下面的数据帧

所有具有相应结果的前因都列出了它们各自的支持度、项目集的总支持度以及所有其他度量。

规则数据框架的总结让我们获得了以下启示:

  1. 总共有 187 条规则。
  2. 各种指标的摘要。

让我们来看看可信度最高的规则

top_rules = rules.sort_values(‘confidence’, ascending = False)[:10]

fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111)
ax.scatter(top_rules.support, top_rules.confidence, top_rules.lift)

在图表中绘制规则:

import networkx as nx
G1 = nx.DiGraph()
color_map = []
N = 50
colors = np.random.rand(N)
strs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9']
for i in range(10):
    G1.add_nodes_from('r'+str(i))
    for a in top_rules.iloc[i]['antecedents']:
        G1.add_nodes_from([a])
        G1.add_edge(a, 'r'+str(i), color = colors[i], weight = 2)
    for c in top_rules.iloc[i]['consequents']:
        G1.add_nodes_from([c])
        G1.add_edge('r'+str(i), c, color = colors[i], weight = 2)
for node in G1:
    found_a_string = False
    for item in strs:
        if node == item:
            found_a_string = True
    if found_a_string:
        color_map.append('red')
    else:
        color_map.append('black')
edges = G1.edges()
colors = [G1[u][v]['color'] for u,v in edges]
weights = [G1[u][v]['weight'] for u,v in edges]
pos = nx.spring_layout(G1, k = 16, scale = 1)
fig = plt.figure(figsize = (20,20))
nx.draw(G1, pos, edges = edges, node_color = color_map, edge_color = colors, width = weights, font_size = 16, with_labels = False)
for p in pos:
    pos[p][1] += 0.07
nx.draw_networkx_labels(G1, pos)

所有这些绘图和进一步的分析在 R 中比在 python 中更容易完成,因为 R 中有更多兼容的数据挖掘和关联规则库。

可以使用提升值和置信度值(因为它们度量关联规则强度)对所获得的项目集进行进一步过滤。

这里发现升力和置信度的平均值分别为 9.388 和 0.429。

rules[(rules.lift >= 9.388) & (rules.confidence >= 0.429)]

项目集被过滤,使得只有那些提升值和置信度值高于平均值的项目集被包括在内。

通过这种方式,可以找到所有需要的项目集。可以通过增加支持度和提升度的阈值来进一步微调项目集以找到更可能的项目集。我们可以将找到的项目集存储在一个 csv 文件中以备将来使用。

总结:

我们看了基本的关联挖掘规则及其应用。然后利用 Apriori 算法解决了频繁购买项目集的生成问题。将关联规则应用于这些生成的项目集的过程被查看。我们还学习了如何在相对大规模的数据集上使用 Pandas 和 Mlxtend 在 Python 中完成整个过程。

参考文献:

[## Apriori 算法:知道如何找到频繁项集| Edureka

有没有发生过这样的情况,你出去买东西,结果却买了很多超出你计划的东西?这是一个…

www.edureka.co](https://www.edureka.co/blog/apriori-algorithm/) [## Python 中的购物篮分析简介

python 分析师可以使用多种数据分析工具,但要知道使用哪种工具可能很困难…

pbpython.com](http://pbpython.com/market-basket-analysis.html)

熊猫菜篮子分析

原文:https://towardsdatascience.com/market-basket-analysis-with-pandas-246fb8ee10a5?source=collection_archive---------18-----------------------

一般有哪些物品是一起买的?

Nathália Rosa 在 Unsplash 上拍摄的照片

购物篮分析是零售商实施的常见数据科学实践。目标是发现项目之间的关联。了解人们倾向于一起购买什么是非常重要的。

有一个像样的市场篮子分析提供了有用的洞察力过道组织,销售,营销活动,等等。

在本帖中,我们将分析 Kaggle 上可用的杂货店数据集。让我们从读取数据集开始。

import numpy as np
import pandas as pdgroceries = pd.read_csv("/content/Groceries_dataset.csv")groceries.shape
(38765, 3)groceries.head()

(图片由作者提供)

数据集的组织方式是每行代表特定客户在给定日期购买的商品。

在开始分析之前,我们应该检查数据类型,以及是否有任何丢失的值。

groceries.isna().sum().sum()
0groceries.dtypes
Member_number       int64 
Date               object 
itemDescription    object

没有丢失值,但是“日期”列的数据类型应该转换为日期时间,这可以通过 pandas 的 to_datetime 函数来完成。

groceries.Date = pd.to_datetime(groceries.Date)

我们先来看看平均每天售出的商品数量。一种方法是按日期对项目进行分组并对项目进行计数。然后我们可以画出结果。

import matplotlib.pyplot as pltgroceries[['Date','itemDescription']].groupby('Date').count()\
.plot(figsize=(12,6), legend=False, fontsize=14)plt.title('Number of Items Sold per Day', fontsize=18)
plt.xlabel('Date',fontsize=14)
plt.ylabel('Qty', fontsize=14)

(图片由作者提供)

如果我们降采样会更好看。我们可以使用重采样功能来降低频率。

groceries[['Date','itemDescription']].groupby('Date').count()\
.resample('M').mean()\
.plot(figsize=(12,6), legend=False, fontsize=14)plt.title('Number of Items Sold per Day', fontsize=18)
plt.xlabel('Date',fontsize=14)
plt.ylabel('Qty', fontsize=14)

(图片由作者提供)

看起来生意越来越好,因为商品数量呈普遍增长趋势。

数据集中的每一行都代表客户在某一天购买的一件商品。如果一个顾客一次购买了三件商品,将会有三行具有相同的顾客号和日期,但是具有不同的商品描述。

另一个衡量标准是每次购物的平均商品数量,它可以通过按客户编号和日期对商品进行分组来计算。

item_qty = groceries[['Member_number', 'Date','itemDescription']]\
.groupby(['Member_number','Date']).count().reset_index()item_qty.head()

(图片由作者提供)

Item_qty dataframe 显示每次购物的商品数量。例如,客户 1000 在 2014 年 6 月 24 日购买了 3 件商品。

平均每次购物的商品数量在 2.5 件左右。

item_qty.itemDescription.mean()
2.5907

我们还来看看每次购物的商品数量分布。

item_qty.itemDescription.plot(figsize=(10,6), kind='hist',
                              legend=False, fontsize=14)plt.title('Histogram of Item Quantities per Shopping', fontsize=18)

(图片由作者提供)

顾客最有可能一起购买 2-3 件商品。

购物篮分析的主要焦点是一起购买哪些项目。一种常见的技术是关联规则学习,这是一种发现变量之间关系的机器学习方法。Apriori 算法是一种常用的关联规则学习算法。

在这篇文章中,我们不会详细讨论 apriori 算法或关联规则学习。相反,我会告诉你一个简单的方法来检查哪些物品是经常一起购买的。

让我们首先创建一个包含每次购物的商品列表的数据框架。

items = groceries.groupby(['Member_number', 'Date'])\
.agg({'itemDescription': lambda x: x.ravel().tolist()}).reset_index()items.head()

(图片由作者提供)

客户 1000 在 2014 年 6 月 24 日购买的三种商品是全脂牛奶、糕点和咸点心。

我们需要确定哪些项目经常出现在“itemDescription”列的相同行中。

一种方法是在每行中创建项目的组合,并计算每个组合的出现次数。python 的 itertools 可以用来完成这项任务。

以下是第一行的示例。

import itertoolslist(itertools.combinations(items.itemDescription[0], 2))

(图片由作者提供)

第一行有 3 个项目,所以我们有 3 对组合。Itertools.combinations 不返回我们需要的重复组合(例如(' pastry ',' pastry '))。

下面的代码将对每一行执行该操作,并将组合添加到一个列表中。

combinations_list = []
for row in items.itemDescription:
    combinations = list(itertools.combinations(row, 2))
    combinations_list.append(combinations)

我们创建了一个列表列表:

(图片由作者提供)

我们可以通过使用 pandas 的 explode 函数从这个列表中创建一个列表,但是我们需要首先将它转换成 pandas 系列。

combination_counts = pd.Series(combinations_list).explode().reset_index(drop=True)

(图片由作者提供)

现在,我们可以使用 value_counts 函数来计算每个组合的出现次数。以下是十种最常见的组合:

(图片由作者提供)

第一个是惊喜,因为它是重复的。我们已经做出了没有重复元素的组合。数据集可能包含 repating 元素。例如,如果一个顾客一次买了 2 瓶全脂牛奶,那就必须有两行全脂牛奶。

我们可以通过计算每次购物时全脂牛奶的数量来确认。

whole_milk = groceries[groceries.itemDescription == 'whole milk']\
.groupby(['Member_number','Date']).count()\
.sort_values(by='itemDescription', ascending=False).reset_index()whole_milk.head()

(图片由作者提供)

看来我们怀疑的是正确的。例如,顾客 1994 在 2015 年 11 月 3 日购买了 4 瓶全脂牛奶。因此,最常见的组合是全脂牛奶和全脂牛奶是完全有道理的。

我们应该关注不重复的组合。例如,第二常见的组合是全脂牛奶和面包卷。全脂牛奶似乎主宰了购物清单。

我们已经做了一个简单和基本的市场篮子分析。大型零售商正在做更复杂的事情,他们可能会从许多不同的角度进行分析。

然而,总体目标通常是相同的,即能够预测客户的购买行为。

感谢您的阅读。如果您有任何反馈,请告诉我。

MLR 的市场组合建模应用

原文:https://towardsdatascience.com/market-mix-modelling-application-with-mlr-60b18bd3dc81?source=collection_archive---------29-----------------------

如何量化每个营销渠道对销售量的影响

市场组合建模(MMM)是一种分析方法,它将营销和销售数据转化为可以衡量营销渠道对销售量的影响的数量。这种技术和经验关系的关系,可以是线性的,也可以是非线性的,是通过每个渠道上的销售和营销费用之间的回归得到的。

Unsplash 上由 Austin Distel 拍摄的照片

使用模拟,其中每个营销渠道的成本是不同的,产生了多种情况,并取决于结果;衍生出有效的营销策略。由于使用了多线性回归,等式可以给出如下:

Sales= β_0 + β_1*(Channel 1) + β_2*(Channel 2)

其中销售代表销售量,渠道 1 和渠道 2 是不同的营销渠道,β_0 代表基本销售,即在没有任何营销活动的情况下,由于自然需求、品牌忠诚度和认知度而产生的销售量。另一方面,β_1 和β_2 是渠道 1 和渠道 2 的系数,代表每个渠道对销售量的贡献。

我们的数据集将是在 Kaggle 上可用的广告数据集。为了说明多元线性回归(MLR)如何应用于该数据集,我将只关注市场组合建模(MMM)的实施部分。

我们将使用 R 进行分析,让我们从导入我们的库开始:

library(ggplot2)
library(reshape2)

然后,阅读我们的数据集,检查缺失值并了解每一列的汇总统计数据:

*# Reading the dataset* 
data = read.csv('advertising.csv')*# Checking for missing values*
sapply(data, function(x) sum(is.na(x)))*# Checking summary statistics of each column*
summary(data)

每列的汇总统计信息

我们现在执行多元线性回归,将销售额作为因变量,将电视、广播和报纸支出作为因变量:

*# Multiple Linear Regression*linear_model = lm( Sales ~., data)
summary(linear_model)

线性回归模型汇总表

整体模型非常显著,p 值为 2.2e-16。除了截距这一常数项,电视和广播都是最重要的变量,分别与销售量有很强和中等的相关性。R 平方值为 0.9026,这意味着模型捕获了数据中 90%的方差。

最后,该等式可被给出为:

Sales= 4.6251241 + 0.0544458*TV + 0.1070012*Radio + 0.0003357*Newspaper

这里的基本销售额约为 4.63,这意味着无论营销策略是否到位,这都是将产生的最低销售额。还可以看出,与其他营销渠道相比,报纸的贡献是微不足道的,因为系数非常小。

此外,在所有营销渠道上的支出,无论贡献大小,都对销量有积极影响。我们现在来看看电视、广播和报纸的贡献图表。

贡献图是一种可视化营销活动影响的方法,以总贡献为基础,根据对销售额的百分比贡献来显示。

Contribution of TV spends = (Coefficient of TV spends) * Mean(TV spends)

同样,其他媒体的贡献也是确定的,电视贡献的百分比由电视贡献占总贡献的比率给出。

*# Contribution Charts*Base_Sale = linear_model$coefficients[1]
TV = linear_model$coefficients[2]*mean(data$TV)
Radio = linear_model$coefficients[2]*mean(data$Radio)
Newspaper = linear_model$coefficients[2]*mean(data$Newspaper)df_cc = data.frame(Medium = c("Base Sale","TV","Radio","Newspaper"),Contribution = c(Base_Sale,TV,Radio,Newspaper))
df_cc$Percentage_Contribution = round(df_cc$Contribution*100/sum(df_cc$Contribution),2)ggplot(df_cc,aes(y=Percentage_Contribution,x=Medium))+geom_bar(stat='identity',fill = 'darkred')+coord_flip()

每个营销渠道的贡献细分

在评估了每种媒体的贡献后,我们现在计算每种媒体的有效性或弹性,即销售额随单位支出变化的百分比变化:

*# Price Elasticity*df_cc$Elasticity = df_cc$Contribution/mean(data$Sales)
df_cc2 = df_cc
df_cc2 = df_cc2[df_cc2$Medium != 'Base Sale',c("Medium","Elasticity")]
print(df_cc2)

所有营销渠道的弹性表

在给定数据集上使用 MMM,我们能够量化不同营销渠道对销量的影响,并确定电视是开展促销和活动的最有效媒体。这一发现也得到了鲁宾逊在 2009 年进行的研究的支持,他引用说“电视广告似乎和以往一样有效,甚至可能增加无效性。”

MMM 可用于创建优化的策略,使得基于不同信道的性能,性能差的信道的预算可被重新分配给性能更强的媒体。

但是,请注意,通过时间序列分析,可以观察到最佳花费。这是因为在某个时间点之后,达到了饱和,无论花费多少,对销售量都没有影响。此外,当营销活动进行时,总会有一种溢出或结转效应,随着时间的推移而逐渐衰减。为了理解这一点,可以进行 Adstock 分析,以了解结转效应以及收益递减规律,即花第一美元比第二、第三或第四美元更有效。

感谢您的阅读。对于任何想法或反馈,请随时通过给我的 Linkedin 发送消息来与我分享!

https://www.linkedin.com/in/faizfablillah/➡️

市场分笔成交点-数据回放

原文:https://towardsdatascience.com/market-tick-data-replay-9719866eb64c?source=collection_archive---------38-----------------------

一个只有 100 行代码的市场数据回放工具。

Wolfpack Flow 是我正在开发的用于操作订单流的最新工具。来源:www.wolfpackflow.com

在过去的几个月里,我一直在研究一个可视化和分析分笔成交点数据的解决方案。虽然该工具的第一个版本开发得非常快,但它被证明存在一些延迟问题,图形部分也很好,但缺乏现代标准,如平滑滚动,这需要适当的硬件加速使用。

带着比自然技能更多的承诺和决心,我一直在开发一个新的改进版本,它被证明比我最初预期的更复杂和更具挑战性,但同时也增加了只有专业工具才有的功能。

在开发过程中,当市场关闭时,我面临着没有市场数据的问题,这在某种程度上限制了开发时间,尤其是在周末或 CME 清算时间工作是一种负担(尽管我不提倡在周末工作)。

为了克服这个问题,我开发了一个小型市场数据回放工具,事实证明这是一个非常简单的工具,可以在不到一个小时的时间内实现。这个简单的工具允许:

  1. 用一致的和可复制的数据集测试你的软件,
  2. 简化调试,因为您总是处理相同的数据包、时间戳等。这看起来是一个小好处,但在处理低级软件处理字节和时间戳时却不是。
  3. 将开发与市场数据馈送 API 分离。
  4. 将开发时间与市场时间分离。
  5. 出于训练目的复制过去的市场条件——可能需要更复杂的代码,但基础已经在这里了。

要做到这一点,你只需要 3 个步骤和大约 100 行代码。

1.获取数据

在我的例子中,我在数据馈送 API 提供者和我正在开发的工具之间开发了一个定制的中间网络接口。这允许将与数据供应商和应用程序相关的逻辑解耦。我这样做是因为:

  1. 更改数据馈送提供者更容易,因为您只需要专注于更改与市场数据 API 交互的代码。
  2. 该软件可以位于不同的服务器上,因为我们使用 UDP 套接字来与两个软件模块进行通信。
  3. 任何与市场数据馈送 API 代码相关联的潜在软件许可问题都通过使用中间的中性网络协议而被绕过(尽管这将产生激烈的争论)。

为了捕获数据,可以使用 tcpdumpWireshark 等工具尽管作为开源软件出身卑微,但它们是可以可靠使用的专业工具。 Wireshark 其实诞生于一个小电信运营商。它们甚至在第一层电信级电信环境中被广泛使用,并且已经成为非常成功的专业网络监控和审计解决方案的核心。对于更严重的应用,可以编写一个定制的数据包分析器,并作为插件集成到 Wireshark中。

Wireshark 允许捕获任何网络协议。

这使我们能够从数据中生成输出。在我的例子中,为了简单起见,我只使用了 Wireshark 的文本格式,它会生成一个相当长的文件。

从 Wireshark 捕获的文件可以导出为多种格式,包括纯 ASCII 文本。

2.解析数据

这样一个冗长的文件(它为每个包创建了 14 行文本)肯定是不需要的,也不适合提供给重放工具。

一点经典的 UNIX 足以将这个文件转换成更合适的文件。假设有两个字段的 CSV。我不太喜欢 CSV,因为使用固定宽度的字段更有效,但这次我在寻找最简单的选项。

“数据工程”是这个行业中最不吸引人的部分,包括许多像这样的步骤。

现在数据是一种易于阅读的格式,可以输入任何软件。请注意,解析是用我正在使用的特定协议完成的,但是它可以用于任何协议,因为该工具是不知道数据包大小的。

3.开发你的重放工具

快速开发对我来说意味着 Java,所以我用 Java 编写了这个小工具(对其他人来说意味着其他语言)。它基本上分为两类:

  1. market file reader—读取解析的文件并遍历每一行(数据包),处理延迟并提交数据包。
  2. PacketSender —打开 UDP 套接字并提供传递 UDP 数据包的方法。

源代码如下:

如您所见,代码非常简单和基本。实现这样一个小工具一点也不困难,甚至比学习一个现有的工具还要快。

摘要

市场数据回放不是一个常见的功能,但它在交易中有一些优势,不仅在开发方面,而且在自主交易的培训方面。能够复制市场数据馈送是测试整个数据管道的最佳方式,它使开发能够处理小的市场数据样本,而无需配置实际的实时市场数据馈送。

马尔可夫和隐马尔可夫模型

原文:https://towardsdatascience.com/markov-and-hidden-markov-model-3eec42298d75?source=collection_archive---------0-----------------------

用例子详细说明

图 1 .随机过程——作者图片

一个随机 过程是由一些数学集合索引的随机变量的集合。也就是说,随机过程的每个随机变量与集合中的一个元素唯一关联。用于索引随机变量的集合称为索引集合,随机变量集合形成状态空间。一个随机 过程可以基于状态空间、指标集等以多种方式分类。

随机 过程被解释为时间时,如果该过程有整数、数字、自然数等有限个元素,那么它就是离散时间。

随机性模型

它是一个离散时间过程,在时间 1、2、3……获取被观察的状态的值。

例如,如果状态(S)= {热,冷}

状态序列随时间变化=> z∈ S_T

4 天的天气可以是一个序列= >{ Z1 =热,z2 =冷,z3 =冷,z4 =热}

马尔可夫和隐马尔可夫模型被设计用来处理数据,这些数据可以被表示为一段时间内的观察“序列”。隐马尔可夫模型是概率框架,其中观察到的数据被建模为由几个(隐藏的)内部状态之一生成的一系列输出。

马尔可夫假设

马尔可夫模型主要是基于两个假设开发的。

  1. 有限视界假设:处于 t 时刻状态的概率只取决于(t-1)时刻的状态。

等式 1 .有限视野假设

这意味着在时间 t 的状态代表对过去的足够总结来合理地预测未来。这个假设是一阶马尔可夫过程。k 阶马尔可夫过程假设状态 z_t 与其前 k + 1 步的状态条件无关。

2.平稳过程假设:给定当前状态,下一个状态的条件(概率)分布不随时间变化。

等式 2 .平稳过程假设

这意味着状态会随着时间不断变化,但潜在的过程是静止的。

符号约定

  • 有一个初始状态和一个初始观测 z0 = s0
  • s_0 —时间 0 时状态的初始概率分布。
  • 初始状态概率— (π)
  • 在 t=1 时,看到第一真实状态 Z1 的概率是 p(Z1/z0)
  • 因为 z0 = s0,

状态转移矩阵

在任何时间 t 从状态 i 转换到状态 j 的𝐀𝐢,𝐣=概率。以下是包括初始状态在内的四个状态的状态转换矩阵。

图 2 .状态转移矩阵—作者图片

马尔可夫模型中的两个主要问题

  1. 状态 z 的特殊序列的概率?
  2. 我们如何估计状态转移矩阵 A 的参数以最大化观察序列的可能性?

特定序列的概率

等式 4 .找到特定序列的概率

考虑上面的状态转移矩阵(图 2),让我们找出序列的概率— > {z1 = s_hot,z2 = s_cold,z3 = s_rain,z4 = s_rain,z5 = s_cold}

P(z)= P(s _ hot | s _ 0)P(s _ cold | s _ hot)P(s _ rain | s _ cold)P(s _ rain | s _ rain)P(s _ cold | s _ rain)

= 0.33 x 0.1 x 0.2 x 0.7 x 0.2 = 0.000924

隐马尔可夫模型(HMM)

当我们不能观察状态本身,而只能观察状态的一些概率函数(观察)的结果时,我们利用 HMM。HMM 是一个统计的马尔可夫模型,其中被建模的系统被假设为一个马尔可夫过程,具有未观察到的(隐藏的)状态。

马尔可夫模型:一系列(隐藏)状态 z={z_1,z_2…………}取自州字母表 S ={s_1,s_2,…。𝑠_|𝑆|},z_i 属于 s。

隐马尔可夫模型:从一个输出字母表 V= {𝑣1,𝑣2,…中抽取的一系列观测输出 x = {x_1,x_2,…}。。,𝑣_|𝑣|}其中 x_i 属于 v

HMM 的假设

嗯,也是建立在几个假设之上的,以下是至关重要的。

  • 输出独立性假设:当给定当前隐藏状态时,输出观察有条件地独立于所有其他隐藏状态和所有其他观察。

等式 5

  • 发射概率矩阵:给定相应时间的状态为 s_j,隐藏状态产生输出 v_i 的概率

作为有限状态机的隐马尔可夫模型

考虑下面图 3 中给出的例子,它详细说明了一个人在不同气候下的感觉。

图 3 .作为有限状态机的马尔可夫模型—作者图片

一组状态= {快乐,暴躁}

隐藏状态集(Q)= {晴天,雨天}

随时间变化的状态序列= z∈ S_T

四天的观察状态=

  • 你从一个人的情绪中理解的感觉被称为观察,因为你观察它们。
  • 影响一个人感觉的天气被称为隐藏状态,因为你无法观察到它。

排放概率

在上面的例子中,感觉(开心或暴躁)只能被观察到。一个人可以观察到一个人有 80%的机会快乐,只要在特定的观察点(或者在这种情况下是一天)气候晴朗。同样,在多雨的气候下,一个人有 60%的几率变得暴躁。这里提到的 80%和 60%是排放概率,因为它们处理的是观测数据。

转移概率

当我们考虑影响观察的气候(隐藏状态)时,在连续的晴天或隔天下雨之间存在相关性。有 80%的机会连续几天天气晴朗,而有 60%的机会连续几天下雨。解释向/从隐藏状态转移的概率是转移概率。

HMM 中的三个重要问题是

  1. 一个观测序列的概率是多少?
  2. 最有可能产生观察序列的状态序列是什么?
  3. 给定一些数据,我们如何学习 HMMs 参数 A 和 B 的值?

1.观察序列的概率

我们必须把数据 x 的可能性加起来,给定每一个可能的隐藏状态序列。这将导致 O(|S|)^T. 的复杂性,因此引入了两个替代程序来寻找观察序列的概率。

  • 正向程序

计算所有观测值(从 t1 开始)到时间 t 的总概率。

𝛼_𝑖 (𝑡) = 𝑃(𝑥_1 , 𝑥_2 , … , 𝑥_𝑡, 𝑧_𝑡 = 𝑠_𝑖; 𝐴, 𝐵)

  • 反向程序

类似地,计算从最终时间(T)到 T 的所有观测值的总概率。

𝛽_i (t) = P(x_T,x_T-1,…,x_t+1,z _ t = s _ I;a,B)

使用正向程序的示例

S = {热,冷}

v = {v1=1 个冰淇淋,v2=2 个冰淇淋,v3=3 个冰淇淋}其中 V 是一天消费的冰淇淋数量。

示例序列= {x1=v2,x2=v3,x3=v1,x4=v2}

图 4 .以矩阵形式给出的数据——作者提供的图片

图 5 .为 HMM 生成的有限状态机—作者图片

我们首先需要计算先验概率(即在任何实际观察之前热或冷的概率)。这可以从 S_0 或π得到。从图 4 中,S_0 被提供为 0.6 和 0.4,它们是先验概率。然后,基于 Markov 和 HMM 假设,我们遵循下面图 6、图 7 和图 8 中的步骤来计算给定序列的概率。

1.对于第一次观察到的输出 x1=v2

图 6 .步骤 1 —作者提供的图片

2.对于观察到的输出 x2=v3

图 7 .步骤 2 —作者提供的图片

3。 为观察输出 x3 和 x4

类似地,对于 x3=v1 和 x4=v2,我们必须简单地将通向 v1 和 v2 的路径相乘。

图 8 第 3 步和第 4 步—作者提供的图片

2。最大似然分配

对于给定的观察到的输出序列𝑥 𝜖 𝑉_𝑇,我们打算找到最可能的状态序列𝑧 𝜖 𝑆_𝑇.我们可以通过下面的例子来理解这一点。

图 9 .实施例 2 的数据—作者提供的图片

图 10 .来自图 9 的作为有限状态机的马尔可夫模型

维特比算法是一种动态编程算法,类似于常用于寻找最大似然的正向程序。它不是跟踪生成观测值的总概率,而是跟踪最大概率和相应的状态序列。

考虑情绪的顺序:H,H,G,G,G,H 连续 6 天。使用维特比算法,我们将找到更多的序列的可能性。

图 11 .维特比算法要求选择最佳路径——作者的图像

将会有几条路径会导致周六的晴天,而很多路径会导致周六的雨天。在这里,我们打算确定最佳路径,直到晴天或雨天的星期六,并乘以快乐的转换发射概率(因为星期六使人感到快乐)。

让我们考虑一个晴朗的星期六。前一天(星期五)可以是晴天也可以是雨天。然后我们需要知道周五之前的最佳路径,然后乘以导致暴躁情绪的排放概率。迭代地,我们需要计算出在一系列日子中更有可能结束的每一天的最佳路径。

图 12 .步骤 1 —作者提供的图片

图 13 .步骤 2 —作者提供的图像

图 14 .迭代算法以选择最佳路径——作者图片

该算法留给你最大似然值,我们现在可以为给定的输出序列产生具有最大似然的序列。

3。学习 HMMs 参数 A 和 B 的值

HMMs 中的学习包括估计状态转移概率 A 和输出发射概率 B,这使得观察到的序列最有可能。期望值最大化算法用于此目的。一种被称为 Baum-Welch 算法的算法被广泛使用,它属于这一类别,并且使用前向算法。

博客全面描述了 Markov 和 HMM。这个博客主要是提供一个例子来解释给定序列的概率和 HMM 的最大似然,这在考试中也经常是有问题的。感谢你一直阅读博客,希望这对备考有所帮助。

马尔可夫随机场与图像处理

原文:https://towardsdatascience.com/markov-random-fields-and-image-processing-20fb4cf7e10d?source=collection_archive---------8-----------------------

网格上的无向图形模型

美国地质勘探局在 Unsplash 上拍摄的照片

这篇文章涵盖了马尔可夫随机场及其在图像处理中的具体问题的应用。我们不深究,不拘泥于形式,只凭直觉。

马尔可夫随机场是这样一种图,其节点模拟随机变量,其边模拟随机变量对之间的期望局部影响。本地的影响传播到全球,利用图的连通性。

这里有一个例子。考虑矩形网格上的图像。它由像素组成。每个像素都有一个值,表示它的颜色。在内部,对于黑白图像,像素可以表示为二进制变量,对于灰度图像,可以表示为连续变量,对于彩色图像,可以使用多个变量(例如 RGB)的混合。这些差异对我们来说无关紧要。就我们而言,一个像素有一个代表其颜色的值。

对此进行建模的自然 MRF 对每个像素都有一个节点。一条边连接两个相邻的节点(在网格上)。下面是一个 3x3 网格上的 MRF 示例。竖线和横线是它的边。

o — o — o
|   |   |
o — o — o
|   |   |
o — o — o

好的,这个 MRF 的结构与网格相匹配。听起来是件好事。选择这种结构是否有更深层次的原因?是的。

真实世界的图像往往是平滑的。也就是说,相邻像素倾向于具有相似的颜色。当然,它们也可能是突变,如边缘或对象边界。然而,在这些过渡之间通常有很多平滑。

正是 MRF 边缘在某种程度上有利于相邻像素具有相似的值。怎么会?首先,它将有助于引入一些新概念。然后我们再回来回答这个问题。

派系和能源职能

这种材料会有点钝。你可能会想,为什么我需要知道这些?这些点将很快开始连接,所以请耐心等待。

图中的团是一组节点,其中每一对节点都由一条边连接。如果一个团不是一个更大的团的一部分,那么它是最大的。

最大派系在 MRF 的运作中起着至关重要的作用。直觉上,每个这样的集团指定一组节点,所有这些节点的值直接相互影响。

在我们的 2D 图像例子中,最大团是图的边。三角形是不可能的,因为一条边只能连接相邻的像素。

好了,我们已经描述了哪些节点直接相互影响。我们如何控制这种影响的性质?在我们的 2D 图像示例中,我们希望相邻像素具有相似的值。

我们通过自己选择的所谓能量函数来控制集团中节点值之间的交互细节。这个函数(每个最大团一个)输入所有团节点的值,并输出其能量,一个标量。我们选择的能量函数应该将低能量分配给这些节点值的良好组合。也就是低能好。

对其节点的特定赋值的全局能量是图中所有最大团的能量之和。

平滑-支持能量函数。在我们的图像 MRF 中,什么能量函数会产生平滑度?考虑|-XJ|。这里 ij 表示相邻像素, xixj 表示它们的值。该能量函数更希望 xixj 具有相似的值。结果,全局能量将被最大程度平滑的图像最小化。

请注意,在引擎盖下, xixj 可能有多个维度,例如颜色的 RGB。我们不在乎,只要我们能有意义地计算出两种颜色之间的距离,这就是| xi - xj |是什么。

嗯,这很好,但是最平滑的图像有什么好处呢?所有像素将具有相同的颜色。

下面我们看到一些具体的有用的图像处理问题,其中平滑度,因此 MRF,发挥了重要作用。

图像去噪

考虑这个例子。

照片由乔希·卡恩Unsplash 上拍摄

看那些白点(星星)。假设有人愿意把它们当成噪音(尽管它们不是)。只需点击一个按钮,这个人就可以要求这个图像去噪。denoiser 的工作是将这些白点识别为最有可能的罪犯,并将它们涂黑。

为什么我们期望 MRF 能够把这些白点当成噪音来检测呢?为了便于讨论,假设每个白点是单个像素。一个点的像素是白色的,它所有的邻居都是黑色的。此外,黑色和白色是非常不同的颜色。MRF 不喜欢这种不和谐。也就是说,如果我们把光斑的颜色变成黑色,总能量会显著降低。这个推理适用于所有的白点。

对于亮红色球体中的任何像素,它至少有一些颜色相似的邻居。因此,大幅改变这种像素的颜色不会降低能量。

更丰富的 MRF 用于图像去噪

这个 MRF 有两层节点。两个表中的节点表示像素,就像在网格上布置的那样。像以前一样,第一个页面的边缘由网格决定。第二个工作表中的节点之间没有边。一条边连接两个工作表中表示同一像素的两个节点。

下面是一个 1X3 网格上的 MRF 示例。

*o — o — o      sheet one
|   |   |
o   o   o      sheet two*

我们将表一中的节点表示为 Y,表二中的节点表示为 X。我们将从要去噪的图像中设置 X 的值。这些值保持不变。Y 中的值表示去噪后的图像。这些值随着去噪过程的发展而变化。

我们将使用和以前一样的能量函数。这对全球能源有什么影响?它试图找到一个既接近输入图像又比输入图像平滑的去噪图像。

图像恢复

在这里,我们得到的图像既有噪声(即它的一些像素具有不正确的值),又有不完整(即它的一些像素没有值)。双张 MRF 也很适合解决这个问题。和以前一样,我们将从输入图像中设置 X 的值。除了输入图像中缺失值的像素保持空闲。

图像分割

这里我们想把图像分割成最大程度上同质的区域。同质性意味着某些属性在整个区域保持相似。该属性可以是颜色。还是质感。或者两者结合。最大化意味着不同的区域,尤其是相邻的区域,是不相似的。听起来像集群?是的,在图像属性的 2D 设置中:颜色等。

分割的一个特别关键的情况是将图像分成前景和背景。在我们的球体例子中,球体是前景,黑色的天空(包括星星)是背景。

一般来说,即使这样的二元分割也不容易做到。与我们示例中的简单背景(黑色天空)不同,其他背景可能有不同的纹理或颜色。另外,图像可能包含多个对象。事实上,在这种情况下,前景是如何定义的?

一种既能简化问题又能消除歧义的有效方法叫做交互式分割。用户在想要分割的目标周围画一个边界框。该算法将该框作为粗略的初始分割,并试图对其进行改进。

以天空为例,修改后的天空中有两个不同的球体。把它们想象成太阳和月亮。用户可以将边界框放在月亮周围。所以太阳和天空都在背景中。

建筑与能源功能

我们在这里也将使用两层 MRF 结构。和以前一样,X 页将包含图像。工作表 Y 将捕获其分段。工作表 Y 的节点是二进制值,用表示背景,表示前景。Y 中的边将形成与之前相同的网格结构。连接 X 和 Y 的边也是一样的。

我们将针对这个问题使用不同的能量函数。为什么?在前景上施加实质上的同质性而在背景上施加较弱的同质性(如果有的话)似乎是合理的。我们如何才能做到这一点?通过选择将 1 值比 0 值更“有力”地传播到相邻节点的能量函数。

我们将举例说明这个算法和能量函数,特别是简单的例子。(虽然,不好看。)

*______ __|___ ____| ____ ______*

这个例子是一个 1D 二进制图像。水平线段是不同长度的黑色像素串。这些被白色像素点打断。竖线划分边界框。

现在来看插图。给定边界框,Y 的初始赋值为

*Y           ________X ______ __|___ ____| ____ ______*

注意,X 中的框内部的白色像素在 y 中已经是黑色的。这就好像我们使用了先前的信念,即用户指定的边界框的内部应该全部被认为是在前景中,除非有实质的相反证据。

从这个初始 Y 开始,算法将把边界框向左扩展两个像素。为什么?因为能量函数的每个分量都会喜欢这个扩展。为什么?因为平滑度分量喜欢将 1 值传播给它的邻居。碰巧图像中这些点的实际像素也是 1 值(黑色)。所以算法会在下面描绘的 Y 处停止。

*Y        ___________X ______ __|___ ____| ____ ______*

高阶模型

我们能丰富我们的模型而不牺牲它的简单和优雅吗?在这里我们如何触及?更广泛的治疗,见[1]。

一种方法是扩展像素的邻域,例如,通过添加对角线连接,或者如果两个像素在特定距离 d 内,则连接两个像素。对于后者,我们可以使用欧几里德距离或曼哈顿距离。

如果我们要扩展一个像素的邻域,我们可以在边上引入权重,权重随着它们连接的像素之间的距离而衰减。

第二种方法是让节点不是代表单个像素,而是代表方形像素块。补丁的值将是我们想要的任何值。例如,块中像素强度的平均强度。如果片足够接近,则边将连接代表两个片的节点。还可以基于面片之间的距离将权重附加到边上。

延伸阅读

  1. 网格模型
  2. 吉布斯场&马尔可夫随机场 1 吉布斯场
  3. 马尔可夫随机场和吉布斯采样用于图像去噪

使用计算机视觉的掩模适应性跟踪

原文:https://towardsdatascience.com/mask-adaptivity-tracking-using-computer-vision-8d36de26f29?source=collection_archive---------45-----------------------

使用 YOLOv3 构建实时掩模适应性检测器

原始图片来源:Pixabay

口罩迅速成为新冠肺炎疫情的象征,超过 50 个国家强制规定。刚摆脱封锁的国家正强制要求在公共场合戴口罩,并接受一般服务。执行这一新规范也给全球各地的机构带来了新的挑战,即我们的安全摄像头无法自动跟踪社交距离和其他预防措施是否得到遵守。在本案例研究中,我们的目的是开发一种解决方案来跟踪人群的面具适应性,跟踪大多数人是否使用面具。

问题陈述

根据佩戴口罩的人数,确定口罩适应性是差、中还是高。从技术上讲,我们可以细分如下:

  1. 检测一帧中戴面具的人数(X)。
  2. 检测一帧中未戴口罩的人数(Y)。
  3. 计算度量(X/(X+Y)),基于某些阈值确定适应性的类别。

我们的方法

我们将该问题转化为两类(掩模,无掩模)对象检测问题,并训练了一个微小的 YOLO(基于卷积神经网络的最先进的对象检测框架)模型来服务于该目的。

有点 YOLO(你只看一次)

YOLO 是由 Joseph Redmon 等人开发的实时对象识别算法。在此之前,对象检测主要由分类器分两个阶段执行:

  1. 将图像分成各种区域,并找到感兴趣的区域(具有物体的概率高的区域)
  2. 使用 CNN 对这些区域进行分类

整个过程很慢,因为我们需要在多个区域中运行预测。YOLO 提出了另一种方法,不是从图像中选择 ROI,而是将问题映射到回归问题。在 YOLO,单个卷积神经网络被应用于整个图像,该网络在单次通过中预测每个区域的边界框和概率。这些预测的有界框然后被预测的概率加权。这种单次预测使它比其他算法快得多,如 R-CNN,更快的 R-CNN 等。

YOLO 在 COCO 数据集上的地图准确率达到 48.1,高于 SSD500 模型(46.1)。虽然它比两级检测器实现了更高的 FPS,但我们仍然认为它不足以满足我们基础设施有限的用例(单个 GPU)。我们选择了 YOLO 的一个更轻的版本,叫做小 YOLO,它比完整版快了将近 442%。虽然这是准确性和速度之间的权衡,我们仍然能够实现下降性能。

如何使用 YOLO 构建屏蔽检测器?

很酷的东西,原始视频来源:彭博快拍

现在让我们讨论真正有趣的部分。我将带你一步步使用微小的 YOLOv3 自己构建一个掩膜检测器。

步骤 0: 喝杯咖啡(完全可选)并下载这个包含所有必要文件的资源库

  1. 数据采集

收集高质量的数据是任何数据科学案例研究的关键部分,同样,谷歌是你的最佳选择。试着下载戴面具的人、不戴面具的人以及两者在不同背景、角度和尺度下的照片。更多高质量的数据使您的模型更加智能。我比较喜欢用一个叫 的 chrome 扩展来批量下载图片 。如果你想使用我的数据集,在这里找到它。

2.注释图像

如果您正在使用我的数据集,请跳过此步骤。如果您想使用自己的数据,我们建议使用label mg工具创建注释文件。

对于 windows,你可以在下载的库的注释工具文件夹中找到它。对于 Linux,你可以从这里下载。

标签工具

它将创建一个 txt 文件,如下所示,包含边界框的标签和坐标。

生成的注释文件

3.准备培训文件

为了让所有人都可以访问这个案例研究,并以最少的努力轻松再现它,我们将使用免费的 GPU 在 colab 中训练我们的模型。

a.进入 google drive,创建一个名为 darknet 的文件夹

b.你会在YOLO _ 自定义文件夹中找到培训所需的所有文件。

YOLO _ 自定义文件夹

文件描述

将您的图像和注释文件包含在图像文件夹中,并将路径添加到 train.txt 文件中,如下所示(无需更改图像文件夹的路径)。同样,如果你想坚持我的数据集,跳过这一步。上传YOLO _ 自定义文件夹到新建的暗网文件夹下的驱动器

train.txt 文件

Google Drive 文件夹结构

4.残局

原创图片鸣谢:www.syfy.com

现在去https://colab.research.google.com,用你的谷歌 id 登录

从下载的资源库上传YOLO _ 面具 _ 适应性. ipynb 笔记本(你会在笔记本文件夹下找到)。

确保从运行时启用 GPU

按照笔记本中提到的一步一步运行单元,准备 darknet 环境(相信我,它可以省去设置 CUDA 环境的许多麻烦)和培训。您还会发现检查图像、视频和网络摄像头预测所需的实用程序(不幸的是,colab 无法检测本地硬件,无论如何,我已经添加了代码,以防您有自己的 darknet 配置箱)。

笔记本中的步骤

留意平均损失,训练时会定期保存重量

我需要训练多长时间?

训练,直到你达到下降平均损失(0。XX)。您可以在yolo v3-tiny _ obj _ train . CFG文件中配置最大批次数量。训练时会定期保存重量,您也可以保存这些重量,下次从那里继续训练。

更换重量路径以恢复训练

冬天终于来了!

现实世界影响

该模型具有 244 FPS 的帧速率,适用于实时人群监控应用,并且可以通过公共场所的摄像头轻松使用。

人群面具适应性监测,原始图像学分:Pixabay

尾注

在这个案例研究中,我们学习了如何使用 colab 中的微小 YOLOv3 轻松构建一个遮罩自适应检测器。为了简单起见,我们避免了详细的培训步骤。实际上,您可以直接下载存储库,在 drive 中创建文件夹结构,然后立即在 colab 中启动,不需要担心设置 darknet、更改配置文件或文件路径。我们的目的是创建训练框架,以便您只需做最小的更改来训练掩模适应性模型或改进我们的案例研究。一个很好的练习将是使用您的家庭安全摄像机或网络摄像头部署模型。保持安全和愉快的学习!

预测,原始图片来源:Pixabay

附加链接

请参考以下文章,了解有关对象检测的更多信息

  1. Neptune.ai 博客—https://bit.ly/3tOjbSI
  2. https://pjreddie.com/darknet/yolo/
  3. https://drive.google.com/drive/folders/1T6N4qd4ep2YgxXdpCrkngOe_o1NszHH
  4. https://github.com/AlexeyAB/darknet

引用(T5)

  1. https://arxiv.org/abs/1506.02640
@misc{darknet13,
  author =   {Joseph Redmon},
  title =    {Darknet: Open Source Neural Networks in C},
  howpublished = {\url{http://pjreddie.com/darknet/}},
  year = {2013--2016}
}

从边缘到云的遮罩检测—使用 TensorFlow 和 Kafka

原文:https://towardsdatascience.com/mask-detection-from-the-edge-to-the-cloud-with-tensorflow-and-kafka-1b6668f15a60?source=collection_archive---------47-----------------------

使用 Raspberry Pi 和 Coral USB edge TPU 在边缘进行模型推断

Benedikt Geyer 在 Unsplash 上拍摄的照片

一个在这个社会距离越来越远的时代,科技更新了它建立一个更安全世界的承诺。热像仪、掩模检测机制不是 COVID 疫情的解决方案,但可以帮助检测风险区域,并通过调整当地公共政策来减缓集群的增长。

在本文中,我概述了如何基于配备摄像头和人脸检测人工智能的物联网设备网络构建一个系统,以识别某个空间内的人们是否戴着面罩,并收集此类事件。

演示—在 Pi 上运行屏蔽检测,并向 Kafka 主题发出和发布警报—图片由作者提供

本项目中使用的工具有:

这个项目你需要一个树莓 Pi 4 和它的相机。我还使用了一个 Coral USB 加速器来更快地推断圆周率。

用于收集和处理事件“这个人没有戴面具”的架构的大图—事件驱动的架构—图片由作者提供

与任何架构和工具选择一样,这是一个固执己见的问题。我在文章的最后略微阐述了我选择的工具的优点、缺点、局限性和优势。你有什么烦心事吗?大家在评论里讨论一下吧。😉

深潜

现在,让我们看看如何实现这个体系结构的每个组件。从逻辑上讲,我们可以把这个系统分成三个不同的部分。完整的代码可以从我的 GitHub 获得。

  1. 从 Raspberry Pi 摄像头馈送中检测某人是否戴着面具。【github.com/fpaupier/pi-mask-detection】-
  2. 从 Pi 到 Google Cloud 引擎的事件收集和分发:
    -github.com/fpaupier/alertDispatcher-
    -github.com/fpaupier/alertIngress
  3. 事件的进一步处理:
    -github.com/fpaupier/notifyMask

在本文中,我们重点关注这些组件之间的联系。

1.掩模检测

在我们系统的边缘,配备了一个 Pi,它的摄像头检测是否有事件发生。我将事件定义为:“某人没有戴面具。”

作者图片

为了检测某人是否戴着面具,我们遵循以下步骤:

  1. 检测当前画面中是否有人脸( MobileNet v2 )
  2. 如果是,将图像裁剪到该面部边界框。
  3. 在裁剪的面上应用遮罩/无遮罩二元分类器。(型号为此项目培训)
  4. 如果没有检测到掩码,则创建一个事件,并将其存储在本地存储中。

逻辑详见我的[detect_mask.py](https://github.com/fpaupier/pi-mask-detection/blob/master/detect_mask.py)main()功能

2.收集事件

一旦 Pi 记录了一个事件,我们就将其发送到服务器进行存档和进一步处理。

作者图片

当然,我们可以在 Pi 上直接运行通知系统。尽管如此,我们在这里的目标是说明一个由几个物联网设备报告事件的系统。进一步的处理是在云上完成的,以便在 1)边缘的事件收集和 2)受控环境中的高级处理之间进行适当的分离。

考虑这部分的两个存储库:

每个设备将其事件发布到 Kafka 主题—“警报—主题”—用于 Pi 和警报入口服务之间的异步通信。事件消息符合使用协议缓冲区定义的模式。

在云上,alert ingress 服务订阅了 alert-topic ,并将传入的事件存档在 PostgreSQL 中。然后,入口服务发布通知服务将使用的消息。

3.通知服务

作者图片

您已经将事件存档在云中,现在该怎么办?让我们添加一个通知服务,向管理员发送包含事件摘要的电子邮件。

通知服务发送的电子邮件-作者图片

一个有趣的后续工作是构建一个地理可视化工具来分析每个位置和时间的事件📍🗺

改进的余地

这个原型说明了这个概念,但不是一个生产就绪的基础设施。将这一概念应用到生产中需要考虑的关键因素有:

  • 事件重复数据删除——当前的实施为单个警报发送多个通知,因为我们为每个引发的警报发送一封电子邮件。某个没戴面具的人可能会出现在摄像机视频中一段时间。可以在服务器级别实施重复数据消除策略。
  • 想想您的保留策略 —定义一个合理的期限,在此期限内,您可以存储警报,然后再删除它们。您不希望将敏感数据(如人脸)保留一段不确定的时间。
  • 模式注册中心 —模式注册中心确保跨服务的一致消息定义。更新和向后兼容性不是小事。如果您决定更改、添加或删除警报事件中的字段,该怎么办?您如何将这种变化传播到您的物联网设备中?
  • 机器学习模型管理-您在边缘推送和部署的模型可能会随着时间的推移而漂移并看到其性能下降,从而导致误报或戴面具的人未被报告。检查 ML 流程项目,了解关于该主题的见解。
  • 设备注册流程—可以手动部署和设置您的第一批设备。十几年后它变成了挑战,一百年后它变成了噩梦。考虑为加入您的物联网设备群的设备自动执行入职流程(下载 ML 模型,获取 Kafka 证书)

工具

语言选择— 为什么选择 Python 和 Go?Python 便于与 TensorFlow 集成。请使用它的强类型和对网络相关操作的本机支持。

异步消息队列选择 —为什么是卡夫卡?许多其他解决方案在内存占用方面更轻量级,可以在边缘实现这个功能( MQTT )。但是,随着今天日益增长的计算能力的边缘,为什么烦恼呢?一个树莓 Pi 4 有 8Go 内存。

模式定义策略— 为什么选择 Protobufs?我明白你的意思;JSON 使用起来会更舒服,而且在这里也能做到。为了像这样的概念验证,使用 JSON 将省去很多麻烦,因为我们处理的是单个设备。然而,模式定义和一致性是事件驱动架构的一个关键特性,protobufs 使这变得更容易。

伦理考虑

这种想法有助于定位和缓解集群的增长,但可能会对个人隐私构成严重威胁。

关于负责任的机器学习的资源变得越来越容易获得,我邀请你在构建基于人工智能的系统时记住这些指导原则。

另请注意,通用数据保护条例( GDPR )对个人数据的收集和处理进行了严格的规定。

没有良知的科学是永恒的— 弗朗索瓦·拉伯雷 的《巨大的生命与巨大的痛苦》

掩膜面-基于 CV 的工具,用于掩膜面数据集

原文:https://towardsdatascience.com/masktheface-cv-based-tool-to-mask-face-dataset-1a71d5b68703?source=collection_archive---------29-----------------------

将面部数据集转换为掩膜数据集

图片来源:https://github.com/aqeelanwar/MaskTheFace

https://github.com/aqeelanwar/MaskTheFace】跳转代码:

什么是 MaskTheFace?

MaskTheFace 是一个基于计算机视觉的脚本,用于遮罩图像中的人脸。它使用基于 dlib 的面部标志检测器来识别面部倾斜和应用面具所必需的面部的六个关键特征。基于面部倾斜,从掩模库中选择相应的掩模模板。然后基于六个关键特征对模板面具进行变换,以完美地适合人脸。完整的框图如下所示。MaskTheFace 提供了几个可供选择的遮罩。很难在各种条件下收集掩膜数据集。MaskTheFace 可用于将任何现有的人脸数据集转换为被遮罩的人脸数据集。MaskTheFace 识别图像中的所有人脸,并将用户选择的遮罩应用于这些人脸,同时考虑各种限制,如人脸角度、遮罩适合度、光照条件等。单个图像或整个图像目录可以用作代码的输入。

图片来源:https://github.com/aqeelanwar/MaskTheFace

如何安装 MaskTheFace

建议用 Python 3.6 创建一个新的虚拟环境并安装依赖项。可以采取以下步骤下载 MaskTheFace 入门

克隆存储库

git clone [https://github.com/aqeelanwar/MaskTheFace.git](https://github.com/aqeelanwar/MaskTheFace.git)

安装所需的软件包

提供的 requirements.txt 文件可以用来安装所有需要的包。使用以下命令

cd MaskTheFace
pip install –r requirements.txt

这将在激活的 python 环境中安装所需的包。

如何运行 MaskTheFace

cd MaskTheFace
# Generic
python mask_the_face.py --path <path-to-file-or-dir> --mask_type <type-of-mask> --verbose --write_original_image# Example
python mask_the_face.py --path 'data/office.jpg' --mask_type 'N95' --verbose --write_original_image

图片来源:https://github.com/aqeelanwar/MaskTheFace

争论

图片来源:https://github.com/aqeelanwar/MaskTheFace

解释:

1.—代码

— code 参数可用于将不同类型的掩膜随机统一应用于数据集中的影像。

# Generic format
--code < masktype1 >-< color as hex or texture file path >, < masktype2 >-< color as hex or texture file path>, ...# Example
--code cloth-masks/textures/check/check_4.jpg, cloth-#e54294, cloth-#ff0000, cloth, cloth-masks/textures/others/heart_1.png, cloth-masks/textures/fruits/pineapple.png, N95

以上示例将对所选的人脸数据集应用 7 个随机统一的不同遮罩(通过路径参数)。

支持的掩码:

遮罩类型:

目前,MaskTheFace 支持以下 4 种遮罩类型

  1. 外科的
  2. N95
  3. KN95
  4. 气体

图片来源:https://github.com/aqeelanwar/MaskTheFace

正在添加新的面具。用户也可以按照提供的指南添加自定义遮罩。

遮罩变化:

上面提到的每种掩模类型可以在下面的术语中变化,以创建更多的掩模

1.纹理/图案变化:

MaskTheFace 提供了 24 种现有模式,可应用于上述遮罩类型,以创建更多的图形变化。此外,用户可以按照提供的指南轻松添加自定义模式。

图片来源:【https://github.com/aqeelanwar/MaskTheFace

2.颜色变化:

MaskTheFace 提供了一个脚本来根据颜色修改现有的遮罩类型,以生成现有图形的变体。

图片来源:【https://github.com/aqeelanwar/MaskTheFace

3.强度变化:

MaskTheFace 提供了一个脚本来根据强度修改现有的遮罩类型,以生成现有图形的变体。

图片来源:https://github.com/aqeelanwar/MaskTheFace

特点:

a.支持多种遮罩类型

图片来源:https://github.com/aqeelanwar/MaskTheFace

b.支持单面和多面图像:

图片来源:https://github.com/aqeelanwar/MaskTheFace

c.宽面角覆盖

图片来源:https://github.com/aqeelanwar/MaskTheFace

d.亮度校正掩模应用

图片来源:https://github.com/aqeelanwar/MaskTheFace

e.数据集上的批量屏蔽

图片来源:https://github.com/aqeelanwar/MaskTheFace

MFR2 —现实世界中用于人脸识别的蒙面人脸

用于人脸识别的真实世界中的蒙面人脸(MFR2)是一个小型数据集,具有 53 个名人和政治家的身份,总共有 269 幅图像,这些图像是从互联网上收集的。每个身份平均有 5 个图像。数据集包含身份的掩蔽和非掩蔽面。数据集根据面部对齐和图像尺寸进行处理。每个图像的尺寸为(160×160×3)。来自 MFR2 数据集和掩模分布的样本图像如下所示。

图片来源:https://github.com/aqeelanwar/MaskTheFace

下载 MFR2

可以使用以下命令下载数据集

cd MaskTheFace
python utils/fetch_dataset.py --dataset mfr2

这将下载并提取 datasets 文件夹中的 mfr2 数据集。

# path to mfr2
MaskTheFace/datasets/mfr2

或者,你可以从这里下载 mfr2.zip 文件

MFR2 的含量

下载的数据集文件夹包含

  1. 带有身份图像的文件夹
  2. mfr2_labels.txt:一个标签文本文件,包含身份名称、图像编号和遮罩基础事实的类型
  3. pairs.txt:包含 848 个正对和负对的文本文件,用于测试。

总结:

MaskTheFace 工具可用于生成合成的面具人脸数据集,然后可用于训练各种面向应用的 ML 网络,如室内考勤系统的人脸识别、面具检测、面具分类等。

如果这篇文章对你有帮助,欢迎鼓掌、分享和回复。如果你想了解更多关于机器学习和数据科学的知识,请关注我@Aqeel an war或者在LinkedIn上与我联系。

掌握 Seaborn 的三分之一:用 relplot()统计绘图

原文:https://towardsdatascience.com/master-a-third-of-seaborn-statistical-plotting-with-relplot-df8642718f0f?source=collection_archive---------7-----------------------

如果你能在锡伯恩做到,就在锡伯恩做吧

照片由来自像素布拉克·K拍摄

介绍

本文的目标是让你对使用 Seaborn 的relplot()函数绘制任何类型的定量变量统计图表有一个很好的了解。

当我开始学习数据可视化时,我第一次接触到 Matplotlib。这是一个如此巨大和深刻的图书馆,你可以想象几乎任何与数据相关的东西。正是这种辽阔,使人们能够以多种方式创造一个单一的情节。

虽然它的灵活性对于有经验的科学家来说是理想的,但作为初学者,区分这些方法之间的代码对我来说是一场噩梦。我甚至考虑过使用 Tableau 的无代码界面,作为一名程序员,我很惭愧地承认这一点。我想要一些易于使用的东西,同时,使我能够创建其他人正在制作的那些很酷的情节(用代码)。

我在 Udacity 攻读纳米学位时了解了 Seaborn,并最终找到了我的选择。这就是为什么我的数据可视化的黄金法则是“如果你能在 Seaborn 做,就在 Seaborn 做”。与 Matplotlib 相比,它提供了许多优势。

首先,它非常容易使用。您可以只用几行代码创建复杂的情节,并且仍然通过内置的样式使它看起来很漂亮。其次,它与熊猫数据框架配合得非常好,这正是你作为一名数据科学家所需要的。

最后但同样重要的是,它是建立在 Matplotlib 本身之上的。这意味着您将享受 Mpl 提供的大部分灵活性,并且仍然保持代码语法最少。

是的,我在标题中说的是真的。Seaborn 将其所有 API 分为三类:绘制统计关系、可视化数据分布和分类数据绘制。Seaborn 提供了三个高级功能,涵盖了它的大部分特性,其中之一是relplot()

reltplot()可以可视化定量变量之间的任何统计关系。在这篇文章中,我们将涵盖这个功能的几乎所有特性,包括如何创建支线剧情等等。

[## 通过我的推荐链接加入 Medium-BEXGBoost

获得独家访问我的所有⚡premium⚡内容和所有媒体没有限制。支持我的工作,给我买一个…

ibexorigin.medium.com](https://ibexorigin.medium.com/membership)

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

[## 阿尔法信号|机器学习的极品。艾总结的。

留在循环中,不用花无数时间浏览下一个突破;我们的算法识别…

alphasignal.ai](https://alphasignal.ai/?referrer=Bex)

概观

 I. Introduction II. SetupIII. Scatter plots with relplot()
     1\. Scatter plot point size
     2\. Scatter plot point hue
     3\. Scatter plot point style
     4\. Scatter plot point transparency
     5\. Scatter plot in subplots IV. Seaborn lineplots
     1\. Lineplot multiple lines
     2\. Lineplot line styling
     3\. Lineplot point markers
     4\. Lineplot confidence intervals
  V. Conclusion

获取关于 this GitHub repo 文章的笔记本和样本数据。

设置

我们导入 Seaborn 作为sns。你可能想知道为什么它不像任何正常人一样别名为sb。好吧,听听这个:它的别名来自电视剧《白宫风云》中的一个虚构人物塞缪尔·诺曼·西本。这是一个开玩笑的缩写。

对于样本数据,我将使用 Seaborn 的一个内置数据集和一个从 Kaggle 下载的数据集。你可以使用这个链接得到它。

第一个数据集是关于汽车的,包含关于它们的引擎、型号等的数据。第二个数据集提供了 500 多家公司的纽约股票价格信息。

基础探索

cars.head()
cars.info()
cars.describe()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 398 entries, 0 to 397
Data columns (total 9 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   mpg           398 non-null    float64
 1   cylinders     398 non-null    int64  
 2   displacement  398 non-null    float64
 3   horsepower    392 non-null    float64
 4   weight        398 non-null    int64  
 5   acceleration  398 non-null    float64
 6   model_year    398 non-null    int64  
 7   origin        398 non-null    object 
 8   name          398 non-null    object 
dtypes: float64(4), int64(3), object(2)
memory usage: 28.1+ KB

stocks.head()
stocks.info()

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 851264 entries, 2016-01-05 to 2016-12-30
Data columns (total 6 columns):
 #   Column  Non-Null Count   Dtype  
---  ------  --------------   -----  
 0   symbol  851264 non-null  object 
 1   open    851264 non-null  float64
 2   close   851264 non-null  float64
 3   low     851264 non-null  float64
 4   high    851264 non-null  float64
 5   volume  851264 non-null  float64
dtypes: float64(5), object(1)
memory usage: 45.5+ MB

两个数据集中有一些空值。由于我们没有进行任何认真的分析,我们可以放心地放弃它们。

cars.dropna(inplace=True)
stocks.dropna(inplace=True)

专业提示:让你的数据集尽可能的整洁,这样 Seaborn 才能有好的表现。确保每行是一个观察值,每列是一个变量。

relplot散点图

让我们从散点图开始。散点图是找出变量之间的模式和关系的最好和最广泛使用的图之一。

这些变量通常是定量的,如测量值、一天中的温度或任何数值。散点图将 x 和 y 值的每个元组可视化为单个点,并且该图将形成点云。这些类型的图非常适合人眼检测模式和关系。

你可以用 SB 的(我从现在开始缩写)内置scatterplot()函数来创建散点图。但是这个功能缺乏relplot()版本所提供的灵活性。让我们看一个使用relplot()的例子。

照片由麦克像素拍摄

使用cars数据集,我们想找出是否更重的汽车往往有更大的马力。由于这两个特征都是数字,我们可以使用散点图:

sns.relplot(x='weight', y='horsepower', 
            data=cars, kind='scatter');

relplot()函数有自变量xydata参数,分别指定要绘制在XAxisYAxis上的值及其应使用的数据。我们使用kind参数来指定它应该使用散点图。其实默认设置为scatter

从剧情可以解读出,更重的车确实马力更大。同样清楚的是,有更多的汽车重量在 1500 到 3000 之间,马力在 50 到 110 之间。

散点图点大小

基于我们之前的绘图,现在我们还想添加一个新的变量。我们来看看更重的车是不是排量更大(能储多少油)。理想情况下,我们希望将该变量绘制为磅值:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement');

使用size参数改变第三个变量的点大小。只需将列名作为字符串传递,就可以设置好了,就像我们的例子一样。该图显示了重量和发动机尺寸之间的明确关系。然而,你可以在中间看到一些不符合趋势的点。

重要的是,您要传递一个“值周期”较少的数值变量。在我们的例子中,位移为 5(0–80,80–160 等)。如果这些时间变得太多,将很难解释你的情节,因为人眼不善于判断事物。如果我们以重量作为第三个变量来创建上面的图,您可以看到这一点:

sns.relplot(x='displacement',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='weight');

正如你所看到的,趋势不明显,很难区分大小。

散点图点色调

散点图中的第三个变量也可以使用彩色标记。它也非常简单,就像磅值一样。假设我们还想将加速度(汽车达到 60 英里/小时所需的时间,以秒为单位)编码为点颜色:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration');

从图中,我们可以看到数据集中一些最快的汽车(暗点)马力较低,但重量也较轻。注意,我们使用了hue参数对颜色进行编码。颜色根据传递给该参数的变量类型而变化。如果我们已经通过了origin列,这是一个分类变量,它将有三个颜色标记,而不是一个连续的(从亮到暗)调色板:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='origin');

专业提示:注意您输入到hue参数的变量类型。类型可以完全改变结果。

如果您不喜欢默认的调色板(默认情况下非常好),您可以轻松地自定义:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration',
            palette='crest');

palette参数设置为您自己的颜色映射。可用调色板列表可在这里找到。

散点图点样式

让我们回到第一个情节。我们绘制了重量与马力的散点图。现在,让我们添加原点列作为第三个变量:

sns.relplot(x='weight', y='horsepower', 
            data=cars, hue='origin');

虽然颜色在该图中增加了额外的信息层,但在更大的数据集中,可能很难区分点群中的颜色。为了更加清晰起见,让我们在图中添加一个点样式:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            hue='origin',
            style='origin');

现在,好一点了。改变点的样式和颜色是非常有效的。如果我们仅使用点样式来指定原点,看看会发生什么:

sns.relplot(x='weight', y='horsepower', 
            data=cars, style='origin');

专业提示:结合使用huestyle参数,让你的绘图更加清晰。

我们删除了hue参数,这使得我们的情节更加难以理解。如果您不喜欢默认颜色,您可以更改它:

首先,您应该创建一个字典,将各个颜色映射到每个类别。请注意,该字典的键应该与图例中的名称相同。

hue_colors = {'usa': 'red', 
              'japan': 'orange', 
              'europe': 'green'}
sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            hue='origin',
            style='origin',
            palette=hue_colors);

从图中,我们可以看到数据集中的大多数汽车来自美国。

散点图点透明度

让我们再次回到我们的第一个例子。让我们再画一次,但是给点增加一点透明度:

sns.relplot(x='weight', y='horsepower', 
            data=cars, alpha=0.6);

我们使用alpha参数来设置点的透明度。它接受 0 到 1 之间的值。0 表示完全透明,1 表示完全不透明。当您有一个大的数据集,并且您想要找出图中的聚类或组时,这是一个非常有用的功能。当你降低透明度时,有很多点的部分会变暗。

支线剧情中的散点图

在《海波恩》中也可以使用支线剧情网格。我之所以一直用relplot()而不是能做以上所有事情的scatterplot(),是因为它不能创建支线剧情网格。

由于relplot是一个图形级别的函数,它产生一个FacetGrid(许多情节的网格)对象,而scatterplot()绘制到一个matplotlib.pyplot.Axes(单个情节)对象上,该对象不能变成子情节:

fg = sns.relplot()
print(type(fg))
plot = sns.scatterplot()
print(type(plot))<class 'seaborn.axisgrid.FacetGrid'>
<class 'matplotlib.axes._subplots.AxesSubplot'>

让我们看一个我们想要使用支线剧情的例子。在上面的一个图中,我们将 4 个变量编码到一个图中(重量与马力,用位移和加速度编码)。现在,我们还想加入汽车的起源。为了使信息更容易理解,我们应该把它分成支线剧情:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration',
            palette='crest',
            col='origin');

这一次在最后,我们添加了一个新的参数,col来指出我们想要在列中创建支线剧情。这些类型的支线剧情非常有用,因为现在很容易看到第五个变量的趋势。顺便说一下,传递给col的变量应该是明确的,这样才能工作。此外,SB 在一行中显示列。如果要绘制多个类别,我们不希望出现这种情况。让我们使用我们的数据来看一个用例,尽管它的类别较少:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration',
            palette='crest',
            col='origin',
            col_wrap=2);

col_wrap argument 告诉某人我们想要一行中有多少列。

还可以指定列中类别的顺序:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration',
            palette='crest',
            col='origin',
            col_order=['japan', 'europe', 'usa']);

也可以按行显示相同的信息:

sns.relplot(x='weight',
            y='horsepower',
            data=cars,
            kind='scatter',
            size='displacement',
            hue='acceleration',
            palette='crest',
            row='origin');

如果你有很多类别,使用行不是很有用,最好坚持使用列。您可以再次使用row_order来指定行的顺序。

Seaborn 线图

另一种常见的关系图是线形图。在散点图中,每个点都是独立的观察值,而在线图中,我们将一个变量与一些连续变量一起绘制,通常是一段时间。我们的第二个样本数据集包含 2010 年至 2016 年跟踪的 501 家公司的纽约证券交易所数据。

为了便于说明,我们来观察给定时间段内所有公司的close价格。由于涉及到日期,折线图是此任务的最佳视觉类型:

Pro 提示:如果你的数据集中有一个日期列,将其设置为 datetype,并使用set_index()函数将其设置为索引。或者用pd.read_csv(parse_dates=['date_column'], index_col='date_column')。它将允许您绘制线图,并使日期的子集设置更容易。

对于线图,我们再次使用relplot()并将kind设置为line。该图描绘了跟踪第二个连续变量(通常是时间)的单个变量。

sns.relplot(x=stocks.index, y='close', 
            data=stocks, kind='line');

它花了相当长的时间来绘制,但我们可以看到明显的趋势。所有公司的股票在给定的时间内都保持增长。蓝色较暗的线代表 6 年来跟踪的所有公司收盘价的平均值。

SB 会自动添加一个置信区间,即线周围的阴影区域,如果一个点有多个观察值,稍后会详细介绍。现在,让我们将数据细分为 3 家公司:

am_ap_go = stocks[stocks['symbol'].isin(['AMZN', 'AAPL', 'GOOGL'])]
am_ap_go.shape(5286, 6)

线条绘制多条线

现在,让我们通过将数据分组到三个公司来重新创建上面的线图。这将在同一个图中创建不是一条而是三条线:

sns.relplot(x=am_ap_go.index,
            y='close',
            data=am_ap_go,
            kind='line',
            hue='symbol');

正如我们在散点图示例中所做的那样,我们使用hue参数在数据中创建子组。同样,您必须将一个分类变量传递给hue。在这个图中,我们可以看到,在 2016 年之后,亚马逊和谷歌的股票非常接近,而苹果在整个时期都处于底部。现在,让我们看看除了颜色之外,如何设计每条线的风格:

线地块线样式

我们使用style参数来指定我们想要不同的线条样式:

sns.relplot(x=am_ap_go.index,
            y='close',
            data=am_ap_go,
            kind='line',
            hue='symbol',
            style='symbol');

好吧,这可能不是不同线条样式的最佳示例,因为观察是针对每天的,并且非常紧凑。让我们仅针对 2015 年至 2016 年期间划分子集,并绘制相同的线图:

am_ap_go_subset = am_ap_go.loc['2015-01-01':'2015-12-31']sns.relplot(x=am_ap_go_subset.index,
            y='close',
            data=am_ap_go_subset,
            kind='line',
            hue='symbol',
            style='symbol');

现在线条样式更清晰了。您可能会说,对这些行进行样式化并不会比前一个添加更多的信息。但是当你有一个情节,它的线条非常接近时,这将对解释有很大的帮助。

线形图点标记

当您有一个较小的数据集并且想要创建一个折线图时,用一个标记来标记每个数据点可能会很有用。对于我们较小的数据,股票价格的分布仍然非常紧密。因此,让我们选择一个更小的时间段,看看如何使用点标记:

smaller_subset = am_ap_go_subset.loc["2015-01-01":"2015-03-01"]

sns.relplot(x=smaller_subset.index,
            y='close',
            data=smaller_subset,
            kind='line',
            hue='symbol',
            style='symbol',
            markers=True)
plt.xticks(rotation=60);

现在我们每条线都有不同的标记。我们将markers参数设置为True来激活该功能。

线图置信区间

接下来,我们将探讨在 SB 中为线图计算的置信区间。如果一个点有多个观察值,置信区间会自动添加。

在这三家公司的数据中,对于这一时期的每一天,我们都有三个观察值:一个是亚马逊,一个是谷歌,一个是苹果。当我们创建一个没有分组的线图时(没有hue参数),SB 默认取这三个的平均值:

sns.relplot(x=am_ap_go.index, y='close', 
            data=am_ap_go, kind='line');

深色线表示三家公司股价的平均值。阴影区域是 95%的置信区间。这是非常巨大的,因为我们的样本数据只有三家公司。阴影区域表示有 95%的把握总体平均值在此区间内。它表明了我们数据中的不确定性。

例如,对于 2017 年,人口的平均值可以在 100 和 800 之间。置信区间的范围很大,因为我们只选择了三家公司。抱歉,我不得不添加统计术语,但这对理解置信区间很重要。您可以关闭置信区间,将ci参数设置为None:

sns.relplot(x=am_ap_go.index,  
            y='close', 
            data=am_ap_go,  
            kind='line', ci=None);

或者如果你愿意,你可以显示标准差而不是置信区间。将ci参数设置为sd:

sns.relplot(x=am_ap_go.index, 
            y='close', 
            data=am_ap_go, 
            kind='line', 
            ci='sd');

也许这些参数对我们的样本数据不是很有用,但当您处理大量真实数据时,它们将非常重要。

最后注意:如果你想为你的线图创建支线图,你可以使用相同的colrow参数。

结论

最后,我们完成了 Seaborn 的关系图。线图和散点图是在数据海洋中发现见解和趋势的非常重要的视觉辅助工具。因此,掌握它们是很重要的。并尽可能使用 Seaborn 来创建它们。你看到了使用图书馆是多么容易。

查看我关于数据可视化的其他文章:

[## 掌握 Seaborn 中的 catplot():分类数据可视化指南。

如果你能在锡伯恩做到,那就在锡伯恩做吧,#2

towardsdatascience.com](/mastering-catplot-in-seaborn-categorical-data-visualization-guide-abab7b2067af) [## 一劳永逸地澄清困惑:fig,ax = plt.subplots()

了解 Matplotlib 中的图形和轴对象

towardsdatascience.com](/clearing-the-confusion-once-and-for-all-fig-ax-plt-subplots-b122bb7783ca)

主数据科学案例研究:招聘经理的视角

原文:https://towardsdatascience.com/master-data-science-case-studies-a-hiring-managers-perspective-49e508263280?source=collection_archive---------30-----------------------

我先说:我去过!

我曾经遇到过这种情况,我从不同的公司获得了一堆数据科学案例研究,我必须找出问题所在,如何解决它以及应该关注什么。相反,我也为数据科学和分析职位设计案例研究,将它们发给候选人,并评估我收到的提交材料。

基于这一经历以及与他人(包括候选人和招聘经理)的交谈,我想回答一些与案例研究相关的典型问题,并解释它们的好处。为此,我将列出招聘经理的一系列共同期望。我相信,如果你了解招聘经理对案例研究的需求,你作为候选人就会知道在这个过程中应该关注什么才能留下好印象。

为案例研究提供案例

让我们从招聘公司的角度来看看申请过程的目的:他们通常在业务中有一个问题或一系列问题,他们希望有人为他们解决,他们试图找出是否能做到这一点。在真正雇用你做这项工作之前,没有确定的方法来发现这一点。那么他们能做的下一件最好的事情是什么呢?是的,你已经猜到了:他们只是要求你在案例研究中解决他们的问题(也经常被称为技术评估、带回家的评估、技术作业等)。)

你可能会想,这看起来很卑鄙。我难道不是在无偿地把我的时间贡献给解决问题的人,而他们的员工却得到了报酬吗?即使这是真的,它仍然是你在申请过程中遇到的最好的事情

如果案例研究确实反映了公司的实际工作情况,那么这就是对你被聘用后将要处理的问题和数据的最佳洞察。通常,还会有一个后续面试,在面试中,你会与公司的数据科学家讨论你的解决方案,你会听到他们如何推理问题和解决方案空间。这很好,因为你还可以获得额外的好处,了解他们在给定问题上的进展。

不要忘记:采访可以是数据科学家之间关于一个有趣问题的愉快对话。

为什么这对你如此重要?申请过程还应该帮助你弄清楚你是否想为这家公司工作,以及他们的挑战是否让你感兴趣。特别是当你已经有了一些工作经验和/或你已经想好你下一个角色到底想要什么的时候,公司的成熟程度可能是你做决定的一个重要信息。是的,我是说你也应该评估你的面试官,注意他们告诉你的关于他们将如何处理这个问题的信息。

斯科特·格雷厄姆Unsplash 上拍照

尽量减少招聘的痛苦

雇佣擅长他们工作的人是昂贵的。但是雇佣一个工作很糟糕的人会更加昂贵。问问那些曾经招错人并需要采取一些激烈行动的人,这个过程有多困难和伤脑筋。更不用说一个糟糕的雇佣对团队的影响了。想想你过去的一次糟糕的合作,现在想象你必须在接下来的两年里日复一日地和这个人一起工作。现在想象一下团队中有几个人和你有同样的感受。这对团队士气有什么影响?

因此,作为一名招聘经理,我的目标是最大限度地减少为我的团队雇佣不合适员工的可能性。

如果我把这作为一个目标,我们可以开始反向工作:为了最小化风险,我需要知道什么(以及在面试过程中我可以合理地发现什么)?在我需要在面试过程中发现的事情中,哪些是我可以通过案例研究更自然地检查的?除了在面试中问一些直接的问题之外,候选人的工作样本是否能告诉我更多的东西?

根据这一推理,我提出了招聘经理通常试图通过案例研究回答的三个问题。回答这些问题可以让他们建立一个候选人的心智模型,以及他们是否适合这个角色。当你作为候选人处理案例研究时,让这些问题引导你的注意力。如果你在那里留下了印象,你知道它会被注意到。

Q1:你能在多大程度上运用你的思维和工具来解决我们的业务问题?

虽然从理论上来说,尝试雇佣一个和我之前招聘的人做完全相同工作的人可能是有意义的,但实际上这可能更困难(候选人范围小,留住这个员工可能很困难,因为他们很容易厌倦)。因此,招聘经理通常需要扩大他们的候选人库,他们需要评估那些经验可能与工作要求没有多大关系的候选人。因此,一个全面的招聘经理会尝试创建一个流程,为他们提供几种方法来考察候选人是否符合工作(技能)要求。这就是案例研究要做的事情(以及其他事情)。

如果你面试的是不同行业或领域的职位,不要低估你作为“新人”的价值。我敢从典型的数据科学团队的多样性中推断,大多数数据科学技能是可以跨行业转移的。当然,无论何时你做了一个转换,你都需要从头开始学习很多领域知识。但是你在一份工作/行业中掌握的分析和建模工具在另一份工作/行业中仍然有用。事实上,它们甚至可能是更大的资产,因为现有团队中没有人尝试过您的工具集来解决这个问题。您只需要找出您的工具可能如何应用,以及它们在新设置中的局限性。

Unsplash 上的谷仓图片拍摄

作为招聘经理,我收到的最好、最全面的申请之一来自一名社会心理学毕业生。让我们叫她简吧。

在案例研究的数据集中,我们包括了一个可以考虑用作标签的特征,以便从问题陈述中制定监督学习任务。但是如果你仔细观察,你会发现这个特征包含了太多的缺失值,更糟糕的是,这个特征的存在是有偏差的。因此,如果你只是训练一个模型来预测这一特征,你会训练一个有偏见的模型。

Jane 通过自己的研究对我们的业务领域有了足够好的了解,并意识到数据中的偏差可能是一个问题。因此,她测试了这一特征与数据集中其他一些特征的相互影响。通过这样做,她可以自信地得出结论,事实上存在偏见。所以她决定不把它作为标签。

虽然 Jane 没有典型的数据科学经验,但她在过去的学术经历中分析了大量的实验数据。她知道可以用什么工具从未知的数据集中梳理出信息,以及如何从中得出结论。通过熟悉我们的产品,她也可以提出合理的假设进行测试。最终,Jane 实际上实现了一个非常接近我们当时自己的解决方案的解决方案,使用了一种无人监管的技术。不用说,我们向她发出了邀请。

像简那样做。

在你想出解决问题的合适方法之前,做好你的功课。如果你的功课做得很好,你也很容易掌握自己的结果,并解释为什么选择你的方法(见下面的 Q3)。

Q2:在不完全信息下你会怎么做?

你很少(我敢说:从来没有)会收到一个案例研究,它对问题和需要做的事情有一个完整的说明。当然,这有一个很好的理由:在现实世界中,手头的问题也很少(同样,可能从来没有)有一个完整的规范。通常,您的工作是确定缺少哪些信息,设计一个如何积极填补这些知识缺口的计划,或者至少是如何管理知识缺口带来的不确定性。这通常也需要你优先考虑在哪里深入挖掘,哪些空白要略过(暂时)。

Rory bjrkman 在 Unsplash 上拍摄的照片

有一次,我作为候选人参加了一个案例研究,我被告知要设计一个“数据科学解决方案”来“优化[…]运营”。这确实是我得到的指示。没有提示“数据科学解决方案”是什么意思。没有提示优化需要什么。甚至没有任何关于当前流程如何运作的细节。完全自由。

在这些情况下,我建议你反过来思考:谁是系统的用户,成功对他们意味着什么?我们如何在一个或几个 KPI 中正式确定这个成功标准?一旦我们知道了我们要优化的 KPI,头脑风暴一下我们如何从现在的位置到达那里?哦,我们不知道我们现在在哪里?让我们做一些研究,然后做出一些有根据的猜测。一旦我们有了关于成功的想法,让我们也考虑一下风险,或者最坏的情况。是被某个 KPI 俘获的吗?我们能做些什么来减轻它?

这些问题中的每一个都可能需要一些研究、一些思考和一些假设。这没关系,因为在工作中,这个过程看起来很相似。你可能需要浏览大量的内部文档,采访产品所有者/利益相关者,或者参考外部资源来找到答案。

对于案例研究来说,你不会得到每一个正确的假设或结论,但这也不是期望。相反,你的面试官希望看到你能提出一个解决未知问题的计划,同时合理安排优先级。也许在后续的面试中他们会纠正你的一些假设。做好接受挑战的准备,并根据新信息调整您的解决方案。这也是为什么做你的家庭作业(见上一节,Q1)可以帮助你在讨论中站起来思考。

Q3:你将如何与团队合作?

我有时从数据科学家那里听到的一个问题是,他们应该在案例研究提交中对代码质量给予多少关注。好吧,好的代码质量有什么帮助呢?

这是关于团队中的其他人是否能理解你的代码,与你合作编写你的代码,并在你度假时维护你的代码。所以问问你自己,别人第一次看到你的代码能很容易理解吗?他们能在不发疯的情况下工作吗?如果你不能回答这些问题,以代理人的身份问自己:我能在 3 个月或 1 年后理解这些代码,并在不憎恨过去的自己的情况下进行工作吗?

马库斯·温克勒在 Unsplash 上的照片

更根本的是,这是一个合作的问题:团队中的人会喜欢和你一起工作吗?他们会理解并信任你的工作吗?他们能在你的工作(和你在他们的工作)上有所建树吗?

理解和信任将取决于另一项与合作相关的重要技能(如果不是也是最重要的),招聘经理将通过案例研究(以及整个过程)检查这项技能。是沟通

对于大多数案例研究来说,没有一个唯一正确的解决方案,所以解释你所采用的方法及其背后的原因是很重要的。您可以很容易地想象数据科学家必须向团队成员传达他们的工作或者向利益相关者证明这一点的工作情况。尤其是后者,如果你展示出某种讲故事的技巧,你可能会更有效,也就是说,你的作品以一种引人注目且易于理解的方式传达了一个清晰的信息(例如,通过可视化、例证等)。).

因此,请仔细阅读案例研究演示是为谁准备的,并根据这些观众量身定制您的演示。什么是正确的抽象层次?需要时,您是否准备好提供您的解决方案和数据的更多细节? 4 你能解释一下你的解决方案的局限性和利弊吗?您的解决方案是否提出了明确的行动要点/关键要点?你甚至可以用解决方案的未来愿景来激励你的观众吗?

不要错误地认为仅仅建立一个无法解释的具有高精确度的模型就足够了。不要低估协作技能的重要性。

结论

在这篇文章中,我试图说服你,数据科学案例研究为候选人提供了一个了解公司和角色的机会。我还分享了招聘经理对案例研究的一些常见期望,并为应聘者提供了一些建议。我希望这些建议能帮助你决定下一个案例研究的重点。

然而,可能总会有一些只有你申请的工作才有的更具体的要求。试着把自己放在招聘经理的位置上!如果你觉得你不能,因为你缺乏关于招聘经理期望的信息,也许这是一个要求和招聘经理聊天的好时机,以便更好地了解他们。

祝你好运!

本文首发于 https://mins.space

熊猫大师在 5 分钟内绘制、应用和应用地图

原文:https://towardsdatascience.com/master-pandas-map-apply-and-applymap-in-5-minutes-d2bd1bba12a5?source=collection_archive---------35-----------------------

如何以及何时使用这些功能

熊猫图书馆有两种主要的数据结构:数据帧和序列。有许多内置函数可以创建、操作和分析这些结构。

杰斯·贝利Unsplash 上拍摄

在这篇文章中,我们将掌握一组用于操作数据帧和序列的 Pandas 函数。这些功能是映射应用应用映射

在某些情况下,熊猫提供了更好的选择来代替地图、应用和应用地图。我们还将尝试涵盖这些选项。

让我们从定义开始:

  • 映射:映射(即更新、更改、修改)系列的值。
  • 应用:沿数据帧的轴应用函数。
  • Applymap:对 DataFrame 元素应用函数。

需要注意的是,在某些情况下,这些函数会执行相同的操作并返回相同的输出。我们将看到这些案例以及有差异的案例。

一个主要的区别是这些函数作用于不同的对象。Applymap 处理数据帧,而 map 处理序列。两者都适用。

我将首先创建一个简单的数据框架来做例子。

import pandas as pd
import numpy as npdf = pd.DataFrame(np.random.randint(10, size=(5,5)), columns=list('ABCDE'))df

假设我们有一个计算给定值平均值的函数。如果我们使用“apply”将此函数应用于数据帧,它将返回行或列的平均值。

def calculate_average(row_col):
    return row_col.mean()

该功能沿轴(行或列)应用。Pandas 提供了在数据帧上执行简单统计操作的功能。在这种情况下,这些功能优先于应用功能。

例如,我们可以用df.mean(axis=0)计算每一列的平均值,用df.mean(axis=1)计算每一行的平均值。然而,了解一下 apply 函数也无妨。

Applymap 和 map 处理单个元素,而不是沿着轴。要了解 map 和 applymap 的区别,让我们做一个非常简单的数学运算。

Applymap 可应用于整个数据帧:

使用 map 函数可以将此函数应用于行或列。因此,映射功能不能应用于整个数据帧。

简单的数学运算可以作为矢量化运算来完成,它具有单纯形语法,比 map 或 applymap 更快。

地图功能也是如此:

除了函数之外,映射还采用字典或序列来映射值。

让我们向数据框架添加两个新列:

df['F'] = ['Abc','Dbc','Fcd','Afc','Kcd']
df['G'] = ['A',np.nan,'B1','B1','C']df

我们希望将 G 列中的值“B1”更改为“B”。

如您所见,其他值被映射为 NaN,这是标准的缺失值表示。我们还需要指定应该映射到哪些其他值。

在这种情况下,还必须指定其他值使得 map 函数不是最佳选择。熊猫的替换功能在这里是比较好的选择。

我们还可以使用 map 和 apply 返回基于现有值的列表:

每个项目都是一个列表,包含转换为小写字母的原始字符串和字符串的长度。

这些函数以迭代的方式工作,这使得它们相对较慢。在许多情况下,矢量化运算或列表理解比使用 map 或 applymap 更受欢迎。

这是一个列表理解、for 循环、map 函数对 50000 个元素求平方的比较。

也有一些情况下,地图功能优于列表理解。列表理解将整个输出列表加载到内存中。这对于小型或中型的列表来说是可以接受的,甚至是可取的,因为它使操作更快。然而,当我们处理大型列表(例如 10 亿个元素)时,应该避免理解列表。这可能会导致您的计算机崩溃,由于内存需求的极端数额。映射功能也不会导致内存问题。

天下没有免费的午餐!map 函数不会导致内存问题,但是它们比 list comprehensions 要慢一些。同样,列表理解的速度来自于内存的过度使用。您可以根据您的应用决定使用哪一种。

感谢您的阅读。如果您有任何反馈,请告诉我。

每天 10 分钟掌握 Python

原文:https://towardsdatascience.com/master-python-in-10-minutes-a-day-ac32996b5ded?source=collection_archive---------42-----------------------

由作者创建的图像—使用上节课中代码的证书。

让您开始使用 Python 的完整课程

这是一个系列的 10 分钟 Python 短文,帮助你开始学习 Python。总共有 25 个讲座,从最基础的开始,到更复杂的习语。如有疑问,请随时通过 LinkedIn 联系我。

这是一种学习指南,旨在通过所有的讲座创建一个计划。讲座本身可以在 10 分钟内读完,但是做一些动手实践也很重要。根据讲座本身和你以前的经验,这些也需要一点时间。虽然在一天之内做很多讲座很有诱惑力,但我认为最好是每天都做。根据我的经验,这有助于更好地处理每个部分。我也认为每个人都应该有一个周末,所以一周只有五天。当然,没有人阻止你一天做不止一个。

https://python-10-minutes-a-day.rocks/

Python 每日 10 分钟进度跟踪器的屏幕截图-图片由作者提供。

为了让体验尽可能顺利,我创建了一个在线进度跟踪器。进度追踪器会显示你的进度和还剩多少课。它还包含所有中型职位的链接,并包括 Jupyter 笔记本版本的链接。虽然两个版本包含相同的信息,但使用中型文章的布局和体验更好。进度跟踪器的好处是,正如它的名字所揭示的,你可以跟踪你的进度。当你写完一篇文章时,点击复选框把已完成的讲稿划掉。进度存储在本地 cookie 中,下次您访问该网站时,会恢复当前进度。只要确保你保留了 cookie,也就是说,在你的浏览器中关闭该网站的 cookie 自动删除插件。虽然它主要是一个静态网站,但我仍然使用 Python 来创建它(为了好玩)。包括 Dockerfile 文件在内的完整网络应用发布在我的 Github 上。

第一周

第一周,我们已经打破了每天一节课的规则,至少如果你还不知道如何组织虚拟环境的话。尽管如此,我认为有一个固定的方法来组织虚拟环境是非常重要的,因为它们可能会变得混乱。前五堂课解释了 Python 是什么以及如何使用它。我们谈论评论,并解释为什么它不无聊,但几乎至关重要。最后两节课讲的是数值变量和字符串。绝对是有趣的一周!

讲座: 0。环境,康达,匹普,啊啊啊!
1。Python、IPython、Jupyter lab 是什么?2。使用 Jupyter Lab 和导航笔记本
3。注释 Python 忽略的对你有用!4
4。数值变量以及如何给它们赋值
5。使用字符串表示文本

第二周

在第一周,我们建立了一个基础,并尝试了一些变量。本周,我们将介绍条件句、循环和函数,并做一些真正的编程。您还将学习最通用的数据结构之一:列表。在本周末,你可以使用所有这些概念来编写你的第一个解决方案:快速排序算法。

讲座:
6。Python 中的条件句:if、elif、else 结构
7。Python 中最全能的数据类型:list
8。在 Python 中循环:一会儿9。定义函数并停止重复自己
10。测试你的新技能:编写一个快速排序算法

第三周

在第三周,我们将从一些中间概念开始,比如 Try/Except,我们将学习三种新的数据结构:字典、元组和集合。一个非常常见的任务是处理文件和文件系统。本周,我们将看到解决这些问题的几种方法。

讲座:
11。用 Python 读写文件
12。尝试,除了,最后,和上下文管理器
13。字典—键值存储
14。元组和集合
15。在 Python 中使用文件和路径

第四周

本周,我们将深入了解 Python 的导入系统是如何工作的,以及模块、包、库和框架之间的区别。我们还介绍了一些高级的酷东西,如列表理解和生成器。看了一些错误,还有一个排序算法赋值。大好玩!

讲座:
16。导入、模块、包、库和框架
17。列出理解和地图:一条神奇的捷径。关于生成器以及如何创建它们的更多信息。读取 Python 中的错误和异常
20。让我们把排序排序

最后一周

这已经是最后一周了。这里我们讨论一些不太常见但绝对有用的概念:lambda 函数和 decorators。直到现在,我们只做函数式编程。面向对象编程是解决编码问题的另一种方式。有两个讲座是关于 Python 如何处理这种编程范式的。最后一堂课,我们将生成我们的证书。如果你喜欢这个课程,请在你的 LinkedIn 上分享,并给我贴上标签。有了这个,我就知道谁能坚持到最后了。当然,我会祝贺你的成就!

讲座:
21。无名函数又名λ函数22。在 Python 中,我们修饰函数以使它们更好。全新的编程类
24。父母、子女和遗产
25。实至名归的自创证书

大家都想要的实至名归的自生超级正统证书!—产生于上节课。

最后的想法

在上一讲中,我们讨论了数据科学职业生涯的下一步,当你掌握了 Python 之后,一定要阅读这一部分。我们已经讨论了所有引入的 Python 概念,我相信你能处理任何关于 Python 的问题(也许通过一些额外的搜索)。

本课程到此结束。如果你喜欢这门课程,如果你在 LinkedIn 上分享来之不易的自我生成的证书,并把我和它一起标记出来,我会非常高兴。这让我知道是谁真正上了这门课,当然,我会祝贺你取得的成就。

本课程到此结束。如果你喜欢这门课程,如果你在 LinkedIn 上分享来之不易的自我生成的证书,并把我和它一起标记出来,我会非常高兴。这让我知道是谁真正上了这门课,当然,我会祝贺你取得的成就。

一切顺利,一如既往,如果您有任何问题、评论或要求,请随时在 LinkedIn 上联系我

掌握 Python 中支线剧情的艺术

原文:https://towardsdatascience.com/master-the-art-of-subplots-in-python-45f7884f3d2e?source=collection_archive---------12-----------------------

照片由 Pietro MattiaUnsplash 上拍摄

了解可视化大数据的六种独特方式

通常,在处理数据时,无论大小,有时您都希望并排比较事物,或者分别绘制不同的属性或特征。在这种情况下,一个数字是不够的。因此,你需要知道 处理支线剧情 的艺术。

本文将重点介绍支线剧情的概念。它会教你 使用 Matplotlib 在 Python 中创建非常简单和非常复杂的网格的六种独特方式** 。

“每一次失败都有另一种选择。你只需要找到它。遇到路障时,绕道而行”——玫琳·凯·艾施

方式一:使用支线剧情( )

绘制单行或单列

让我们首先导入一些基本模块,并使用一个花哨的样式表来给我们的人物添加艺术感。

%matplotlib inline # To enable inline plotting in Jupyter Notebookimport numpy as np
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight') # For better style

让我们定义一些数据来绘图。我们用我们不朽的正弦和余弦曲线来描述 3𝜋).的𝑥∈(0

x = np.linspace(0., 3*np.pi, 100) # 0 to 3*Pi in 100 stepsy_1 = np.sin(x) 
y_2 = np.cos(x)

现在让我们用一行两列来创建我们最初的两个支线剧情。由于axes对象包含两个子情节,您可以使用索引[0]和[1]来访问它们,因为在 Python 中索引是从 0 开始的。

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(9, 3))axes[0].plot(x, y_1, '-', c='orange', label='sin(x)')
axes[1].plot(x, y_2, '-', c='magenta', label='cos(x)')axes[0].legend(fontsize=16, frameon=False)
axes[1].legend(fontsize=16, frameon=False)fig.suptitle('Subplots without shared y-axis')

使用“支线剧情()”模块创建的支线剧情

注意:如果你不喜欢指数符号,你也可以使用如下所示的轴名,然后直接使用它们绘图。下面的元组(ax1, ax2)表示各个支线剧情的轴句柄。由于以上两个支线剧情有相同的 y 轴限制,你可以使用关键字sharey=True从右侧支线剧情中移除多余的 y 轴值。

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3), sharey=True)ax1.plot(...)
ax2.plot(...)

跨越多行的支线剧情:上图中,支线剧情以柱状方式绘制。要将它们绘制成两行,可以使用nrows=2, ncols=1。现在你必须使用关键字sharex

绘制多行和多列

当你有超过 1 行和 1 列时,你需要两个索引来访问单独的支线剧情,如下面的代码所示。索引从 0 开始。因此,对于 2 行 2 列,索引将是 0 和 1。切片符号[i,j]中的第一和第二索引分别对应于行(I)和列(j)的编号。

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(9, 5),
                         sharey='row', sharex='row')axes[0, 0].plot(x+1, y_1+1, '-', c='orange')
axes[0, 1].plot(x, y_2, '-', c='magenta')
axes[1, 0].plot(x, y_1**2, '--', c='orange')
axes[1, 1].plot(x, y_2**2, '--', c='magenta')axes[0, 0].set_ylabel(r'sin(x)')
axes[0, 1].set_ylabel(r'cos(x)')
axes[1, 0].set_ylabel(r'sin$^2$(x)')
axes[1, 1].set_ylabel(r'cos$^2$(x)')fig.tight_layout()

使用 subplots()模块绘制的包含 2 行 2 列的图形。

在上图中,您可以选择如何共享 xy 轴。我选择了sharex='col'sharey='row',这意味着x-轴跨每列共享,而y-轴跨每行共享。请注意上图中不同的轴限制,以便理解这一点。

如前所述,您还可以使用元组来命名轴,避免使用索引符号。第一个元组(ax1, ax2)对应第一行支线剧情。同样,(ax3, ax4)对应于第二行。

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(9, 5))

方式二:使用支线剧情( )

在这种方法中,首先创建人物对象,然后手动一个接一个地添加支线剧情。下面的示例创建一个 2 x 2 的网格。如果你想让多个支线剧情共享同一个 xy- 轴,你可以在创建支线剧情时指定相应的轴,如下所示。

注:此处,从 1 开始编号。因此,对于一个 2×2 的网格,上面一行将使用数字(2, 2, 1)(2, 2, 2),第二行将分别使用数字(2, 2, 3)(2, 2, 4)。前两个索引分别是总行数和总列数,而第三个数字指定子情节。

fig = plt.figure(figsize=(8, 6))ax1 = plt.subplot(2, 2, 1, frameon=True) 
ax1.plot(x+1, y_1+1)
ax1.set_title('ax1')ax2 = plt.subplot(2, 2, 2, sharex=ax1, facecolor='orange')
ax2.plot(x, y_2, '-r')
ax2.set_title('Shares x-axis with ax1')ax3 = plt.subplot(2, 2, 3, sharey=ax1)
ax3.plot(x, y_1**2, '-g')
ax3.set_title('Shares y-axis with ax1')ax4 = plt.subplot(2, 2, 4, facecolor='orchid')
ax4.plot(x, y_2**2, '-b')fig.tight_layout()

包含使用 subplot()模块创建的 2x2 子情节的图形。

方式 3:使用 subplot2grid()

这种方法对于生成复杂网格很有用,其中子情节跨越多行或多列。在这里,您可以在整个网格中的指定位置创建支线剧情。

您必须首先指定整体网格大小,如下面示例代码中的(3, 3)。然后,使用索引元组指定子情节的开始位置,索引元组的顺序为(行,列),其中索引从 0 开始。因此,对于一个 3 x 3 的网格,行和列的索引都是 0、1 和 2。如果您希望一个子情节跨越多行或多列,您可以使用关键字rowspancolspan指定跨度的长度。

def add_title(axes):
    for i, ax in enumerate(axes):
        ax.set_title("ax%d" % (i+1), fontsize=18)fig = plt.figure(figsize=(8, 8))ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=2)
ax2 = plt.subplot2grid((3, 3), (0, 2), rowspan=3)
ax3 = plt.subplot2grid((3, 3), (1, 0), rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 1))
ax5 = plt.subplot2grid((3, 3), (2, 1))add_title(fig.axes)

使用 subplot2grid()模块生成的复杂的子情节网格。

方式 4:使用 gridspec。GridSpec()

这种方法对于生成复杂网格也很有用。要使用这种方法,您需要对 NumPy 数组的切片和索引符号有一个基本的了解。

例如,切片[0, :]表示第一行(索引 0)和所有列(:表示全部),切片[1, :-1]表示第二行(索引 1)和除最后一列以外的所有列(:-1 表示除最后一列以外的所有列)。

import matplotlib.gridspec as gridspecfig = plt.figure(constrained_layout=True, figsize=(8, 8))
spec = gridspec.GridSpec(ncols=3, nrows=3, figure=fig)ax1 = fig.add_subplot(spec[0, :])
ax2 = fig.add_subplot(spec[1, :-1])
ax3 = fig.add_subplot(spec[1, -1])
ax4 = fig.add_subplot(spec[2, 1:])
ax5 = fig.add_subplot(spec[2, 0])# Now you can plot individually as ax1.plot(), ax2.plot() etc.

使用 gridspec 生成的复杂的子情节网格。Gridspec()模块。

方式 5:使用 add_gridspec( ) —仅限 Matplotlib 3+

该方法与方式 3 非常相似,并且使用与上述相同的索引符号。该功能仅在 Matplotlib 3+版本中可用。

fig = plt.figure(constrained_layout=True, figsize=(8, 8))spec = fig.add_gridspec(3, 3)ax1 = fig.add_subplot(spec[0, :-1])
ax1.set_title('ax1')ax2 = fig.add_subplot(spec[:, -1])
ax2.set_title('ax2')ax3 = fig.add_subplot(spec[1:, 0])
ax3.set_title('ax3')ax4 = fig.add_subplot(spec[1, 1])
ax4.set_title('ax4')ax5 = fig.add_subplot(spec[-1, 1])
ax5.set_title('ax5')

使用 add_gridspec()模块生成的复杂的子情节网格。

方式 6:使用 subplot_mosaic( ) —仅限 Matplotlib 3.3

这是仅在 Matplotlib 3.3 中可用的最新方法

最新版本的 Matplotlib 3.3 引入了一个新的、不太冗长的和一个 语义的方式 来生成复杂的子情节网格。经由subplot_mosaic()。你也可以随意命名你的支线剧情。您也可以使用简写 ASCII 符号重新创建下图。

最酷的地方在于 ,要生成下图所示的支线剧情网格,可以通过以列表的形式布局。缺失的支线剧情被标示为'.'。为了让一个支线剧情跨越两列,你可以重复名字,就像我对'bar'做的那样。要跨越多行(垂直),请在第二个列表中垂直重复下面的名称。你也可以使用名字'bar''hist''scatter'使用字典来控制/修改相应支线剧情的属性。

axes = plt.figure(constrained_layout=True).subplot_mosaic(
                [['.', 'bar', 'bar'], # Note repitition of 'bar'
                 ['hist', '.', 'scatter']])for k, ax in axes.items():
    ax.text(0.5, 0.5, k, ha='center', va='center', 
            fontsize=36, color='magenta')# Using dictionary to change subplot properties
axes['bar'].set_title('A bar plot', fontsize=24)    
axes['hist'].set_title('A histogram', fontsize=24)    
axes['scatter'].set_title('A scatter plot', fontsize=24)

使用 subplot_mosaic()生成的支线剧情。请注意跨越两列的扩展“条”。

这就是我这篇文章的结尾。如果你有兴趣了解更多关于 Matplotlib 的最新特性,可以参考我下面的文章。

[## Matplotlib 的最新酷功能

立即将您的 Matplotlib 升级至最新版本 3.3

towardsdatascience.com](/latest-cool-features-of-matplotlib-c7a1e2c060c1) [## Matplotlib 3 的新特性

第 3 代中最重要的更新概述

towardsdatascience.com](/whats-new-in-matplotlib-3-1b3b03f18ddc)

掌握用于语义图像分割的 COCO 数据集—第 1 部分,共 2 部分

原文:https://towardsdatascience.com/master-the-coco-dataset-for-semantic-image-segmentation-part-1-of-2-732712631047?source=collection_archive---------1-----------------------

在这个由两部分组成的演练中,我们将使用 PyCoco 和 Tensorflow Keras 等库来探索和操作 COCO(上下文中的公共对象)图像数据集,以便在 Python 中进行语义图像分割。

你是说可可吗?(原图由来自派克斯伊兰尼特·科彭斯拍摄)

COCO(上下文中的常见对象),是最受欢迎的图像数据集之一,具有对象检测、分割和字幕等应用程序——令人惊讶的是,几乎没有全面而简单的端到端教程。当我第一次开始使用这个数据集时,我感到非常失落和害怕。我不得不费力地通过网上这么多分散的、不充分的资源、多个模糊的教程和一些实验,最终在这条隧道的尽头看到光明。当我完成后,我知道我必须记录下这段旅程,从开始到结束。于是我照做了。希望有一天,有人会发现这些有价值的东西,而不必经历我所面临的所有麻烦。

这是一个由两部分组成的系列教程,旨在帮助您探索、使用和掌握用于图像分割的 COCO 图像数据集。我会尽量保持简单,为每一步提供解释,并且只使用免费的、简单的库。我在这里的工作是让你熟悉和熟悉这个话题,达到一个水平,在这个水平上 你可以占据中心位置,并根据你的需要操纵它!

在第 1 部分中,我们将首先使用一个名为 pycoco 的 python 库来探索和操作用于图像分割的 COCO 数据集。这个库简化了 COCO 数据集的处理,否则自己编写代码会非常困难。

第 2 部分中,我们将使用 Tsensor flow Keras库来简化该数据集上的训练模型,并添加图像增强。

你可以在我的 GitHub 库中找到本教程的完整代码。然而,请继续阅读这篇文章以获得更详细的解释。

1.COCO 数据集

" COCO 是一个大规模的对象检测、分割和字幕数据集."

COCO 数据集

上下文中的常见对象(COCO)字面上意味着数据集中的图像是从日常场景中捕获的日常对象。这为场景中捕捉的对象添加了一些“上下文”。在这里探索这个数据集

数据集中的示例图像。

COCO 提供多对象标记、分割遮罩注释、图像字幕、关键点检测和全景分割注释,共有 81 个类别,使其成为一个非常通用和多用途的数据集。

在本演练中,我们将重点关注数据集的语义分段应用。

2.下载和安装

椰子树

您需要将 COCO 数据集下载到您的设备上(很明显)。您可以使用以下链接下载 2017 年数据集文件。这些文件非常大,所以请耐心等待,因为这可能需要一些时间。您需要的文件有:

(一) 2017 年列车图像

(b) 2017 val 图像

(c) 2017 Stuff Train/Val 注释

提取压缩文件。从(c)中,只需要 train 和 val 的实例文件,即实例 _train2017.json实例 _val2017.json.

按照下面给出的文件结构排列这些文件。需要对文件夹和文件进行一些简单的重新排列和重新命名。我这样做只是为了便于使用和可视化,如果你不想这样做,你需要做的就是相应地更改代码(主要是文件路径)。

Project Folder
└───the code notebook (.py / .ipynb)
│
└───COCOdataset2017   
    └───images
    │   └───train
    │   │    │   000000000009.jpg
    │   │    │   000000000025.jpg
    │   │    │   ...
    │   └───val   
    │        │   000000000139.jpg
    │        │   000000000285.jpg
    │        │   ...
    └───annotations
        │   instances_train.json
        │   instances_val.json

#请注意,有一种方法可以访问图像及其 URL(从注释文件中),只需要下载(c)。然而,在一个漫长的训练过程中,如果你不依赖互联网会更好,因此我建议你也下载(a)和(b)。

PyCoco

接下来,让我们安装我们的主要库, pycoco 。我特别说明了这个过程,因为如果你按照你的标准过程,你会在安装和导入过程中面临许多错误。

Conda 中,如果你按照下面的步骤操作,你应该可以相当流畅地安装、导入和使用这个库。

其他人

让我们导入我们将在本教程中使用的所有库。其他库的安装非常简单,所以我不会在这里提及细节。在 python 环境中安装所有的库。

3.使用 PyCoco 探索数据集

首先,让我们初始化 PyCoco 库。这个库接受 COCO 注释(。json)文件(我们在步骤 2 中下载的文件)作为输入。train 或 val 实例注释都可以,但对于本教程,我使用“instances_val.json ”,因为它加载速度更快(原因:val 数据集比 train 数据集小)。

输出(即类别)打印如下:

[{'supercategory': 'person', 'id': 1, 'name': 'person'},
 {'supercategory': 'vehicle', 'id': 2, 'name': 'bicycle'},
 {'supercategory': 'vehicle', 'id': 3, 'name': 'car'},
 {'supercategory': 'vehicle', 'id': 4, 'name': 'motorcycle'},
 {'supercategory': 'vehicle', 'id': 5, 'name': 'airplane'},
 {'supercategory': 'vehicle', 'id': 6, 'name': 'bus'},
 {'supercategory': 'vehicle', 'id': 7, 'name': 'train'},
 {'supercategory': 'vehicle', 'id': 8, 'name': 'truck'},
 {'supercategory': 'vehicle', 'id': 9, 'name': 'boat'},
 {'supercategory': 'outdoor', 'id': 10, 'name': 'traffic light'},
 {'supercategory': 'outdoor', 'id': 11, 'name': 'fire hydrant'},
 {'supercategory': 'outdoor', 'id': 13, 'name': 'stop sign'},
 {'supercategory': 'outdoor', 'id': 14, 'name': 'parking meter'},
 {'supercategory': 'outdoor', 'id': 15, 'name': 'bench'},
 {'supercategory': 'animal', 'id': 16, 'name': 'bird'},
 {'supercategory': 'animal', 'id': 17, 'name': 'cat'},
 {'supercategory': 'animal', 'id': 18, 'name': 'dog'},
 {'supercategory': 'animal', 'id': 19, 'name': 'horse'},
 {'supercategory': 'animal', 'id': 20, 'name': 'sheep'},
 {'supercategory': 'animal', 'id': 21, 'name': 'cow'},
 {'supercategory': 'animal', 'id': 22, 'name': 'elephant'},
 {'supercategory': 'animal', 'id': 23, 'name': 'bear'},
 {'supercategory': 'animal', 'id': 24, 'name': 'zebra'},
 {'supercategory': 'animal', 'id': 25, 'name': 'giraffe'},
 {'supercategory': 'accessory', 'id': 27, 'name': 'backpack'},
 {'supercategory': 'accessory', 'id': 28, 'name': 'umbrella'},
 {'supercategory': 'accessory', 'id': 31, 'name': 'handbag'},
 {'supercategory': 'accessory', 'id': 32, 'name': 'tie'},
 {'supercategory': 'accessory', 'id': 33, 'name': 'suitcase'},
 {'supercategory': 'sports', 'id': 34, 'name': 'frisbee'},
 {'supercategory': 'sports', 'id': 35, 'name': 'skis'},
 {'supercategory': 'sports', 'id': 36, 'name': 'snowboard'},
 {'supercategory': 'sports', 'id': 37, 'name': 'sports ball'},
 {'supercategory': 'sports', 'id': 38, 'name': 'kite'},
 {'supercategory': 'sports', 'id': 39, 'name': 'baseball bat'},
 {'supercategory': 'sports', 'id': 40, 'name': 'baseball glove'},
 {'supercategory': 'sports', 'id': 41, 'name': 'skateboard'},
 {'supercategory': 'sports', 'id': 42, 'name': 'surfboard'},
 {'supercategory': 'sports', 'id': 43, 'name': 'tennis racket'},
 {'supercategory': 'kitchen', 'id': 44, 'name': 'bottle'},
 {'supercategory': 'kitchen', 'id': 46, 'name': 'wine glass'},
 {'supercategory': 'kitchen', 'id': 47, 'name': 'cup'},
 {'supercategory': 'kitchen', 'id': 48, 'name': 'fork'},
 {'supercategory': 'kitchen', 'id': 49, 'name': 'knife'},
 {'supercategory': 'kitchen', 'id': 50, 'name': 'spoon'},
 {'supercategory': 'kitchen', 'id': 51, 'name': 'bowl'},
 {'supercategory': 'food', 'id': 52, 'name': 'banana'},
 {'supercategory': 'food', 'id': 53, 'name': 'apple'},
 {'supercategory': 'food', 'id': 54, 'name': 'sandwich'},
 {'supercategory': 'food', 'id': 55, 'name': 'orange'},
 {'supercategory': 'food', 'id': 56, 'name': 'broccoli'},
 {'supercategory': 'food', 'id': 57, 'name': 'carrot'},
 {'supercategory': 'food', 'id': 58, 'name': 'hot dog'},
 {'supercategory': 'food', 'id': 59, 'name': 'pizza'},
 {'supercategory': 'food', 'id': 60, 'name': 'donut'},
 {'supercategory': 'food', 'id': 61, 'name': 'cake'},
 {'supercategory': 'furniture', 'id': 62, 'name': 'chair'},
 {'supercategory': 'furniture', 'id': 63, 'name': 'couch'},
 {'supercategory': 'furniture', 'id': 64, 'name': 'potted plant'},
 {'supercategory': 'furniture', 'id': 65, 'name': 'bed'},
 {'supercategory': 'furniture', 'id': 67, 'name': 'dining table'},
 {'supercategory': 'furniture', 'id': 70, 'name': 'toilet'},
 {'supercategory': 'electronic', 'id': 72, 'name': 'tv'},
 {'supercategory': 'electronic', 'id': 73, 'name': 'laptop'},
 {'supercategory': 'electronic', 'id': 74, 'name': 'mouse'},
 {'supercategory': 'electronic', 'id': 75, 'name': 'remote'},
 {'supercategory': 'electronic', 'id': 76, 'name': 'keyboard'},
 {'supercategory': 'electronic', 'id': 77, 'name': 'cell phone'},
 {'supercategory': 'appliance', 'id': 78, 'name': 'microwave'},
 {'supercategory': 'appliance', 'id': 79, 'name': 'oven'},
 {'supercategory': 'appliance', 'id': 80, 'name': 'toaster'},
 {'supercategory': 'appliance', 'id': 81, 'name': 'sink'},
 {'supercategory': 'appliance', 'id': 82, 'name': 'refrigerator'},
 {'supercategory': 'indoor', 'id': 84, 'name': 'book'},
 {'supercategory': 'indoor', 'id': 85, 'name': 'clock'},
 {'supercategory': 'indoor', 'id': 86, 'name': 'vase'},
 {'supercategory': 'indoor', 'id': 87, 'name': 'scissors'},
 {'supercategory': 'indoor', 'id': 88, 'name': 'teddy bear'},
 {'supercategory': 'indoor', 'id': 89, 'name': 'hair drier'},
 {'supercategory': 'indoor', 'id': 90, 'name': 'toothbrush'}]

COCO 数据集有 81 个对象类别(注意‘id’:0 是背景),正如我们上面打印出来的一样(这里还列出了)。然而,正如您所观察到的,这 81 个类的标签 id 范围从 0 到 90(中间有一些空的 id 号)。这是一个方便的函数,它可以获取给定 id 号的类名。

这将给出一个输出:

The class name is cell phone

类别过滤

假设我想要只包含“笔记本电脑”、“电视”和“手机”类的图像,而不需要任何其他对象类。要获取数据集的这个子集,请执行以下步骤:

现在, imgIDs 变量包含了包含所有 filterClasses 的所有图像。print 语句的输出是:

Number of images containing all the classes: 11

这意味着,在整个验证数据集中,有 11 个图像包含了我想要的全部 3 个类。显示的示例图像是:

包含过滤后的输出类的示例图像。

为了显示注释,我们应该遵循下面的代码。请注意,我们使用 pycoco 功能"loadAnns"加载 coco 格式的关于对象的注释,并使用"showAnns在图像上绘制这些注释。这些函数极大地简化了注释遮罩的绘制。您可以查看链接的函数定义,了解它们在内部是如何工作的。

过滤后的类的注释简洁明了。

所有可能的组合

当我们用类过滤数据集时,pycoco 工具返回的图像只包含所有需要的类,而不是一两个或任何其他组合。因此,这段代码将确保在结果数据集中获得给定的 filterClass 列表的所有可能组合。

print 语句的输出是:

Number of images containing the filter classes: 503

看上面,我们只收到了 11 张图片,但是现在有 503 张图片!我们也避免了图像的重复。

4.图像分割掩模生成

对于任何语义分割训练任务,您都需要一个装满图像(train 和 val)和相应的输出真实遮罩的文件夹。本节将帮助创建相应的图像遮罩。

屏蔽类型 1:正常语义分段屏蔽

每个像素根据其所属的类别都有一个标签。我没有使用官方的 COCO ids,而是按照数组' filterClasses '中类名的顺序分配像素值,即:
0:背景
1:笔记本电脑
2:电视
3:手机

输出是一个 2 通道语义分割蒙版,其尺寸等于原始图像,如下所示:

用于语义分割的普通双通道掩码。

掩码类型 2:二元语义分段掩码

一般来说,对于 N 个输出类,你的输出遮罩将有 N 个可能的像素值。然而,二进制掩码意味着输出掩码将只有 2 个像素值,即 1 (对象:可以是 N 个类中的任何一个)和 0 (背景)。

输出是一个 2 通道二元语义分割蒙版,其尺寸等于原始图像,如下所示:

二元语义分割掩码。黄色代表像素值 1,紫色代表像素值 0。

N 例如,您可能希望标签 id 号与原始 COCO 数据集中的相同(0–90)。或者你可能想要一个实例分割用例的输出格式。另一个例子是,您可能希望您的遮罩是一个热编码,即通道数=输出对象类的数量,并且每个通道只有 0(背景)和 1(该对象)。

无论如何,相应地修改上面的代码,你就可以得到你想要的遮罩。如果将来我有时间,我也会尝试为这些额外的类型添加代码。

接下来,我们接着看 第二部分

** [## 掌握用于语义图像分割的 COCO 数据集

创建一个数据生成器,并在 COCO 图像数据集上训练您的模型,以便使用 PyCoco 进行语义图像分割…

towardsdatascience.com](/master-the-coco-dataset-for-semantic-image-segmentation-part-2-of-2-c0d1f593096a)

同样,本教程的代码在我的 GitHub 库中。

我的朋友们,今天到此为止!如果您已经走了这么远,我希望您已经对 COCO 数据集有了一些信心。 但不要止步于此——走出去,尝试一下这个地狱,用你的新想法震撼图像分割的世界!**

如果您喜欢这篇文章,那么下一篇文章将向您展示如何用最少的努力轻松地倍增您的图像数据集。一定要读一读!

** [## 创建一个合成图像数据集——“是什么”、“为什么”和“如何”

缺少图像来训练你的模型?以下是如何使用合成图像将数据集的大小增加数倍…

towardsdatascience.com](/create-a-synthetic-image-dataset-the-what-the-why-and-the-how-f820e6b6f718)

或者想在股票中利用 ML 一夜暴富?这篇文章(不)适合你!

[## 如何(不)用 LSTMs 预测股票价格

股票和机器学习——天作之合。但是事情真的像看起来那么简单吗?

towardsdatascience.com](/how-not-to-predict-stock-prices-with-lstms-a51f564ccbca)

ML 模型真的能读懂股价图吗?

[## 机器学习模型可以阅读股票图表并预测价格吗?

股票和机器学习——天作之合。如果你的 ML 模型可以从字面上阅读价格图表…

towardsdatascience.com](/can-an-ml-model-read-stock-charts-and-predict-prices-fb73c551c7a4)**

掌握用于语义图像分割的 COCO 数据集—第 2 部分,共 2 部分

原文:https://towardsdatascience.com/master-the-coco-dataset-for-semantic-image-segmentation-part-2-of-2-c0d1f593096a?source=collection_archive---------8-----------------------

在这两部分演练的最后一部分,我们将使用 COCO(上下文中的公共对象)图像数据集创建一个带有图像增强的数据生成器,用于 Python 中的语义图像分割,库包括 PyCoco 和 Tensorflow Keras。

你去椰子了吗?!(原图由 Craig Adderley 发自 Pexels

[## 掌握用于语义图像分割的 COCO 数据集

使用 PyCoco、Tensorflow Keras Python…探索和操作 COCO 图像数据集进行语义图像分割

towardsdatascience.com](/master-the-coco-dataset-for-semantic-image-segmentation-part-1-of-2-732712631047)

对于新读者,你可以在这里 找到本系列 的第 1 部分。我强烈建议通读一下,以便更好地理解下面的文章。

COCO(上下文中的常见对象),是最受欢迎的图像数据集之一,具有对象检测、分割和字幕等应用程序——令人惊讶的是,几乎没有全面而简单的端到端教程。当我第一次开始使用这个数据集时,我感到非常失落和害怕。我不得不费力地通过网上这么多分散的、不充分的资源、多个模糊的教程和一些实验,最终在这条隧道的尽头看到光明。当我完成后,我知道我必须记录下这段旅程,从开始到结束。于是我照做了。希望有一天,有人会发现这些有价值的东西,而不必经历我所面临的所有麻烦。

这是一个由两部分组成的系列教程,旨在帮助您探索、使用和掌握用于图像分割的 COCO 图像数据集。我会尽量保持简单,为每一步提供解释,并且只使用免费的、简单的库。我在这里的工作是让你熟悉和熟悉这个话题,达到一个你可以占据中心位置并根据你的需要操纵它的水平。

第 1 部分中,我们用一个叫做 pycoco 的 python 库探索了用于图像分割的 COCO 数据集。

在第 2 部分中,我们将使用 T ensorflow Keras 库来简化这个数据集上的训练模型,并添加图像增强。我们走吧!

你可以在我的 GitHub 库中找到本教程的完整代码。然而,请继续阅读这篇文章以获得更详细的解释。

1.创建数据生成器

现在,我们将结合第 1 部分中讨论的所有概念来创建一个数据生成器,您可以使用它来训练任何细分模型。下面的函数是独立函数,不需要第 1 部分中的任何变量。项目的文件夹结构如第 1 部分所示。为了更清楚地理解这些函数运行背后的概念,我推荐快速阅读第 1 部分

下面提到的导入与第 1 部分中的相同。

(a)图像过滤

该函数接受 3 个输入—
(a) 文件夹:包含 COCO 数据集
(b) :无或包含所需输出类
(c) 模式的列表对象:“train”或“val”

该函数首先加载并初始化 pycoco 对象[第 3–4 行]。然后,获取所有可能的“类别”组合[第 6-13 行]。如果没有给定过滤器类,它将加载整个数据集[第 15–18 行]。由于一些图像可能包含两个或更多的输出类,在我们的图像变量中可能会有重复的图像。因此[第 19–23 行]我们遍历它并过滤掉唯一的图像。最后,我们打乱唯一的图像列表,并将其与其他一些有用的数据一起返回。

现在我们的函数已经定义好了,让我们调用并初始化它。

【注意 :对于本教程,我将使用mode = ' val ',但是当使用它来训练模型时,为' val '和' train '分别调用这些函数来创建两个生成器对象。

我已经提到了 3 种期望的输出类别(笔记本电脑、电视、手机)。该函数过滤 COCO 数据集以返回仅包含一个或多个这些输出类的图像。

该函数返回—
(a):包含所有过滤后的图像对象的列表(唯一)
(b) dataset_size :生成的过滤数据集的大小
(c) coco :初始化的 coco 对象

您可以打印出这些输出,以便更好地理解它们。

(b)生成图像和遮罩

我们已经准备好了过滤后的数据集,让我们创建一个生成器对象来批量生成图像和蒙版。

【注: 为了便于查看,这里我没有包括子功能的代码。完整代码可以查看我的 GitHub 库

函数 dataGeneratorCoco 接受 8 个输入—
(a) 图像:由 filterDataset 函数
(b) 返回的图像列表:过滤器类列表与 filterDataset 函数
(c) Coco 的输入相同:由 filterDataset 函数
返回的 coco 对象 input_image_size :你的模型的输入图像的大小,如(宽度,高度)
(f) batch_size :批处理大小
(g)mode:‘train’或‘val’与 filterDataset 函数
(h)mask _ type:‘binary’或‘normal’(类不能是 None)

该功能执行批量循环[第 20~行]并从文件夹中检索图像,加载带有过滤输出(二进制或正常分段屏蔽)的屏蔽,最后将它们集中起来形成图像批次和屏蔽批次。yield 语句[第 41 行]负责创建一个生成器类型的对象。

现在我们的函数已经定义好了,让我们调用并初始化它。

该函数创建一个数据生成器对象,生成批量图像和二进制掩码。既然我们的生成器终于准备好了,让我们定义一个函数来可视化它。

****visualizeGenerator(val_gen)****

mask_type='binary '的生成器生成的图像的可视化。

mask_type='normal '的生成器生成的图像的可视化。

2.添加扩充

如果您遵循前面的步骤,COCO 数据生成器已经准备好了!您可以使用它来按原样训练您的模型,但是如果您希望向影像中添加数据增强以增加潜在的数据集大小,请遵循最后一步!

这里我们将使用 Tensorflow Keras 的图像生成器添加图像增强。

增强生成器*函数接受 3 个输入-
(a) gen :您希望添加增强的生成器对象
(b)
augmentorargs
:增强参数(参见前面的代码示例)
(c) seed :用于生成随机增强参数或不生成增强参数的种子
***

要定义增强的参数,请遵循以下格式。您可以为您的用例试验这些值。关于参数的更多细节,你可以查看关于这个主题的 keras 文档

该函数的输出是一个数据生成器对象,产生批量的增强图像和相应的增强二进制掩码。可视化增强的数据生成器,注意你现在可以看到旋转,亮度变化,反射等。

****visualizeGenerator(aug_gen)****

mask_type='binary '的增强生成器生成的图像的可视化。

mask_type='normal '的增强生成器生成的图像的可视化。

3.最后…训练一个模型

现在发电机准备好了,我们能用它做什么呢?以下代码是如何在培训中使用这些 COCO 数据集生成器的快速模板。

TIP:你可以单独创建一个。py 文件(比如 cocoFunctions.py ),并复制 imports、filterDataset 函数和 dataGeneratorCoco +支持函数的代码。这将有助于使代码更加系统化。**

然后,您可以使用:
from coco functions import filter dataset,dataGeneratorCoco
将函数导入到任何代码中

****-> Create filtered train dataset (using filterDataset()) 
-> Create filtered val dataset (using filterDataset())-> Create train generator (using dataGeneratorCoco()) 
-> Create train generator (using dataGeneratorCoco())# Set your parameters
n_epochs = <number of epochs of training>steps_per_epoch = dataset_size_train // batch_size
validation_steps = dataset_size_val // batch_sizem = <your model>
opt = <your optimizer>
lossFn = <your loss function># Compile your model first
m.compile(loss = lossFn, optimizer = opt, metrics=['accuracy'])# Start the training process
history = m.fit(x = train_gen_aug,
                validation_data = val_gen_aug,
                steps_per_epoch = steps_per_epoch,
                validation_steps = validation_steps,
                epochs = n_epochs,
                verbose = True)****

这是解决问题的一种方法。你打算用这个新发现的技能做什么?

同样,本教程的完整代码可以在我的 GitHub 库中找到。

好了,我们完成了!我希望您现在已经对 COCO 数据集有了一定的掌握和信心。但是不要止步于此——走出去,尝试一下,用你的新想法震撼图像分割的世界!

我的下一篇文章将教你如何轻松地倍增你的图像数据集。一定要读一读!

**** [## 创建一个合成图像数据集——“什么”、“为什么”和“如何”

缺少图像来训练你的模型?以下是如何使用合成图像将数据集的大小增加数倍…

towardsdatascience.com](/create-a-synthetic-image-dataset-the-what-the-why-and-the-how-f820e6b6f718)

或者想在股票中利用 ML 一夜暴富?这篇文章(不)适合你!

[## 如何(不)用 LSTMs 预测股票价格

股票和机器学习——天作之合。但是事情真的像看起来那么简单吗?

towardsdatascience.com](/how-not-to-predict-stock-prices-with-lstms-a51f564ccbca)

ML 模型真的能读懂股价图吗?

[## 机器学习模型可以阅读股票图表并预测价格吗?

股票和机器学习——天作之合。如果你的 ML 模型可以从字面上阅读价格图表…

towardsdatascience.com](/can-an-ml-model-read-stock-charts-and-predict-prices-fb73c551c7a4)****

掌握 DS/ML 中最讨厌的任务

原文:https://towardsdatascience.com/master-the-most-hated-task-in-ds-ml-3b9779276d7c?source=collection_archive---------16-----------------------

用熊猫清理数据

用熊猫清理分类数据

照片由 Pixabay 像素

介绍

直接来自福布斯:

“数据科学家花 60%的时间清理和组织数据。收集数据集排在第二位,占他们时间的 19%,这意味着数据科学家花费大约 80%的时间来准备和管理用于分析的数据。57%的数据科学家认为清理和组织数据是他们工作中最不愉快的部分,19%的人认为收集数据集是如此。

数据清理充满了挫折,令人厌恶的惊喜需要几个小时来处理,总是有新数据集的新问题,你能想到的都有。这个过程从来都不是令人愉快的,并且总是被认为是数据科学肮脏的一面。

尽管它经常被讨厌,但它可能是任何数据项目之前最重要的一步。如果没有正确解决数据问题,您可能会危及数据科学工作流程中的所有其他阶段。

在我的数据清理系列的第二部分中没有太多介绍,让我们直奔主题。这篇文章是关于分类数据清理的。我将讨论处理一些中级分类数据问题的常见和不常见的方法。以下是总体概述:

可点击的目录(仅限网络)

简介
设置
分类数据,了解并举例
处理分类数据问题
成员约束
值不一致
将数据折叠成类别
减少类别数量

你可以在这个 GitHub repo 上获得本帖使用的笔记本和数据。

设置

分类数据——理解和示例

分类数据的正式定义是:

一组预定义的可能的类别或组。

您可以在几乎所有处理过的数据集中看到分类数据的例子。几乎任何类型的数据都可以转化为分类数据。例如:

  • 调查反馈:
  • YesNo
  • malefemale
  • employedunemployed
  • 数字数据:
  • 分组年收入:0-40k40-100k,...
  • 年龄:儿童,青少年,成人…

当我们使用panads库学习数据清理时,理解pandas永远不会将分类数据作为分类导入是很重要的。它通常以字符串或整数的形式导入:

您可以看到cutcolorclarity是作为字符串而不是类别导入的。我们可以像这样使用read_csvdtype参数:

你可以通过这个链接从 Kaggle 下载这个版本的“钻石”数据集。

但是对于真实世界的数据集,您通常没有这种奢侈,因为您将要处理的数据可能会有许多分类变量,并且通常您一开始会对这些数据完全不熟悉。

在确定分类变量之后,在将列转换为分类变量之前,需要进行一些检查和清理。

处理分类数据问题

当您处理真实世界的数据时,它将充满清理问题。

正如我在本系列的第一部分中所写的,收集数据的人不会考虑数据的干净程度,尽可能以简单的方式记录必要的信息。

此外,由于收集过程中的自由文本会导致输入错误、相同值的多个表示等,因此会出现问题。也有可能是因为数据解析错误或糟糕的数据库设计而引入错误。

例如,考虑这种最坏的情况:您正在处理一个在美国进行的调查数据,数据集中的每个观察状态都有一个state列。美国有 50 个州,想象一下人们能想出的各种州名。如果数据收集者决定使用缩写,你的问题就更大了:

  • 加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚,加利福尼亚…

这样的栏目总是充满了错别字、错误和不一致。永远不要想象你会有一个平滑的一对一的类别映射。

在继续分析之前,您必须建立所谓的成员约束,它清楚地定义了类别的数量以及它们如何以单一格式表示。

成员限制

有三种方法可以处理分类数据问题:

  • 落下
  • 重新映射类别
  • 推断类别

首先,我们将集中于隔离不一致的观察值并丢弃它们。我创建了假数据来说明代码是如何实现的:

您可以看到我写的简短脚本,它从我在文章开头分享的 GitHub repo 中生成这个数据集

通常情况下,您会有一些关于您的数据的背景信息。例如,假设您想要检查上述数据框的blood_type列中的不一致。你事先发现blood_type只能有这几类:【A+,A-,B+,B-,O+,O-,AB+,A B-】。因此,您必须确保数据源中的列只包含这些值。

在我们的例子中,有 10k 行,视觉搜索不一致是不可行的,这也是许多其他真实数据的情况。以下是如何实现此类问题的最佳解决方案:

首先,您应该创建一个新的数据框来保存分类列的所有可能值:

PRO 提示: 创建这样的数据框是一个很好的实践,它保存主数据中每个分类列的类别映射。

由于我们现在在一个单独的数据框中有了正确的类别,我们可以使用一个基本的集合操作,它给出了两列中唯一值的差异:

为了得到两个集合之间的差异,我们使用.difference函数。它基本上返回左集中不在右集中的所有值。这里有一个非常简单的例子:

细心的读者可能已经注意到,在set函数内部,我还在blood_type上调用了.unique()。从我从一个 StackOverflow 线程中读到的内容来看,如果对较大的数据集同时使用setunique,获取唯一值所需的时间似乎会短得多。

现在,我们将筛选血型“C+”和“D-”的主要数据:

blood_type上使用isin将返回一个布尔序列,我们可以用它来索引数据帧:

90 行 x 6 列。不知何故 x 变成了俄语в🤷‍♂️

所以,有 90 个人血型不正确。因为我们不知道这些错误是如何发生的(我做到了😁😁😁),我们不得不放弃他们。有两种方法可以做到:

因为我们的列现在是干净的,所以可以安全地将其设置为分类变量:

一定要看看这个系列的第一部。在那里,我讨论了基本和常见的数据问题。您还将熟悉我将在这里使用的一些功能。

[## 掌握 DS/ML 中最耗时的任务,#1

处理常见的数据问题

towardsdatascience.com](/data-type-constraints-data-range-constraints-duplicate-data-with-pandas-44897a350b1e)

价值不一致

就像我们在第二节中谈到的,在数据集中可能有许多相同类别的表示。这些错误可能仅仅是因为简单的错别字、随意的大写字母,等等。继续清理我们的数据,轮到了marriage_status列:

对数据框列使用value_counts会返回该列中唯一值的计数。如果您查看结果,您可以立即看到问题。这些值应该是小写或大写。我更喜欢小写:

对数据框列使用.str使我们能够对列的每个值使用所有 Python 字符串函数。这里,我们使用.lower()将字符串转换成小写。

value_counts仍在返回 6 个唯一值,为什么?仔细观察后,您会发现其中一个类别有额外的前导空格。这就是为什么它被视为一个单独的类别。对于其中一个unmarried也是如此,它可能有尾随空格。我们可以使用 string strip函数来去除字符串中的尾随空格:

现在柱子干净了。剩下要做的就是将该列转换成 category 数据类型:

将数据分类

有时,您可能想要获取已经存在的数据,通常是数字数据,并从中生成类别。这在许多情况下是有用的。

在我们的demographics数据集中,我们有一个年收入列。将这一栏分成不同的收入组可能是有用的,因为这样做可能会对数据提供一些额外的见解。

pandas对此有一个完美的函数:cut。它使我们能够将数字范围(如数据框列)切割成箱,并给它们定制标签。让我们来看看它的实际应用:

现在,我们可以使用像value_counts这样的函数来获得更多的洞察力:

您也可以绘制计数图:

这是随机生成的数据,这就是为什么酒吧的高度几乎相同。

减少类别的数量

有时,可能会有不必要的类别。在这种情况下,您可以将较小的类别折叠成更大的类别,这样可能更适合您的需要。考虑我们数据的device栏:

把手机的操作系统和电脑的相比没有多大用处。更好的做法是将类别减少为mobileOSdesktopOS。为此,首先,我们需要创建一个字典,将每个类别映射到新的类别:

然后,我们使用pandasreplace函数,它动态地映射出新的类别:

如果你喜欢这篇文章,请分享并留下反馈。作为一名作家,你的支持对我来说意味着一切!

阅读更多与主题相关的文章:

[## 认识熊猫最难的功能,第一部分

掌握 pivot_table()、stack()、unstack()的时机和方式

towardsdatascience.com](/meet-the-hardest-functions-of-pandas-part-i-7d1f74597e92) [## 认识熊猫最难的功能,第二部分

掌握交叉表的时间和方式()

towardsdatascience.com](/meet-the-hardest-functions-of-pandas-part-ii-f8029a2b0c9b) [## 认识熊猫最难的功能,第三部分

形状像果冻的桌子有熊猫旋转()和融化()

towardsdatascience.com](/shape-tables-like-jelly-with-pandas-melt-and-pivot-f2e13e666d6) [## 我习惯如何将数据与熊猫绑定

您可能只使用了默认值

towardsdatascience.com](/how-i-customarily-bin-data-with-pandas-9303c9e4d946) [## 掌握 DS/ML 中最耗时的任务,#1

处理常见的数据问题

towardsdatascience.com](/data-type-constraints-data-range-constraints-duplicate-data-with-pandas-44897a350b1e) [## 来自 Kagglers:DS 和 ML 的最佳项目设置

来自顶级 Kagglers 的项目成功最佳实践的集合

towardsdatascience.com](/from-kagglers-best-project-setup-for-ds-and-ml-ffb253485f98)

在 Tableau 中掌握您的瀑布图

原文:https://towardsdatascience.com/master-your-waterfall-chart-in-tableau-acea2121e98c?source=collection_archive---------22-----------------------

关于如何在 Tableau 上创建具有高级功能的精彩瀑布图的完整教程(带有商业分析中的示例)

戴夫·霍夫勒在 Unsplash 上拍摄的照片

瀑布图是商业演示中非常常用的一种图表类型(有时也称为累积图或缩减图)。在许多不同的情况下,它们被用来把一些分析变量分解成不同的成分。

以下是一些例子:

将净收入分成几个部分;

了解从 6 月到 12 月每个月的销售额。

然而,瀑布图并不是一件容易的事情,甚至 Office Suite 直到 2016 版都没有瀑布图(你必须使用一些变通方法或使用第三方插件,如智库)。

甚至 Tableau 也没有对瀑布图的本地支持,您必须使用一些变通方法。

基本瀑布

对于第一个例子,我将使用我的 Github 帐户上的文件netbankiningincome . CSV

要构建一个基本的瀑布图,您需要遵循以下步骤:

  1. 在视图中添加一个维度(列)和一个度量(行)。维度应包含您希望将测量拆分成的组件

作者图片

2.单击测量,然后选择快速表格计算和累计

作者图片

作者图片

3.诀窍来了。选择甘特条形图作为标记(您在 Tableau 中使用过甘特吗?真的吗?)和“甘特图大小”使用一个新的计算字段:相同的测量,但符号相反

作者图片

作者图片

作者图片

4.将总计加到右边

作者图片

作者图片

分组组件

有时您需要将组件分组并显示小计。

按照本教程第一部分中的示例,我们有商业银行净银行收入的 5 个最重要的组成部分:

  • 资产利息;
  • 负债利息;
  • 股权分红;
  • 费用和准备金;
  • 交易收入。

在银行部门损益表的常见重新分类中,前两者被归为一类,总影响被称为“净利息收入”,而其他三者通常被归为“非利息收入”。

作者图片

在列中添加新的分组维度(在组件之前)。你甚至创造了一个等级制度。

作者图片

您希望添加到图表中的另一个有用的东西是区分积极和消极影响的条件格式。这很简单。只需添加一个带有度量符号的计算字段,并将其添加到“颜色”中。

作者图片

作者图片

按颜色拆分条形图

有时,您希望将组件拆分成两个维度:也许您希望用两种或更多种颜色划分每个条形,而不在 x 轴上创建另一个组件。

对于这张图表,我想使用另一个数据集,它是关于银行业的另一个重要话题:流动性

银行在经济体系中的角色是在谁拥有过剩的流动性并希望从中获得资金(投资者)和谁的业务需要流动性(借款者)之间充当中间人。银行本身需要流动性,需要优化流动性的规模(相对于更有利可图的投资,持有流动性可能是一种成本)。

流动性的一个典型来源是客户支票账户或发行债券。但银行也可以收回短期流动性贷款,即它们拥有的一些资产(通常是债券或贷款,但也包括股权)。这可以通过市场对手方(通过回购协议的其他银行)或央行来完成。

在这种情况下,跟踪您的资产(已经抵押或可用)的状态是有用的,以避免将同一资产出借两次,以及您的流动性的潜在来源(市场或中央银行)。因此,有两个维度和一个衡量标准(资产的流动性价值)。

让我们看看如何在这个数据库中实现它。你看,这种类型可以假定两个值:总资产或担保资产。因为可用资产可以计算为总资产和抵押资产之间的差额,所以让我们试着得到一个“逐步减少”的图表。

作者图片

第一步与前面的步骤相同(请记住,要将总资产排在担保资产之前)。

作者图片

然后尽量把出处用彩色。你会发现你得到的结果并不是你所期望的:总资产从 90 变成了 60。此外,可用资产比我们预期的要少。

作者图片

这取决于这样一个事实,即运行总和是按类型分组获得的,现在您还使用了另一个级别的详细信息(源),您会看到市场和中央银行在同一个条形图中重叠。所以我们需要“编辑表格计算”,选择使用“特定维度”进行计算并添加来源。

作者图片

另一个有用的细节是标签。在标签上加上尺寸,你会得到这样的东西。

作者图片

它只显示顶部标签:默认情况下不显示重叠标签。您需要选择“始终显示”并垂直居中。

作者图片

作者图片

总结

瀑布图是一种很好的方式来表示商业分析中常用的度量的组成部分。

使用 Tableau“GANTT ”,您只需点击几下就可以轻松获得一个完美的瀑布,利用您在本教程中学到的知识,您可以超越商业分析中最常用工具的通常功能。

掌握连接:Pandas merge()、concat()、append()

原文:https://towardsdatascience.com/masteriadsf-246b4c16daaf?source=collection_archive---------16-----------------------

通过熊猫连接数据

从半连接/反连接到验证数据合并

图片来自 Pixabay丹尼尔·克什

对于每个数据科学项目或数据集,您需要执行多项分析,并创建绘图以获得真知灼见。通常,原始数据不会出现在一个巨大的表中,而是出现在许多单独的表中。要回答您的问题,您应该掌握将多个表连接成一个表,然后对它们执行操作的技能。

您可以通过学习不同种类的合并操作来获得这些技能,例如内部连接、左右连接、自连接和反连接、索引合并等。

本文中使用的样本数据和笔记本可以在 this GitHub repo 中找到。

[## 通过我的推荐链接加入 Medium-BEXGBoost

获得独家访问我的所有⚡premium⚡内容和所有媒体没有限制。支持我的工作,给我买一个…

ibexorigin.medium.com](https://ibexorigin.medium.com/membership)

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

[## 阿尔法信号|机器学习的极品。艾总结的。

留在循环中,不用花无数时间浏览下一个突破;我们的算法识别…

alphasignal.ai](https://alphasignal.ai/?referrer=Bex)

设置

熊猫合并()

Pandas 提供了几种在数据帧上执行合并的方法。在所有其他方法中,merge()方法是最灵活的。它是一个 dataframe 方法,一般语法如下:

df1.merge(df2, on='common_column')

当组合表格时,有两个术语您应该熟悉:您首先使用的表格的名称称为左表、,而另一个称为右表。在上面的代码片段中,左边的表是df1,右边的表是df2。此外,动词 join、combine 和 merge 都可以互换使用。

现在让我们看看如何执行内部连接:

内部联接将只返回两个表中具有匹配值的行。在连接过程中,您必须知道两个表中的公共列名。

图片作者作者

基础探索

假设我们有两张表:

>>> user_usage.head()

>>> user_devices.head()

我从 KillBiller 应用程序下载了这些数据。KillBiller 是一项免费服务,可以比较英国和爱尔兰的所有移动资费。第一个user_usage表包含用户移动使用的月度统计数据。user_devices表提供了每个用户手机的详细信息,如操作系统和手机型号。

问题 1:

有多少用户使用 Android OS,又有多少用户使用 iOS?

要回答这个问题,我们需要两个表中的信息。两个表之间有一个链接属性:use_id。我们将在合并中使用此列:

Number of users for each OS: android    157
                             ios          2
Name: platform, dtype: int64

在我们的数据集中,这两个操作系统之间存在巨大的差异。

在上面的合并中,我们使用了一个内部连接的例子。在merge()函数中,how参数默认设置为inner,所以我们没有必要把它写出来。当使用merge()函数合并两个表时,我们使用on参数来指定公共列。如果有多个,也可以将一列列表传递给参数,剩下的由pandas处理。

注意,作为右表,我对user_devices表进行了子集化,以排除与问题无关的列。

现在,随着我们进一步探索,我们会注意到两个数据集中给定用户的数量是不同的:

两个表中匹配的用户 id 的数量都是 159。这意味着有用户 id 在user_devices表中而不在user_usage表中,反之亦然。所以,我们想问的下一个问题是:

问题 2

有多少用户使用 Android OS 和 iOS,包括所有不在user_usage表中的用户?

我们可以用左连接或右连接来回答这个问题。首先,让我们看看单侧连接的一般情况:

图片作者作者

一个左连接将返回所有的左表行,包括右表中的匹配行。一个右连接将返回所有的右表行,包括来自左表的匹配行。注意,在这两种类型的连接中,pandas将把一个NaN值放入没有匹配的单元格中。

Number of users for each OS: android    184
                             ios         88
Name: platform, dtype: int64

使用左连接可以获得相同的结果。我们可以交换这些表,并将关键字left传递给参数how:

Number of users for each OS: android    184
                             ios         88
Name: platform, dtype: int64

我们使用外部连接返回交集和两个表中的所有其他行:

图片作者作者

熊猫合并(),后缀

假设我们在两个表中都有相同名称的列。因为在我们的例子中,我们没有同名的列,所以我将把一列复制到另一列中:

现在我们在两个表中都有了monthly_mb列。让我们看看当我们加入他们时会发生什么:

如果我们查看列名,两个同名的列通过添加_x_y后缀进行了重命名。这里,_x为左表,_y为右表。这是我们不指定后缀时的默认行为。我们可以很容易地控制后缀:

现在好多了。当它们具有相同的名称时,使用这样的后缀来指示列的来源表。注意,suffixes参数接受一个值的元组,而不是一个列表,并且顺序很重要!

熊猫合并(),左 _ 开,右 _ 开

还有一种情况是,您希望在一个公共列上进行联接,但是这些列有不同的名称。pandas为这样做提供了一个方便的参数,不需要改变列名。让我们重命名use_id列,这样我可以向您展示一个例子。

现在,让我们用一个inner连接来组合这些表:

我们使用 merge 函数的left_onright_on参数来指定公共列的名称。您应该将左表中的列名传递给left_on,反之亦然。注意,当我们使用不同命名的公共列时,pandas会将两个列都作为副本,所以不要忘记删除其中一个:

熊猫合并索引

也可以在一个公共索引上进行合并。任何使用索引的连接类型的语法都是相同的。pandas足够聪明,知道你指的是指数:

当我们有不同名称的索引时,事情会变得有点棘手。与列类似,我们将不得不使用left_onright_on参数。此外,还有两个参数表明我们正在合并一个索引:

我们将left_indexright_index设置为True,以表示我们正在合并索引。这也给出了重复的值:一个作为索引,一个作为列。因此,在合并时不要忘记删除列!

如果您要合并的表有多级索引,那么您可以将一个索引名称列表传递给onleft/right_on参数,这样就完成了!

熊猫把桌子连在一起

在某些情况下,您可能希望将一个表连接到它自己。在下列情况下,将表与其自身联接会很有帮助:1。等级关系 2。顺序关系 3。图形数据

将表连接到自身的一般情况:

图片由作者

如您所见,自合并有时非常有用。当使用自联接时,通常会联接同一个表的不同列。

到目前为止,我们完成的所有连接都从两个表中返回了数据。但是有时,您可能希望根据其他表上的值来筛选您的表。pandas不直接提供此功能。但是我们可以很快地设计步骤。

半加盟熊猫

当您希望根据其他表中的观察值对数据进行子集划分时,半连接非常有用。半连接:

1.返回两个表的交集,类似于内部联接。

2.只返回左中的列,不返回右中的列。

3.没有重复。

回到我们的小桌子上:

图片作者作者

正如您所看到的,半连接非常类似于内部连接,但是它只包括左表中的结果。现在回到我们的示例数据,我们想知道两个表中所有用户的统计信息。但是我们不希望最终的表包含user_devices表的列。我们可以用三个步骤来解决这个问题:

有了内部连接后,我们希望用最终表中的值对原始左表进行子集化:

变量in_both现在是一个Boolean Series,我们可以用它来子集化左边的表。

>>> users_in_both.shape
(159, 4)

结果如我们所料。如果您将这个连接与我们所做的第一个inner连接进行比较,它是同一个表,但是没有右边表中的列:

>>> inner.shape
(159, 8)

这是一个棘手的案子。请多重读和练习这一节,以便更好地理解它。

反对加入的熊猫

反连接与半连接完全相反。反联接:

1.返回左表,不含交叉点

2.仅返回左表中的列。

图片由作者

作为一个例子,让我们在半连接中做与上一步完全相反的事情。让我们找出所有只在user_usage表中的用户。第一步:

现在,我给你介绍另一个有用的参数:indicator。当设置为True时,合并的结果表将有一个额外的列_merge。它指示一行是两个表的结果还是一个表的结果。如您所见,在没有匹配的行中有一个left_only字符串。现在,我们想对这些行进行子集划分:

我使用了.loc子集来立即获取用户 id。现在我们可以使用这个 pandas series来子集化原来的左表:

>>> left_only_users.shape(81, 4)

同样,这有点复杂,所以开始练习吧。

熊猫系列()

最后,我们介绍了大部分的merge函数。现在,pd.concat()用于沿特定轴连接/添加两个或多个表格。它还提供了一些操作轴的功能。该函数的一种常见用法是垂直添加表格。

数据帧的垂直连接

要垂直添加两个或更多表格,我们使用concat()方法,将axis参数设置为index

图片作者作者

让我们分三部分加载其中一个示例表:

请注意我是如何使用chunksize参数的!了解这一点很有帮助,因为它在加载大型数据集时会非常有用。

当使用concat()函数时,我们总是传递要连接在一个列表中的表。为了指定连接轴,我们使用axis参数。我强烈建议您将字符串值传递给axis参数,如indexcolumns。传递 0 或 1 可能会让很多人感到困惑。因此,提高代码可读性是一个很好的实践。

concat()功能不关注轴标签。如果您的所有表中都有编号索引,那么当您进行连接时,它们将会混合在一起。因此,解决问题的一个有用参数是ignore_index:

这将重置索引,它将从 0 计数到 n-1。

concat()的另一个用例是当你有相似的表但有不同的列名时。当连接具有不同列名的表时,使用带有合适字符串valuejoin参数。

图片由作者

使用带有inner值的concat会产生一个单列数据框架,因为它是表之间唯一的公共列。使用leftrightouter会得到预期的结果,但是值是垂直堆叠的。

熊猫追加()

.append()方法:

  1. concat()方法的简化版

2.支持:ignore_index

3.不支持:join等差异。

另一个区别是它是一个 DataFrame 方法。这意味着它是在数据帧上调用的,而不是像pd.concat那样显式调用。简单的例子:

数据映射的类型

我们在上面看到了几种类型的连接。我们明确地告诉这些方法我们希望在每个方法中使用的连接类型,并相信它会返回正确的结果。但是,有一些方法可以确保我们得到正确的结果。要用代码完成这项任务,您必须理解合并中的四种数据映射类型:

  1. 一对一

2.一对多

3.多对一

4.多对多

我们来细说一下。当我们使用一对一映射时,我们希望我们的连接应该为左侧表中的每一行返回一个且只有一个匹配。如果我们用一对一映射连接一个有 200 行的表,结果也应该包含 200 行。

类似地,如果是一对多,我们允许左侧表中的一行有多个匹配。让我们看看如何用代码实现这个想法:

merge()方法为验证这类合并提供了一个有用的参数。它只接受四个值:

  1. one_to_one

2.one_to_many

3.many_to_one

4.many_to_many

此外,如果我们验证不正确的映射,pandas将引发MergeError:

https://gist.github.com/64bb2102575ffc9edf587cebbcd59605

如您所见,合并产生了一个错误。让我们将其设置为正确的映射:

验证串联

使用.concat()方法时,也可以在轴上验证。它有verify_integrity参数,默认设置为False。设置为 True 时,如果轴或列有重复名称,将引发 ValueError:

结论

最后,我想在这篇文章中涵盖的事情结束了。我们讨论了很多连接数据的不同方法。信不信由你,这个主题还有更多的内容,比如merge_ordered()merge_asof()方法,但是它们可能是另一篇文章的主题。

这恰恰说明了pandas库的深度和广度,以及你可以用它做什么。我打算将本文作为学习组合数据的一站式平台,并希望您将在实践中使用它。

掌握 Python 中的匿名函数

原文:https://towardsdatascience.com/mastering-anonymous-functions-in-python-75bcd4332dfa?source=collection_archive---------34-----------------------

理解 Python Lambda 表达式

照片由像素上的 Pixabay 拍摄

函数定义是软件编程的重要组成部分。在 python 中,lambda 表达式可以用来匿名定义简单的函数。例如,计算乘法的函数可以替换为 lambda 表达式。在这篇文章中,我们将讨论如何使用 lambda 表达式在 python 中定义匿名函数。

假设我们有一个单行函数,它返回两个输入整数值的乘积:

def product(x, y):
    return x*y

如果我们用整数 5 和 10 调用这个函数,并打印我们得到的返回值:

print("Product:",product(5, 10))

由于这是一个简单的函数,它只对单个表达式“x*y”求值,因此可以用 lambda 表达式替换它:

product_value = lambda x, y: x*y

lambda 表达式包含关键字“lambda”、输入 x 和 y、一个冒号以及我们想要计算的表达式。如果我们回头看看我们最初的函数定义:

def product(x, y):
    return x*y

我们看到这些表达看起来非常相似。最大的区别是在我们的 lambda 表达式中没有“def”关键字、“return”关键字和函数名。

让我们用 x = 5 和 y = 10 作为输入来打印这个函数:

print("Product w/ Lambda Expression:",product_value(5,10))

lambda 表达式的另一个有趣的应用是在熊猫的数据框中。对于这个例子,我们将使用网飞、Prime Video、Hulu 和 Disney Plus 数据集上的电影,可以在这里找到

让我们将数据读入熊猫数据框:

import pandas as pd 
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
df = pd.read_csv("MoviesOnStreamingPlatforms_updated.csv")

接下来,我们将打印该数据中可用的列:

print(df.columns)

让我们删除“未修改:0”列,并打印前五行数据:

del df['Unnamed: 0’]
print(df.head())

我们可以使用“assign()”方法将 lambda 表达式应用于单个列。假设我们想创建一个新列,从“烂番茄”列的值中删除“%”符号。我们可以用 lambda 表达式来实现。我们将把我们的新专栏命名为“rt_ratings”:

df = df.assign(rt_ratings = lambda x: x['Rotten Tomatoes'].str.rstrip('%') )
print(df.head())

另一个例子是,如果我们想将“IMDb”评级四舍五入到最接近的整数。我们将我们的新列命名为“round_imdb”:

df = df.fillna(0)
df = df.assign(round_imdb = lambda x: x['IMDb'].astype(int))
print(df.head())

我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。

结论

总之,在这篇文章中,我们讨论了如何在 python 中使用 lambda 表达式定义匿名函数。首先,我们展示了如何定义一个匿名函数来返回两个整数的乘积。接下来,我们讨论了如何将 lambda 表达式应用于 Pandas 的数据框,以删除列字符串值中的字符,以及如何将浮点值四舍五入为最接近的整数。如果你有兴趣学习更多关于熊猫的数据操作、机器学习甚至只是 python 编程的一些基础知识,请查看Python for Data Science and Machine Learning:Python 编程、熊猫和 Scikit-初学者学习教程 。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

用 Python 掌握二分搜索法

原文:https://towardsdatascience.com/mastering-binary-search-in-python-e96d7a44769b?source=collection_archive---------34-----------------------

Python 中的高效搜索

Tobias Aeppli 在 Pexels 拍摄的照片

二分搜索法是一种高效的搜索算法,用于在排序列表中查找项目。该算法通过重复分割可能包含被搜索值的子列表来工作。对于大型数组,二分搜索法比线性搜索效率高得多。具体来说,二分搜索法在最坏情况下运行在对数时间, O (log n) 而线性搜索在最坏情况下运行在线性时间O(n)**。在这篇文章中,我们将讨论如何用 python 写一个二分搜索法函数。

我们开始吧!

首先,让我们定义我们的函数。我们称之为‘我的二进制搜索函数’:

def my_binary_search_function():

我们的函数将采用一个名为“input_list”的数组,一个对应于最后一个索引的“high_value”,一个对应于第一个索引的“low_value”,以及一个我们将尝试查找的值“target_value”:

def my_binary_search_function(input_list, low_value, high_value,  target_value):

接下来,我们要确保我们的输入列表实际上是一个列表:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    if type(input_list)!=type([]):
        print('Not a list!')

如果我们试图用一个不属于' list '类型的值调用我们的函数,例如我们将传入一个字符串,我们的函数将打印' Not a list!':

my_binary_search_function('this_is_a_string', 0, 10, 2)

我们需要做的下一件事是检查基本情况。具体来说,我们需要检查“高值”是否高于“低值”。然后,我们定义列表的中间索引,它将是“高值”加上“低值”的平均值的下限:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    ...
    else:
        if high_value >= low_value:
            middle **=** (high_value **+** low_value) **//** 2

如果索引“middle”处的值小于我们的函数的目标值,则递归调用“my_binary_search_function”,其中“low_value”等于“middle+1”:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    ...
            if input_list[middle] < target_value:
                return my_binary_search_function(input_list, middle +1, high_value, target_value)

如果索引' middle '处的值大于我们函数的目标值,则递归调用' my_binary_search_function ',使' high_value '等于' middle-1 ':

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    ...
            elif input_list[middle] > target_value:
                return my_binary_search_function(input_list, low_value, middle-1, target_value)

否则,返回中间值作为我们要搜索的值的索引:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    ...
            else:
                return middle 

如果元素不在列表中,我们返回-1:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    ...
        else:
            return -1

完整的功能如下:

def my_binary_search_function(input_list, low_value, high_value,  target_value):
    if type(input_list)!=type([]):
        print('Not a list!')
    else:
        if high_value >= low_value:
            middle = (high_value + low_value) // 2
            if input_list[middle] < target_value:
                return my_binary_search_function(input_list, middle +1, high_value, target_value)
            elif input_list[middle] > target_value:
                return my_binary_search_function(input_list, low_value, middle-1, target_value)
            else:
                return middle
        else:
            return -1

现在让我们测试一下我们的功能。让我们定义一个整数的排序列表:

my_list = [100, 3000, 4500, 5000, 6000, 6050, 7020, 8400, 9100]

假设我们想要搜索数字 6050:

my_value = 6050

我们可以调用我们的函数,并将返回的索引存储在一个名为“my_result”的变量中。如果返回的索引不等于-1,我们打印值存储的位置。否则,我们打印该值不在列表中:

my_result = my_binary_search_function(my_list, 0, len(my_list)-1, my_value) 

if my_result != -1: 
    print("{} is present at index".format(my_value), str(my_result)) 
else: 
    print("{} is not present in array".format(my_value))

如果我们将“my_value”更改为列表中没有的数字,如 80,我们会得到以下结果:

my_value = 80
my_result = my_binary_search_function(my_list, 0, len(my_list)-1, my_value) 

if my_result != -1: 
    print("{} is present at index".format(my_value), str(my_result)) 
else: 
    print("{} is not present in array".format(my_value))

我就讲到这里,但是您可以自己随意摆弄代码。

结论

总之,在这篇文章中,我们讨论了如何用 python 写二分搜索法函数。如果你有兴趣学习其他重要算法,我推荐 GeeksforGeeks 。我希望你觉得这篇文章有趣/有用。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

掌握 Seaborn 中的 catplot():分类数据可视化指南。

原文:https://towardsdatascience.com/mastering-catplot-in-seaborn-categorical-data-visualization-guide-abab7b2067af?source=collection_archive---------4-----------------------

如果你能在锡伯恩做到,那就在锡伯恩做吧,#2

照片由来自 Pexels安德里亚·皮亚卡迪奥拍摄

介绍

本文的目标是使用 Seaborn 的catplot()函数向您介绍最常见的分类图。

在进行探索性或解释性数据分析时,您将不得不从广泛的绘图类型中进行选择。选择一个能准确描述数据中关系的方法可能会很棘手。

如果您处理的数据涉及任何分类变量,如调查响应,那么可视化和比较数据不同特征的最佳工具就是分类图。幸运的是,数据可视化库 Seaborn 将几种类型的分类图包含在一个函数中:catplot()

与其他绘图库相比,Seaborn 库提供了许多优势:

1\. It is very easy to use and requires less code syntax

2\. Works really well with `pandas` data structures, which is just what you need as a data scientist.

3\. It is built on top of Matplotlib, another vast and deep data visualization library.

顺便说一句,我对数据可视化的黄金法则是“如果你能在 Seaborn 做,就在 Seabron 做”。

在 SB 的(以后我会简称为)文档中,陈述了[catplot()](https://seaborn.pydata.org/generated/seaborn.catplot.html)函数包括 8 种不同类型的分类图。但是在本指南中,我将介绍三种最常见的图:计数图、条形图和箱形图。

[## 通过我的推荐链接加入 Medium-BEXGBoost

获得独家访问我的所有⚡premium⚡内容和所有媒体没有限制。支持我的工作,给我买一个…

ibexorigin.medium.com](https://ibexorigin.medium.com/membership)

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

[## 阿尔法信号|机器学习的极品。艾总结的。

留在循环中,不用花无数时间浏览下一个突破;我们的算法识别…

alphasignal.ai](https://alphasignal.ai/?referrer=Bex)

概观

 I. Introduction II. SetupIII. Seaborn Count Plot
         1\. Changing the order of categories IV. Seaborn Bar Plot
         1\. Confidence intervals in a bar plot
         2\. Changing the orientation in bar plots V. Seaborn Box Plot
         1\. Overall understanding
         2\. Working with outliers
         3\. Working with whiskers VI. Conclusion

你可以在这个 GitHub repo 上获得样本数据和文章的笔记本。

设置

如果您还没有安装 SB,您可以使用pip以及我们将使用的其他库来安装它:

pip install numpy pandas seaborn matplotlib

如果你想知道为什么我们不像正常人一样将 Seaborn 别名为sb,那是因为首字母sns是以电视剧《白宫风云》中的一个虚构人物塞缪尔·诺曼·Seaborn 命名的。你能说什么?(耸耸肩)

对于数据集,我们将使用经典的diamonds数据集。它包含了 54000 颗钻石的价格和质量数据。这是一个很好的数据可视化数据集。数据的一个版本预装在 Seaborn 中。可以用sns.get_dataset_names()函数得到其他加载的数据集(有很多)。但是在本指南中,我们将使用我从 Kaggle 下载的完整版本。

# Load sample data
diamonds = pd.read_csv('data/diamonds.csv', index_col=0)

基础探索

diamonds.head()
diamonds.info()
diamonds.describe()

<class 'pandas.core.frame.DataFrame'>
Int64Index: 53940 entries, 1 to 53940
Data columns (total 10 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   carat    53940 non-null  float64
 1   cut      53940 non-null  object 
 2   color    53940 non-null  object 
 3   clarity  53940 non-null  object 
 4   depth    53940 non-null  float64
 5   table    53940 non-null  float64
 6   price    53940 non-null  int64  
 7   x        53940 non-null  float64
 8   y        53940 non-null  float64
 9   z        53940 non-null  float64
dtypes: float64(6), int64(1), object(3)
memory usage: 4.5+ MB

diamonds.shape(53940, 10)

Seaborn 计数图

顾名思义,计数图显示每个变量类别中的观察值数量。在这篇文章中,我们将使用catplot()函数改变它的kind参数来创建不同的图。对于计数图,我们将kind参数设置为count,并使用data参数输入数据。让我们从探索钻石切工质量开始。

sns.catplot(x='cut', data=diamonds, kind='count');

我们从catplot()函数开始,使用x参数来指定我们想要显示类别的轴。您可以使用y使图表水平。计数图自动计算每个类别中数值的数量,并显示在YAxis上。

更改类别的顺序

在我们的图中,切割的质量从最好到最差。但是让我们颠倒一下顺序:

category_order = ['Fair', 'Good', 'Very Good', 'Premium', 'Ideal']

sns.catplot(x='cut', data=diamonds, kind='count', order=category_order);

最好按照您想要的顺序创建一个类别列表,然后将其传递给order。这提高了代码的可读性。

Seaborn 条形图

绘制分类数据的另一个流行选择是条形图。在计数图示例中,我们的图只需要一个变量。在柱状图中,我们经常使用一个分类变量和一个定量变量。让我们看看不同钻石切割的价格如何相互比较。

为了创建条形图,我们分别输入XAxisYAxis的值,并将kind参数设置为bar:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='bar',
            order=category_order);

每个条形的高度代表每个类别中的平均值。在我们的图中,每个条形显示了每个类别中钻石的平均价格。我想你也很惊讶地看到,低质量的削减也有明显较高的价格。平均而言,质量最低的钻石甚至比理想的钻石还要贵。这一令人惊讶的趋势值得探究,但超出了本文的范围。

条形图中的置信区间

每个柱顶部的黑线代表平均值的 95%置信区间,可以认为是样本数据中的不确定性。简单地说,每条线的顶端是你期望的每个类别中所有钻石的真实平均价格的区间。如果你不懂统计学,最好跳过这一部分。您可以关闭置信区间,将ci参数设置为None:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='bar',
            order=category_order,
            ci=None);

更改条形图中的方向

当你有很多类别/条,或者很长的类别名称时,改变方向是个好主意。只需交换 x 轴和 y 轴的值:

sns.catplot(x='price',
            y='cut',
            data=diamonds,
            kind='bar',
            order=category_order,
            ci=None);

Seaborn 箱线图

箱线图是视觉效果,可能有点难以理解,但是非常漂亮地描绘了数据的分布。最好从一个箱线图的例子开始解释。我将使用 Seaborn 中常见的内置数据集之一:

tips = sns.load_dataset('tips')

sns.catplot(x='day', y='total_bill', data=tips, kind='box');

整体理解

该盒状图显示了一家样本餐厅每天的账单金额分布。让我们从解读周四的开始。

蓝框的边缘是所有钞票分布的第 25 和第 75 个百分位数。这意味着周四所有账单中有 75%低于 20 美元,而另外 75%(从底部到顶部)几乎高于 13 美元。方框中的水平线表示分布的中值。

胡须上方的点称为异常值。异常值分三步计算:

  1. 从第 75 个百分点值中减去第 25 个百分点值,得出四分位数范围(IQR):75%—25%
  2. 25 号减去 IQR 的 1.5 倍计算出异常值下限: 25% — 1.5IQR*
  3. 在第 75 位加上 IQR 的 1.5 倍计算出异常值上限: 75% + 1.5IQR*

高于和低于异常值限值的任何值都将成为方框图中的点。

现在您对盒状图有了更好的理解,让我们回到闪亮的钻石:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='box',
            order=category_order);

我们以与任何其他图相同的方式创建一个盒图。关键的区别在于我们将kind参数设置为box。这个方框图显示了不同质量切割钻石的价格分布。如您所见,每个类别都有许多异常值。而且分布是高度倾斜的。

箱形图非常有用,因为它们:

  1. 在单个图中显示异常值、偏斜度、分布和分布
  2. 非常适合比较不同的群体

箱线图中的异常值

也可以通过将sym参数设置为empty string来关闭箱线图中的异常值:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='box',
            order=category_order,
            sym='');

默认情况下,箱线图中的异常值是使用我前面介绍的方法计算的。但是,您可以通过为whis参数传递不同的值来更改它:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='box',
            order=category_order,
            whis=2);   # Using 2 times of IQR to calculate outliers

使用胡须

使用不同的百分位数:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='box',
            order=category_order,
            whis=[5, 95]); # Whiskers show 5th and 95th percentiles

或者使胡须显示最小值和最大值:

sns.catplot(x='cut',
            y='price',
            data=diamonds,
            kind='box',
            order=category_order,
            whis=[0, 100]);   # Min and max values in distribution

包扎

我们已经讨论了三种最常见的分类图。我没有包括如何使用catplot()功能创建支线剧情,尽管这是catplot()的灵活性的优势之一。我最近为一个类似的用于绘制关系变量的函数relplot()写了另一篇文章。我已经在那里详细讨论了如何创建支线剧情,同样的技巧也可以应用在这里。

[## 掌握 Seaborn 的三分之一:用 relplot()统计绘图

如果你能在锡伯恩做到,就在锡伯恩做吧

towardsdatascience.com](/master-a-third-of-seaborn-statistical-plotting-with-relplot-df8642718f0f)

看看这个关于 Matplotlib figax对象的故事:

[## 一劳永逸地澄清困惑:fig,ax = plt.subplots()

了解 Matplotlib 中的图形和轴对象

towardsdatascience.com](/clearing-the-confusion-once-and-for-all-fig-ax-plt-subplots-b122bb7783ca)

用熊猫掌握数据聚合

原文:https://towardsdatascience.com/mastering-data-aggregation-with-pandas-36d485fb613c?source=collection_archive---------35-----------------------

用熊猫聚合数据

来源

数据汇总是收集数据并以汇总形式表达的过程。这通常对应于数据集中数值和分类变量的汇总统计。在本帖中,我们将讨论如何使用 pandas 聚合数据并生成有洞察力的汇总统计数据。

我们开始吧!

出于我们的目的,我们将使用葡萄酒评论数据集,这个数据集可以在这里找到。

首先,让我们将数据读入熊猫数据框:

import pandas as pd
df = pd.read_csv("winemag-data-130k-v2.csv")

接下来,让我们打印前五行数据:

print(df.head())

使用 DESCRIBE()方法

“describe()”方法是一个基本方法,它允许我们为数据中的列提取汇总统计信息。让我们用“describe()”方法来计算葡萄酒的价格:

print(df['price'].describe())

我们看到葡萄酒价格的“计数”,即非空值的数量是 120,975。葡萄酒的平均价格是 35 美元,标准差是 41 美元。葡萄酒价格的最小值为 4 美元,最大值为 3300 美元。“describe()”方法也提供了百分位数。在这里,25%的葡萄酒价格低于 17 美元,50%低于 25 美元,75%低于 42 美元。

让我们使用“points”列上的“describe()”来查看汇总统计数据:

print(df['points'].describe())

我们看到点的非空值个数是 129971,恰好是数据帧的长度。平均点数为 88,标准偏差为 3。葡萄酒积分的最小值为 80,最大值为 100。对于百分位数,25%的葡萄酒得分低于 86,50%低于 88,75%低于 91。

使用 GROUPBY()方法

您还可以使用“groupby()”来聚合数据。例如,如果我们想要查看每种葡萄酒的平均价格,我们可以执行以下操作:

print(df['price'].groupby(df['variety']).mean().head())

我们看到“Abouriou”葡萄酒的平均价格为 35 美元,“Agiorgitiko”的平均价格为 23 美元,以此类推。我们还可以显示排序后的值:

print(df['price'].groupby(df['variety']).mean().sort_values(ascending = False).head())

让我们来看看每个“省份”的平均价格:

print(df['price'].groupby(df['province']).mean().sort_values(ascending = False).head())

我们还可以查看多个列。让我们看看各省的平均价格和积分:

print(df[['price', 'points']].groupby(df.province).mean().head())

我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。

结论

总之,在这篇文章中,我们讨论了如何使用 pandas 来聚集数据。首先,我们讨论了如何使用“describe()”方法来生成汇总统计数据,例如数据列的平均值、标准偏差、最小值、最大值和百分位数。然后,我们讨论了如何使用“groupby()”方法来生成特定分类变量的统计数据,例如每个省的平均价格和每个品种的平均价格。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

用熊猫掌握数据过滤

原文:https://towardsdatascience.com/mastering-data-filtering-with-pandas-449eb91f8890?source=collection_archive---------21-----------------------

熊猫的三个有用的数据过滤功能

肯·富田像素上拍摄的照片

Pandas 是一个 python 库,用于生成统计数据、争论数据、分析数据等等。在这篇文章中,我将讨论三个有用的函数,它们可以让我们使用 Pandas 轻松过滤数据。

我们开始吧!

出于我们的目的,我们将使用 FIFA 19 数据集,可以在这里找到

首先,让我们导入熊猫包:

import pandas as pd 

接下来,让我们将显示列和行的最大数量设置为“None”:

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

现在,让我们读入数据:

df = pd.read_csv('fifa_data.csv')

接下来,我们将打印前五行数据,以了解列类型及其值(列结果被截断):

print(df.head())

我们可以考虑的第一个功能是按类别过滤。让我们定义我们的函数‘filter _ category’。我们的函数将接受一个类别和类别值:

def filter_category(category, category_value):

我们可以使用“loc”操作符来选择类别值是我们选择的值的行:

def filter_category(category, category_value):
    df_filter = df.loc[df[category] == category_value]
    return df_filter

让我们过滤阿根廷国籍:

df_filter = filter_category('Nationality', 'Argentina')
print(df_filter.head())

我们看到“国籍”的所有值都是“阿根廷”。另一种有用的函数是按值列表过滤的函数:

def filter_category_with_list(category, category_value_list):
    df_filter = df.loc[df[category].isin(category_value_list)]
    return df_filter

我们可以筛选“国籍”为“巴西”、“西班牙”或“阿根廷”的行:

df_filter = filter_category_with_list('Nationality', ['Brazil', 'Spain', 'Argentina'])
print(df_filter.head())

我们也可以通过分类栏“俱乐部”进行过滤。让我们过滤“曼城”、“皇家马德里”和“巴塞罗那足球俱乐部”:

df_filter = filter_category_with_list('Club', [‘Manchester City’, ‘Real Madrid’, ‘FC Barcelona’])
print(df_filter.head())

我们还可以定义一个根据数值过滤的函数。该函数将能够根据输入值以及行是大于、小于还是等于输入值来筛选行:

def filter_numerical(numerical, numerical_value, relationship):
    if relationship == 'greater':
        df_filter = df.loc[df[numerical] > numerical_value]
    elif relationship == 'less':
        df_filter = df.loc[df[numerical] < numerical_value]     
    else: 
        df_filter = df.loc[df[numerical] == numerical_value]  
    return df_filter

我们可以筛选足球运动员的“年龄”大于 30 的行:

df_filter = filter_numerical('Age', 30, 'greater')
print(df_filter.head())

不到 30:

df_filter = filter_numerical('Age', 30, 'less')
print(df_filter.head())

或者等于 30:

df_filter = filter_numerical('Age', 30, 'equal')
print(df_filter.head())

我们也可以按工资过滤。首先,让我们将工资转换成浮动工资:

f['Wage'] = df['Wage'].str.lstrip('€')
df['Wage'] = df['Wage'].str.rstrip('K')
df['Wage'] = df['Wage'].astype(float)*1000.0print(df['Wage'].head())

现在让我们过滤工资低于 100000 欧元的情况:

df_filter = filter_numerical('Wage', 100000, 'less')
print(df_filter.head())

我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。可以考虑编写一个有趣的函数,它根据数值和分类列值进行过滤。

结论

总之,在这篇文章中,我们讨论了如何定义三个函数来轻松过滤数据行。首先,我们讨论了如何通过单个分类值过滤数据行。然后我们讨论如何使用分类值列表过滤行。最后,我们展示了如何通过数字列值过滤数据行。如果你有兴趣学习更多关于熊猫的数据操作、机器学习甚至只是 python 编程的一些基础知识,请查看Python for Data Science and Machine Learning:Python 编程、熊猫和 Scikit-初学者学习教程 。我希望你觉得这篇文章有用有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

用熊猫掌握数据选择

原文:https://towardsdatascience.com/mastering-data-selection-with-pandas-e8768104a39?source=collection_archive---------49-----------------------

用熊猫选择数据

来源

Pandas 是一个 python 库,为统计分析、特征工程、数据选择、数据过滤等提供了一些有用的工具。数据选择和数据过滤对于探索性数据分析、特征工程和预测模型构建非常有用。在本帖中,我们将讨论 Pandas 中一些有用的数据选择和过滤方法。

我们开始吧!

出于我们的目的,我们将使用 视频游戏销售数据集

首先,让我们导入 Pandas 库并将数据读入 Pandas 数据框:

import pandas as pd 
df = pd.read_csv("vgsales.csv")

让我们也放宽对显示列数的限制:

pd.set_option('display.max_columns', None)

接下来,让我们打印数据中的列:

print(list(df.columns))

让我们也打印一些关于数据的基本信息:

print(df.info())

现在,让我们使用“head()”方法打印前五行数据:

print(df.head())

好了,现在我们对数据中的列名和类型有了大致的了解,我们可以执行一些基本的数据选择操作了。首先,我们可以使用。loc[]'方法来根据列值选择我们的数据子集。让我们选择“体育”类别的视频游戏:

df_sports = df.loc[df.Genre == 'Sports']

让我们打印新数据框的前五行:

print(df_sports.head())

让我们看看另一个专栏。让我们为 Wii 平台选择对应于视频游戏的数据子集:

df_wii = df.loc[df.Platform == 'Wii']

让我们打印前五行数据:

print(df_wii.head())

我们也可以选择子集的子集。例如,我们选择在“Wii”上玩的“赛车”游戏:

df_wii_racing = df_wii.loc[df.Genre == 'Racing']

我们也可以用一行代码使用一个联合条件来执行这个操作:

df_wii_racing = df.loc[(df.Platform == 'Wii') & (df.Genre == 'Racing')]
print(df_wii_racing.head())

我们可以添加任意多的条件。让我们选择全球销量超过 100 万台的 Wii 赛车游戏:

df_gt_1mil = df.loc[(df.Platform == 'Wii') & (df.Genre == 'Racing') & (df.Global_Sales >= 1.0)]
print(df_gt_1mil.head())

我们也可以使用'按行选择数据。iloc[]'方法。让我们选择原始数据的前 1000 行:

df_filter_rows = df.iloc[:1000]
print("Length of original: ", len(df))
print("Length of filtered: ", len(df_filter_rows))

我们还可以使用“sample()”方法选择数据的随机样本:

df_random_sample = df.sample(n=5000)
print("Length of sample: ", len(df_random_sample))

如果我们打印前五行:

print(df_random_sample.head())

并在另一次运行中打印前五行:

我们看到我们得到不同的结果。如果我们希望始终获得相同的结果,我们可以在示例方法中设置“random_state”参数:

df_random_sample = df.sample(n=5000, random_state = 42)
print("Length of sample: ", len(df_random_sample))

这将在每次运行时给我们相同的结果。我将在这里停下来,但是我鼓励您自己尝试代码和数据。

结论

总之,在这篇文章中,我们讨论了如何使用 Python Pandas 库选择和过滤数据。我们讨论了如何使用。“loc[]”方法根据列值选择数据子集。我们还展示了如何使用'按行过滤数据帧。iloc[]'方法。最后,我们讨论了如何使用“sample()”方法从数据帧中选择随机数据样本。我希望你觉得这篇文章有趣/有用。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

使用 Python 和 Pandas 掌握日期和时间操作

原文:https://towardsdatascience.com/mastering-date-and-time-manipulations-with-python-and-pandas-e1cb2db8177a?source=collection_archive---------41-----------------------

你不知道你不知道什么。

有一句老话是这样说的:不管开发人员是初级还是高级,在处理日期时,他总是会参考文档。我同意,我的工作也是如此。有很多事情我可以不用引用的文档来实现,但是我最不擅长的是日期和时间操作,或者设法记住格式化代码。

Aron VisualsUnsplash 上拍摄的照片

这就是我决定写一篇关于这个话题的文章的原因——我不觉得我在这种情况下是孤独的。

处理日期和时间并不难,但是肯定有很多事情需要记住。今天我们将讨论其中的大部分内容,以便您为下一个分析挑战做好准备。我们所做的一切要么在 Python 处理日期和时间的默认库中实现——方便地称为datetime——要么在 Pandas 中实现。

以下是进口货:

事不宜迟,让我们直接开始吧。

日期时间基础

使用datetime库,我们可以很容易地创建日期时间对象——如果您不关心小时、分钟和秒的信息,这里有一个如何创建日期时间对象的例子:

或者,如果您确实关心这些,您可以很容易地指定值:

也许你想知道现在的时间,精确到毫秒——你可以使用方便的.now()功能:

时间增量

让我们现在做一些不同的事情。我要声明一个变量,并将它的值设置为当前时间:

稍后,我将声明另一个变量,并将其值设置为当前时间减去current_time变量的值:

您可以看到我们是如何返回这个 timedelta 对象的,这表明在声明这两个变量之间经过了多长时间。您可以轻松访问这些信息:

如果要计算数据集中两个日期列之间的差异,这可能会很有用,例如,如果一列指示某个过程开始的时间,而另一列指示该过程结束的时间。

字符串到时间,反之亦然

datetime库有两种更方便的方法将字符串记录转换成日期时间对象,或将日期时间对象转换成字符串。

让我们探索第一个选项。您有一个字符串表示的时间信息,并希望将它转换成 datetime 对象,以便以后更快地操作(在这种情况下,实际上不能比较字符串)。在这种情况下,您将需要使用strptime()功能:

如果你对格式感到困惑,看看这个网站,你会在那里找到所有的代码。

这个过程可以反过来。假设您有日期信息,表示为 datetime,并且您需要以某种方式将值呈现给用户,比如说通过某种前端。strftime()方法可以解决问题:

现在,当我们有了这些工具,让我们探索一下 Pandas 库提供了什么。

熊猫的日期范围

在处理日期的大部分时间里,我都在使用 Python 的datetime库。唯一的例外情况是:

  • 日期范围
  • 时间重采样

第二个问题需要一整篇文章来深入探讨,所以我将重点讨论第一个问题。

我使用 Pandas 来创建日期范围,只是因为我想避免标准库的循环。如果你不确定我所说的“日期范围”是什么意思,这里有一个简短的例子。想法是从 2020 年 1 月 1 日开始创建一个 30 天的时间段:

你看到那有多容易了吗?

请记住,您不需要坚持某种特定的格式,因为 Pandas 很聪明,可以推断出这一点:

这个也很好:

即使是一些疯狂的组合也不成问题:

在你走之前

Python 中的日期和时间声明和操作已经足够了。你可以做更高级的事情,但我发现这对大多数任务来说已经足够了。

如果你喜欢这篇文章,请继续关注,过几天我会发表一篇关于日期重采样和基于时间条件的高级数据过滤的文章。

感谢阅读。

喜欢这篇文章吗?成为 中等会员 继续无限制的学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

掌握 Pandas(和 Python)中的日期和时间戳

原文:https://towardsdatascience.com/mastering-dates-and-timestamps-in-pandas-and-python-in-general-5b8c6edcc50c?source=collection_archive---------3-----------------------

你所需要的就是在熊猫中处理日期和时间戳!提供了许多例子。

内容

  • 一般日期

更具体地说,用…处理操作

  • 周;星期
  • 月份

额外:生成日期范围

  • 生成连续的日期范围
  • 生成随机日期范围

照片由 Aron 视觉效果Unsplash 上拍摄

一般日期

(*)在运行任何代码之前,请导入熊猫!

import pandas as pd

现在,让我们开始吧。

改变列数据框架中的日期格式

按照这个简单的 strftime 文档,你可以随意选择每种格式。

例如,从这个数据框架开始:

日期格式更改为:

df['date'] = df['date'].apply(lambda x: pd.Timestamp(x).**strftime('%Y-%m-%d')**)

或者,我们可以来点更有异国情调的:

df['date'] = df['date'].apply(lambda x: pd.Timestamp(x).**strftime('%B-%d-%Y %I:%M %p')**)

请记住,您可以选择的时间戳格式的所有变体都可以在此链接中找到: strftime

你自己试试!从这个示例构建的数据框架开始:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-03-02 13:15:21']})

将列类型从对象/字符串更改为日期时间

# 4 possible options# 1
df['date'] = pd.to_datetime(df['date'])
# 2
df['date'] = df['date'].astype('datetime64[ns]')
# 3
df['date'] = df['date'].apply(lambda x: parse(x))
# 4
df['date'] = df['date'].apply(lambda x: pd.Timestamp(x))

示例(我们只尝试了 4 个选项中的一个,但所有选项都应该有效)

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-01-02 13:15:21']})df
df.dtypesdf['date'] = pd.to_datetime(df['date'])
df
df.dtypes

输出:

从字符串到日期格式,再从日期格式到字符串

隔离变量示例:

from dateutil.parser import parsestr_date = '2018-05-01'# String to Date:
date_1 = parse(str_date)
print ('date_1: ',date_1, type(date_1))# Date to String:
date_2 = date_1.strftime('%Y-%m-%d')
print ('date_2: ',date_2, type(date_2))

输出:

从 Unix/纪元时间到可读日期格式

df['date'] = pd.to_datetime(df['date'],unit='s')

示例:

df = pd.DataFrame({'date': [1349720105,1349806505]})dfdf['date'] = pd.to_datetime(df['date'],unit='s')df

输出(之前和之后):

加减日期

使用时间增量!示例:

from datetime import datetime, timedelta
from dateutil.parser import parseparse('2019-04-07') — timedelta(days=3)# or, to get it as a string
(parse('2019-04-07') — timedelta(days=3)).strftime('%Y-%m-%d')

输出:

# with date format 
datetime.datetime(2019, 4, 4, 0, 0) # with string format
'2019-04-04'

得到两个日期之间的差异

将两个字符串转换成日期格式,然后进行计算。示例:

from dateutil.parser import parsed1 = parse('2018-12-01')
d2 = parse('2018-12-08')
abs((d2 - d1).days)

输出:

7
# 7 days

带天数的操作

从日期中获取日期

# for a column in a DataFrame
from datetime import datetime as dt
df['day'] = df['date'].dt.day# for a single value
from dateutil.parser import parse
parse('2018-08-09').day

输出:

9

数周的操作

获取一年中的第几周

示例:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-01-02 13:15:21']})# if date column type is a string
df['week'] = pd.DatetimeIndex(df['date']).week# if date column type is a datetime
# df['week'] = df['date'].dt.week

输出:

(*)要创建 yyyy-ww 格式的周列,请使用:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-03-02 13:15:21']})# if column type is a string/object
df['yyyy_ww'] = pd.DatetimeIndex(df['date']).strftime('%Y-%U')# if column type is a datetime
# df['yyyy_ww'] = df['date'].dt.strftime('%Y-%U')

对于独立变量:

import datetime
date_1 = '2018-02-06'
parse(date_1).isocalendar()[1]

输出:

6
# 6th week of the year

获取工作日

示例:

df['weekday'] = df['date'].apply(lambda x: parse(str(x)).strftime("%A"))

输出:

从年-周格式转换到 yyyy-mm-dd 格式(获得一周的第一天和最后一天)

示例:您想知道 2018 年第 37 周的开始和结束日期:

# define this function
def get_start_end_dates(yyyyww):
    year = yyyyww[:4]
    week = yyyyww[-2:]
    first_day_year = str(year) + '-' +  '01' + '-' + '01'
    d = parse(first_day_year)
    if(d.weekday()<= 3):
        d = d - timedelta(d.weekday())             
    else:
        d = d + timedelta(7-d.weekday())
    dlt = timedelta(days = (int(week)-1)*7)
    return (d + dlt).strftime('%Y-%m-%d'),  (d + dlt + timedelta(days=6)).strftime('%Y-%m-%d')# run it
get_start_end_dates('201837')

输出(包含一周的开始和结束的元组):

('2018-09-10', '2018-09-16')

月操作

获取一年中的月份号

示例:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-03-02 13:15:21']})# if date column type is a string/object
df['month'] = pd.DatetimeIndex(df['date']).month# if date column type is a datetime
# df['month'] = df['date'].dt.month

输出:

对于独立变量:

import datetime
date_1 = '2018-02-06'
parse(date_1).month

输出:

2
# 2nd month of the year

(*)要创建 YYYY-MM 格式的月份列,请使用:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-03-02 13:15:21']})# if column type is a string/object
df['yyyy_mm'] = pd.DatetimeIndex(df['date']).strftime('%Y-%m')# if column type is a datetime
# df['yyyy_mm'] = df['date'].dt.strftime('%Y-%m')

加减月份(向前或向后移动 X 个月)

使用此功能

def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, [31,
        29 if y%4==0 and not y%400==0 else 28,31,30,31,30,31,31,30,31,30,31][m-1])
    new_date = (date.replace(day=d,month=m, year=y))
    return new_date.strftime('%Y-%m-%d')

示例(某个日期减去 4 个月):

monthdelta(parse('2019-11-09'), -4)

输出(显示相同的日期,但在 4 个月之前):

'2019-07-09'

运营年限

获得年份

示例:

df = pd.DataFrame({'date': ['2018-08-09 11:10:55','2019-03-02 13:15:21']})# if date column type is a string/object
df['year'] = pd.DatetimeIndex(df['date']).year# if date column type is a datetime
# df['year'] = df['date'].dt.year

对于独立变量:

import datetime
date_1 = '2018-02-06'
parse(date_1).year

输出:

2018

生成数据范围

生成连续的日期范围

示例:生成从 2019 年 1 月 1 日到 2019 年 1 月 2 日的日期范围,频率为每小时。

from datetime import datetime
import numpy as npdate_range = pd.date_range(start='01/01/2019', end='01/02/2019', freq='H')

参见中的不同频率选项。

生成随机日期范围

import random
import time
from dateutil.parser import parsedef str_time_prop(start, end, format, prop):
    stime = time.mktime(time.strptime(start, format))
    etime = time.mktime(time.strptime(end, format))
    ptime = stime + prop * (etime - stime)
    return time.strftime(format, time.localtime(ptime))selected_format = '%Y-%m-%d %H:%M:%S'def random_date(start, end, prop):
    return parse(str_time_prop(start, end, selected_format, prop)).strftime(selected_format)print(random_date("2020-01-01 13:40:00", "2020-01-01 14:10:00", random.random()))def make_date(x):
    return random_date("2012-12-01 13:40:00", "2012-12-24 14:50:00", random.random())

这里是这个函数的[源](# more https://stackoverflow.com/questions/553303/generate-a-random-date-between-two-other-dates)。

由此,我们可以生成随机日期。例如,让我们生成圣诞节和新年之间的 10 个随机时间戳的列表:

def make_date(x):
    return random_date("2012-12-24 00:00:00", "2012-12-31 23:59:59", random.random())[make_date(x) for x in range(10)]

我们还可以将它添加到任何数据帧中,如下所示:

df = pd.DataFrame({'number': [1,2,3,4,5]})
df['time'] = df['number'].apply(make_date)
df

这是文章的结尾。希望你喜欢它,也希望你能好好利用它!

如果您有任何问题,请给我发消息或留下回复。

如果你想在将来了解类似这样的文章,请关注我!

使用 Awk 实用程序掌握文件和文本操作

原文:https://towardsdatascience.com/mastering-file-and-text-manipulation-with-awk-utility-65fc09d56bef?source=collection_archive---------21-----------------------

只需一行命令即可实现高级文本处理

马丁·范·登·霍维尔Unsplash 拍摄的照片

作为软件开发人员、系统管理员和数据科学家,处理和操作文件是我们日常工作中频繁而重要的一部分。知道如何处理文本文件,并以快速有效的方式对它们进行所需的更改,可以节省我们大量的时间。

在本文中,我将向您介绍 Awk command,这是一个非常强大的文本处理工具,可以用一行或几行代码完成复杂的文本处理任务。你可能倾向于使用你最喜欢的编程语言,比如 Python、Java、C……来完成这类任务,但是在阅读完这篇教程之后,你会意识到用 Awk 来完成其中的许多任务会更加简单和高效。

我将通过提供如何用 Awk 解决常见文本处理任务的基本示例来演示 Awk 的用法。

装置

默认情况下,Awk 在大多数 Unix 发行版上都是可用的。如果您没有它,您可以使用以下命令来安装它。

对于基于 Debian 的发行版:

$ sudo apt-get install gawk

对于基于 RPM 的分发:

# yum install gawk

如果您使用的是 Microsoft Windows,请查看 GNU 手册中的安装说明。

工作流程

Awk 工作流程很简单。它从输入流中读取一行,对它执行指定的命令,并重复这个过程,直到文件结束。

还有 BEGIN 和 END 块,您可以使用它们在重复过程之前和之后执行一些命令。

作者流程图

让我们开始吧

Awk 命令的基本结构是这样的:

awk [options] file ...

让我们举几个例子。

示例 1:按原样打印每一行

考虑一个文本文件 input.txt ,其内容如下:

John 23 ItalyDavid 18 SpainSarah 21 GermanyDan 42 GermanyBrian 50 EnglandLewis 37 FranceEthan 12 France

通过运行命令:

$ awk '{print}' input.txt

它将为正在打印的每一行运行{print}。因此输出将与输入相同。

示例 2:打印前两列

这里我们只想打印每个人的名字(第一个单词)和年龄(第二个单词),用制表符分开。

命令:

$ awk '{print $1 "\t" $2}' input.txt

输出:

John    23David   18Sarah   21Dan     42Brian   50Lewis   37Ethan   12

在上面的例子中, $1 和$2 代表每条输入线的第一个和第二个场。 $0 代表整行。

示例 3:在每一行的开头添加行号

在这里,我们将变量定义为 count,在读取每一行时递增,并在第一行打印出来。

命令:

$ awk -v count=0 '{print ++count " " $0}' input.txt

注意我们也可以去掉-v count=0部分。它将被隐式定义为值 0:

$ awk '{print ++count " " $0}' input.txt

输出:

1 John 23 Italy2 David 18 Spain3 Sarah 21 Germany4 Dan 42 Germany5 Brian 50 England6 Lewis 37 France7 Ethan 12 France

示例 4:仅打印 30 岁以上的人

Awk 编程语言也支持条件。

命令:

$ awk  '{if ($2 > 30) print $0}' input.txt

输出:

Dan 42 GermanyBrian 50 EnglandLewis 37 France

示例 5:生成每个国家有多少人的报告

我们可以通过使用字典和循环来达到这个目的。

命令:

$ awk '{my_dict[$3] += 1} END {for (key in my_dict) {print key, my_dict[key]}}' input.txt

这里我们有一本名为my_dict的字典。对于每一行,关键字是第三个单词(国家名称),我们将它的值增加 1。在END关键字之后,我们可以编写结束块命令,我们已经在工作流部分解释过了。在结束块,我们循环字典并打印它的(键,值)对。

输出:

Spain 1France 2Germany 2Italy 1England 1

示例 6:计算平均年龄

命令:

$ awk '{age_sum += $2} END {print age_sum/NR}' input.txt

NR是一个内置变量,代表当前记录号。所以在END block,它将等于总行数。

输出:

29

你可以在这里看到其他 Awk 内置变量。

示例 7:仅打印姓名中包含“s”字符的人

我们可以在 Awk 中使用正则表达式。

命令:

awk '$1 ~ /[sS]/ {print $1}' input.txt

这里我们指定第一个单词$1应该匹配正则表达式[sS]

输出:

SarahLewis

示例 7:如果输入文件是另一种格式,比如 CSV,该怎么办?

您可以使用-F选项设置用于分隔字段的正则表达式。

考虑将该文件命名为input.csv:

John,23,ItalyDavid,18,SpainSarah,21,GermanyDan,42,GermanyBrian,50,EnglandLewis,37,FranceEthan,12,France

命令:

awk -F "," '{print $1 " " $3}' input.csv

输出:

John ItalyDavid SpainSarah GermanyDan GermanyBrian EnglandLewis FranceEthan France

示例 8:通过定义一个函数,添加一个新列来显示这个人是小于还是大于 20 岁

在这个例子中,我们将展示如何创建和使用函数。此外,我们将把代码添加到一个名为prog.awk的文件中,而不是把它作为输入参数。我们还将输出打印到一个名为output.txt的文件中。

程序 awk:

# Returns if the person is younger or older than 20
function age_func(age) {
    if (age < 20) {
        return "younger"
    }
    return "older"
}{print $0 " " age_func($2)}

命令:

awk -f prog.awk input.txt > output.txt

输出. txt:

John 23 Italy olderDavid 18 Spain youngerSarah 21 Germany olderDan 42 Germany olderBrian 50 England olderLewis 37 France olderEthan 12 France younger

Awk 也有一些内置函数,你可以在这里查看

摘要

在本文中,我们展示了 Awk 命令的工作流程,通过提供一些例子,我们看到 Awk 是一个强大而灵活的文本处理工具,可以在许多场景中使用。你可以阅读[GNU Awk 用户指南](https://www.gnu.org/software/gawk/manual/gawk.html)以获得更详细的说明。

谢谢大家,编码快乐!

张量流上深度学习模型的线性代数

原文:https://towardsdatascience.com/mastering-linear-algebra-in-tensorflow-part1-input-layer-e0480a8d69bf?source=collection_archive---------17-----------------------

以表格数据为例进行处理

初学者的一个耗时问题是不同深度学习架构下的矩阵运算。换句话说,处理线性代数的东西代表了你对矩阵计算机制的理解程度。如果你对线性代数中的矩阵或张量没有什么概念,可以看看维哈尔·鞍马在 Medium 上的文章。为了减少混乱, TensorFlow 1。x 和张量流 2。x 都将包含在本教程中。所有代码在 Google Colab 上都是可执行的,你可以在最短的时间内进入主题。

主要数据格式

在详细介绍之前,输入数据格式有四种主要类型:

1。矢量数据

(1)数据形状:(数据样本*特征)

2。时间序列数据或序列数据

(1)数据形状:(数据样本时间戳特征)

对于序列数据,时间戳代表输入数据的序列长度,该长度在输入模型之前应该是固定的。通常的方法包括零填充和切片。至于时间序列数据,它代表每个时间段。

3。图像数据

(1)数据形状:(数据样本高度宽度*通道)

高度和宽度指的是图像的形状。通道表示 RGB(通道是 3)、灰度(通道是 1)等。

(2)数据形状:(数据样本特征)如果展平高度宽度*通道

4。视频数据

(1)数据形状:(数据样本高度宽度通道)

(2)数据形状:(数据样本特征)如果展平框架高度宽度通道

矢量数据

今天,在构建这种类型的模型时,我们将重点关注矢量数据和线性代数处理。请注意,数据预处理可能会被忽略,因为我们现在关注的内容不在这里。向量数据,也称为 2D 张量。如果我们说单个数据是一个向量,那么 2D 向量数据就是我们一次处理多个单个数据的时候。2D 向量数据是机器学习中最常见的任务,我们有时也会将图像数据等高维矩阵转换为 2D 向量。

矢量数据—分类问题

1.数据准备

假设我们正在 TensorFlow 1.X 上为虹膜数据集实现一个 3 层多层感知器,用于分类。首先,我们导入一些必要的包:

关于 TensorFlow 1。X:

在 TensorFlow 2 上。X:

2.模型架构准备

然后,我们分配每层数据的维度:

3.模型构建(输入和隐藏层)

为了方便起见,我们将隐藏层的输出形状设置为相同的维度,即 4。n_class指目标特征的类别数。那么,我们先来处理棘手的部分:inputs, and labels

关于 TensorFlow 1。X:

根据 TensorFlow 的设计,我们倾向于将feature_size作为第二维度,将None作为第一维度的任意数量的样本(批量)。对于权重(w1),我们使用[feature_size, hidden_1]。至于偏,形状是[hidden_1, ]。因此,我们做第 1 层tf.add(tf.matmul(x, w1), b1)但是,为什么不是 Wx + b 呢?为什么 xW 更有意义?我们来看下图:

TensorFlow 预期形状为(number of examples, num_classes)。因此,做tf.matmul(x, W)对于适应 TensorFlow 的 API 格式更直观。不过,你可能会看到一些输入数据或教程,如来自吴恩达的Deep learning . aiusetf.matmul(W, x)但是,这种格式需要点积后的转置操作( tf.transpose(tf.matmul(W, x)) ) :

根据这个原因,就更容易知道为什么下面几层是这个样子了:

在 TensorFlow 2 上。X:

张量流 2。x 就方便多了,你只需要小心输入层,应该是(feature_size, )。至于其他的,你只需要指定输出形状,TensorFlow 2。x 会帮你完成剩下的部分。注意,代码的格式是函数式 API 格式,保持了更大的灵活性。但是您仍然可以使用通用的,因为我两者都提供了。

4.模型构建(优化器和预测)

对于初学者来说,预测也是一个棘手的部分,尤其是当他们看到到处都是像tf.argmaxtf.reduce_mean这样的语法时。

在 TensorFlow 1 上。X:

tf.argmax是一个返回数组中最大数字的索引的函数。参数axis指定您正在比较哪个维度。例如,axis = 1比较第二维,即 Iris 数据集中的特征列。为了说明清楚,我们来看下图:

tf.equal(tf.argmax(targets, 1), tf.argmax(output_logits, 1))之后,我们将收到一个布尔值列表,指示两个索引是否匹配相同的值,也就是说,正确的预测。然后,tf.reduce_mean是对结果进行平均的函数,总精度!

在 TensorFlow 2 上。X:

向量数据—回归问题

至于回归问题,它们比分类要简单得多,因为标签只是一个 1D 向量。你需要的是改变输出维度和激活函数,比如把激活函数从‘soft max’改成‘relu’,就万事大吉了。

表格数据教程到此结束。接下来,我们将开始处理序列数据和时序数据上的线性代数!

掌握 Python 中的链表

原文:https://towardsdatascience.com/mastering-linked-lists-in-python-ce66650de666?source=collection_archive---------45-----------------------

理解单链表数据结构

来源

链表是计算机科学中重要的数据结构。链表是节点的线性集合,其中每个节点包含一个数据值和对列表中下一个节点的引用。在这篇文章中,我们将通过一个例子来构建一个对应于音乐播放列表的单链表。

我们开始吧!

首先,我们将定义一个名为“SongNode”的类。在“init”方法的参数中,我们将属性“current_song”和“next_song”初始化为“None”:

class SongNode:
    def __init__(self, current_song=None, next_song = None):

接下来,我们定义类属性,“当前歌曲”和“下一首歌曲”:

class SongNode:
    def __init__(self, current_song=None, next_song = None):
        self.current_song = current_song
        self.next_song = next_song

现在,让我们写一个类,允许我们建立我们的链接歌曲列表。让我们称这个类为“歌曲列表”:

class SongList:
    def __init__(self):  
        self.head = None

我们将使用“SongList”类来初始化我们的歌曲列表对象,该类将包含对“SongNode”类型的引用。让我们编写一个 song list 类的实例并打印结果:

if __name__=='__main__':
    #initialize linked list object
    linkedlist = SongList()
    print(linkedlist)

现在让我们为我们的播放列表建立一个链接的歌曲列表。让我们根据 娱乐周刊 选出披头士有史以来的前 3 首歌曲。首先让我们定义每个节点的值。(注:‘…’对应省略的代码):

if __name__=='__main__':
    ... 
    #assign values to nodes 
    linkedlist.head = SongNode("A Hard Day's Night")
    second = SongNode('A Day in the Life')
    third = SongNode("Strawberry Fields Forever")

现在让我们定义头节点的“下一首歌”值(第一首歌):

if __name__=='__main__':
    ...
    #link nodes
    linkedlist.head.next_song = second

然后我们定义第二个节点的“下一首歌”值:

if __name__=='__main__':
    ...
    second.next_song = third

接下来,让我们定义一个简单的函数,它将允许我们遍历链接的歌曲列表。在 while 循环中,我们将打印当前歌曲的值,并将当前值重新定义为下一首歌曲,直到它到达链表的尾部,指向 null:

class SongList:   
    ...
    def printSongs(self): 
        value = self.head 
        while (value): 
            print(value.current_song) 
            value = value.next_song

接下来,让我们打印我们的歌曲列表:

if __name__=='__main__':
    ...
    linkedlist.printSongs()

接下来,让我们定义一个函数,允许我们在链表的末尾插入一首歌曲。该函数将采用参数“new_song”。该函数首先检查链表的头是否为‘None’。如果是,头取新歌的值:

def NewSong(self, new_song):
        NewSongNode = SongNode(new_song)
        if self.head is None:
            self.head = NewSongNode

接下来,变量“last”被定义为头节点,在 while 循环中,我们遍历链接的对象,直到到达指向 null 的 song 节点。“最后”节点的“下一首歌曲”值被定义为新的歌曲节点:

def newSong(self, new_song):
    NewSongNode = SongNode(new_song)
    if self.head is None:
        self.head = NewSongNode
    last = self.head
    while(last.next_song):
        last = last.next_song
    last.next_song=NewSongNode

现在,让我们添加两首新歌“她爱你”和“什么”,并打印我们的歌曲列表:

if __name__=='__main__':
    ...
    linkedlist.newSong("She Loves You")
    linkedlist.newSong("Something")
    linkedlist.printSongs()

我就讲到这里,但是我鼓励你自己去研究代码。具体来说,您可能想尝试在“SongList”类中定义一个函数,允许您搜索一个节点。您还可以尝试定义一个允许您删除节点的方法。

总之,在这篇文章中,我们讨论了如何创建一个与歌曲播放列表相对应的链表。我们展示了如何使用“SongNode”类定义歌曲节点,以及如何使用“SongList”类链接“SongNode”对象。我们还展示了如何在链表的末尾添加额外的歌曲节点。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

掌握 Python 中的列表方法

原文:https://towardsdatascience.com/mastering-list-methods-in-python-183e2469ae87?source=collection_archive---------50-----------------------

Python 中可用于列出对象的方法

来源

在 python 中,列表是可变的值集合。鉴于 python 中的列表是对象,就像 Python 中的大多数事物一样,它们有各自的属性和方法。在这篇文章中,我们将讨论 python 中列表对象可用的方法。

我们开始吧!

首先,让我们定义一个包含一些编程语言名称的基本列表:

languages = ['python', 'swift', 'julia', 'ruby', 'go']

我们可以使用内置的 python 方法“len()”来获得列表的长度:

print("Length: ", len(languages))

接下来,我们可以使用“type()”方法来验证我们的列表对象类型:

print(type(languages))

现在让我们使用' dir()'来查看 list 对象可用的所有方法和属性:

print(dir(languages))

现在,让我们考虑“append()”方法。我们可以使用 append 方法向列表中添加元素。首先,让我们打印“语言”列表:

print(languages)

让我们使用“append”方法将“scala”添加到我们的列表中,并打印结果:

languages.append('scala')
print(languages)

我们还可以在 for 循环中追加值:

for i in range(5):    
    languages.append('scala')
print(languages)

另一个有用的方法是“count()”。我们可以用这个方法来计算一个值在列表中出现的次数:

languages = ['python', 'swift', 'julia', 'ruby', 'go']
languages.append('scala')
for i in range(5):    
    languages.append('scala')
print("Count:",languages.count('scala'))

我们还可以使用“clear()”方法删除所有元素:

languages.clear()
print("Empty list: ", languages)

让我们重新定义我们的原始列表:

languages = ['python', 'swift', 'julia', 'ruby', 'go']

接下来,我们可以使用“copy()”方法将列表的浅层副本存储在一个新变量中:

languages_copy =  languages.copy()

为了验证这是一个浅层拷贝而不是引用,让我们通过将“sql”追加到“languages_copy”来修改“languages_copy”:

languages_copy.append('sql')
print(languages)
print(languages_copy)

我们看到“languages_copy”被修改,而“language”未被修改。让我们将其与一个参考进行比较:

languages_reference =  languages
languages_reference.append('r')
print(languages)
print(languages_reference)

正如我们所料,修改“languages_reference”列表也会修改原始语言列表,这在许多情况下并不是理想的行为。浅层复制方法在一定程度上解决了这个问题。现在,如果我们有一个如下的列表列表:

languages = [['python', 'swift'], ['julia', 'ruby', 'go']]
languages_copy =  languages.copy()

我们修改了子列表中的一个元素,例如将“julia”改写为“r”:

languages_copy[1][0] = 'r'
print(languages)
print(languages_copy)

这也将修改原始列表。这是浅层拷贝的一个局限。副本只有一层,所有后续层都是对原始对象的引用。为了执行深度复制,我们使用“复制”模块中的“deep copy()”方法:

import copy
languages = [['python', 'swift'], ['julia', 'ruby', 'go']]
languages_deep_copy = copy.deepcopy(languages)

现在我们可以在副本中修改子列表的元素,而不修改原始列表:

languages_deep_copy[1][0] = 'r'
print(languages)
print(languages_deep_copy)

我们要讨论的下一个方法是“extend()”,它允许我们将一个列表中的元素添加到另一个列表中。这里我们有两个城市列表,我们将使用' extend()'将一个列表的元素添加到另一个列表中。

list_one = ['New York', 'Boston', 'Los Angeles']
list_two = ['Dallas', 'Portland', 'Hoboken']
list_one.extend(list_two)
print(list_one)

另一个有用的方法是“reverse()”,它允许我们在适当的位置反转列表中的元素。让我们为我们最初的“语言”列表这样做:

languages = ['python', 'swift', 'julia', 'ruby', 'go']
languages.reverse()
print(languages)

此外,我们有“sort()”方法,它允许我们按数字或字母顺序对元素进行排序。对于我们的语言列表,我们有:

languages = ['python', 'swift', 'julia', 'ruby', 'go']
languages.sort()
print(languages)

如果我们有一个数字列表:

list_of_numbers = [10, 300, 1, 400, 10]
list_of_numbers.sort()
print(list_of_numbers)

我们将讨论的最后一个方法是“pop()”方法。此方法接受一个索引,并返回和移除该索引处的元素。如果没有提供索引,它将返回并删除最后一个值:

languages = ['python', 'swift', 'julia', 'ruby', 'go']
print("Last element: ",languages.pop())

如果我们想返回并删除第三个索引处的值,我们应该得到“julia”:

languages = ['python', 'swift', 'julia', 'ruby', 'go']
print("Third index element: ",languages.pop(2))

我将在这里停下来,但是我鼓励你自己尝试这些列表方法。

结论

总之,在这篇文章中,我们讨论了 python 中的列表方法。我们讨论了如何计算列表中的值,复制列表,反转列表中的元素,排序列表值,清除列表值,弹出列表值等等。我希望你觉得这篇文章有用/有趣。感谢您的阅读!

掌握 Python 中的机器学习

原文:https://towardsdatascience.com/mastering-machine-learning-in-python-67b8a9e5db50?source=collection_archive---------34-----------------------

可访问的机器学习用例

照片由像素上的 Hitesh Choudhary 拍摄

机器学习是使用特征来预测结果测量的过程。机器学习在很多行业都扮演着重要的角色。一些例子包括使用机器学习进行医疗诊断、预测股票价格和广告推广优化。

机器学习采用统计学、数据挖掘、工程学和许多其他学科的方法。在机器学习中,我们使用一组训练数据,其中我们观察过去的结果和特征测量,以建立预测模型。我们可以随后使用这个模型来预测未来事件的结果测量。这种方法被称为监督机器学习。这里还有几个机器学习的用例:

  1. 预测森林火灾过火面积
  2. 识别图像中的对象
  3. 预测医疗成本

在我们继续之前,让我们简要回顾一下一些术语。我们来区分一下有监督和无监督的机器学习。

监督机器学习

监督学习是学习一个函数的任务,该函数基于过去的特征-结果对的例子将特征测量映射到结果测量。在受监督的机器学习中,测量输出在本质上可以根据示例而变化。有定量测量结果,我们使用回归模型,定性测量结果,我们使用分类模型。

无监督机器学习

另一种类型的机器学习是无监督学习,其中我们只观察特征测量,而不观察结果。无监督学习是在没有预先存在的测量结果的情况下发现未检测到的模式的任务。

监督学习的定量和定性结果

定量测量结果(回归)

例如,在预测森林火灾的燃烧面积时,输出是一种定量测量。可以有大的烧伤面积、小的烧伤面积以及介于两者之间的数值范围。同样,在预测医疗费用的例子中,您可以有大的和小的医疗费用以及介于两者之间的例子。一般来说,价值接近的结果测量具有相似的性质(相似的特征/输入)。

定性测量结果(分类)

定性变量是描述性标签或有序分类值的分类或离散变量。在图像分类的例子中,图像标签只是对图像内容的简单描述(例如:建筑物、飞机等等)。定性变量通常用数字代码表示。例如,如果您正在对猫和狗的图像进行分类,猫可以用“0”进行编码,狗可以用“1”进行编码(因为狗更好)。

在这篇文章的剩余部分,我将介绍上面列出的三个机器学习用例。我将开发一个基线模型,用 python 实现,演示回归和分类的监督学习。

我们开始吧!

预测森林火灾过火面积

这个例子的数据包含了来自葡萄牙 Montesinho 自然公园的 517 起火灾。该数据包含烧伤区域和相应的事故周、月和坐标。它还包含气象信息,如雨水、温度、湿度和风力。目标是从包括空间、时间和天气变量在内的大量测量数据中预测烧伤面积。这个例子是一个监督学习回归问题,因为结果测量是定量的。数据可以在这里找到。

首先,让我们进口熊猫。Pandas 是一个 python 库,用于各种任务,包括数据读取、统计分析、数据聚合等等。我们将使用 Pandas 将我们的数据读入所谓的数据帧。数据框是带有标注列的二维数据结构。数据框与 Excel 电子表格非常相似。

让我们用熊猫来读取我们的数据:

import pandas as pd df = pd.read_csv("forestfires.csv")

让我们打印前五行数据:

让我们使用随机森林模型来进行预测。随机森林使用一组不相关的决策树。决策树是流程图,包含关于数据特征的是或否问题和答案。为了更好地介绍随机森林,我推荐你阅读了解随机森林

对于我们的模型,我们将使用“月”、“温度”、“风”和“雨”来预测烧伤面积。让我们将月份转换成可以用作输入的数值:

df['month_cat'] = df['month'].astype('category')
df['month_cat'] = df['month_cat'].cat.codes

接下来,让我们定义输入“X”和输出“y”:

import numpy as np
X = np.array(df[['month_cat', 'temp', 'wind', 'rain']])
y = np.array(df[['area']]).ravel()

然后,我们将数据进行拆分,用于训练和测试:

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

现在让我们定义我们的随机森林对象,并使我们的模型适合我们的训练数据。这里我们将使用 100 个评估器(决策树的数量)和最大深度 100(要问的问题的数量):

reg = RandomForestRegressor(n_estimators = 100, max_depth = 100)
reg.fit(X_train, y_train)

然后,我们可以根据测试数据进行预测:

y_pred = reg.predict(X_test)

我们可以通过运行训练/测试分割和预测计算 1000 次并取所有运行的平均值来评估我们的模型的性能:

for i in range(0, 1000):X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

    reg = RandomForestRegressor(n_estimators = 100, max_depth = 100)
    reg.fit(X_train, y_train)

    y_pred = reg.predict(X_test)
    result.append(mean_absolute_error(y_test, y_pred))

print("Accuracy: ", np.mean(result))

现在,让我们转到另一个机器学习用例:图像分类。

识别图像中的物体

在本例中,我们将使用来自英特尔图像分类挑战赛的数据构建一个分类模型。它包含了 25k 张森林、海洋、建筑、冰川、山脉和街道的图片。数据可以在这里找到。

我们将使用卷积神经网络(CNN)对图像数据中的对象进行分类。CNN 是一类最常用于计算机视觉的深度神经网络。CNN 发现图像的低级特征,如边缘和曲线,并通过一系列卷积建立更一般的概念。

CNN 的组成包括以下几层:

卷积层:滤镜一次扫描几个像素。从这些像素中,生成特征并用于预测每个特征所属的类别。

汇集层:该层对卷积层输出的每个特征的信息量进行下采样,同时保留最重要的信息。

展平图层:该图层从之前的图层中提取输出,并将它们转换成一个单独的矢量,用于输入。

完全连接层:该层将权重应用于生成的特征。

输出层:最后一层给出类别预测。

CNN 大致上是受视觉皮层的启发,在视觉皮层中,细胞的小区域对视野中的特定区域很敏感。因此,神经元会在特定方向的边缘出现时放电,共同产生视觉感知。对于 CNN 更彻底的讨论,可以考虑阅读理解卷积神经网络的初学者指南。如果你想进一步了解 CNN,文章卷积神经网络中的全连接层:完整指南是另一个有用的资源。

现在让我们建立我们的图像分类模型。本文中的代码灵感来自 Kaggle 内核:英特尔图像分类(CNN — Keras)

首先,让我们导入必要的包:

import os
from sklearn.metrics import confusion_matrix
from sklearn.utils import shuffle                    
import cv2                                 
import numpy as np 
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten

接下来,让我们定义一个加载数据的函数:

def load_data():

    datasets = ['seg_train/seg_train', 'seg_test/seg_test']
    output = []

    for dataset in datasets:

        images = []
        labels = []

        print("Loading {}".format(dataset))

        for folder in os.listdir(dataset):
            current_label = class_names_label[folder]            
            for file in os.listdir(os.path.join(dataset, folder)):

                image_path = os.path.join(os.path.join(dataset, folder), file) current_image = cv2.imread(image_path)
                current_image = cv2.resize(current_image, (150, 150)) 

                images.append(current_image)
                labels.append(current_label)

        images = np.array(images, dtype = 'float32')
        labels = np.array(labels, dtype = 'int32')   

        result.append((images, labels))return result

然后,我们定义用于训练和测试的数据:

(X_train, y_train), (X_test, y_test) = load_data()

接下来,让我们定义我们的模型:

model = Sequential()
model.add(Conv2D(32, (3, 3), activation = 'relu', input_shape = (150, 150, 3)))
model.add(MaxPooling2D(2,2))        
model.add(Conv2D(32, (3, 3), activation = 'relu'))
model.add(MaxPooling2D(2,2)) model.add(Flatten())
model.add(Dense(128, activation = 'relu'))
model.add(Dense(6, activation = 'softmax'))

然后我们编译我们的模型。我们使用稀疏分类交叉熵或对数损失作为损失函数。该指标通常用于衡量分类模型的性能:

model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics=['accuracy'])

接下来,让我们来拟合我们的模型。这里,我们将使用一个 epoch(为了节省时间)和 128:

model.fit(X_train, y_train, batch_size=128, epochs=1, validation_split = 0.2)

接下来,让我们生成预测概率,并选择概率最高的标签:

y_pred = model.predict(X_test)
y_pred = np.argmax(y_pred, axis = 1)

最后,我们可以使用 seaborn 中的热图混淆矩阵来可视化模型的输出:

import seaborn as sns 
confusion_mat = confusion_matrix(y_test, y_pred)
ax = plt.axes()
sns.heatmap(confusion_mat, annot=True, 
           annot_kws={"size": 10}, 
           xticklabels=class_names, 
           yticklabels=class_names, ax = ax)
ax.set_title('Confusion matrix')
plt.show()

我们的模型在预测街道和森林方面做得不错,但在其他类别方面还有很多不足之处。随意执行进一步的超参数调整(试验层数、神经元、时期和批量大小)以进一步降低分类错误率。

你也可以试着把这个应用到其他的图像分类问题上。这里可以找到几个

现在让我们继续最后一个机器学习用例:预测医疗成本。

预测医疗费用

我们将使用的数据是来自 Brett Lantz 的机器学习入门书的模拟保险成本数据。这些数据包含主要保险持有人的年龄、性别、身体质量指数、子女数量、吸烟状况、受益人的居住区域以及健康保险支付的个人医疗费用。数据可以在这里找到。

让我们导入熊猫并将数据读入熊猫数据框:

import pandas as pddf = pd.read_csv("insurance.csv")

让我们打印前五行数据:

print(df.head())

正如我们所见,这是一个非常简单的数据集。在本例中,我们将使用年龄、性别、身体质量指数、父母身份、吸烟者身份和地理区域来预测医疗费用。

对于这个例子,我们将构建一个k-最近邻回归模型来预测医疗费用。虽然我们将使用k-最近邻进行回归,但它也可以用于分类。在这两种情况下,它使用欧几里德距离计算来预测 k 最近邻的结果测量。

接下来,让我们将分类列转换成可以用作模型输入的数值:

df['sex_cat'] = df['sex'].astype('category')
df['sex_cat'] = df['sex_cat'].cat.codesdf['smoker_cat'] = df['smoker'].astype('category')
df['smoker_cat'] = df['smoker_cat'].cat.codesdf['region_cat'] = df['region'].astype('category')
df['region_cat'] = df['region_cat'].cat.codes

接下来,让我们定义输入“X”和输出“y”:

import numpy as np
X = np.array(df[['age', 'sex_cat', 'bmi', 'children', 'smoker_cat', 'region_cat']])
y = np.array(df['charges'])

让我们将数据分为训练和测试两部分:

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

现在,让我们定义我们的k-最近邻回归模型对象。让我们使用 5 个邻居:

from sklearn.neighbor import KNeighborsRegressor
reg = KNeighborsRegressor(n_neighbors = 5)

接下来,我们将模型与训练数据进行拟合:

reg.fit(X_train, y_train)

根据测试数据生成预测:

y_pred = reg.predict(X_test)

我们现在可以评估我们的模型了。让我们使用平均绝对误差指标:

from sklearn.metrics import mean_absolute_error
accuracy = mean_absolute_error(y_test, y_pred)
print("Mean Absolute Error: ", accuracy)

最后,让我们来看看我们的输出:

import matplotlib.pyplot as plt 
plt.scatter(y_test, y_pred)
plt.xlabel('True')
plt.ylabel('Predicted')
plt.title('K-nearest neighbors')

我就说到这里,但是您可以随意调整最近邻居算法,通过调整邻居的数量来调整。一般来说,k-最近邻算法更适合异常检测问题。你可以在这里找到这些问题的几个例子

结论

总之,在这篇文章中,我们讨论了机器学习和三个使用机器学习和统计方法的相关用例。我们简要讨论了监督学习和非监督学习的区别。我们还用两种问题类型的例子区分了回归模型和分类模型。我鼓励您将这些方法应用到其他有趣的用例中。例如,你可以使用 CNN 来检测 x 光图像中的乳腺癌(数据可以在这里找到)或者你可以使用K-最近邻来检测信用卡欺诈(数据可以在这里找到)。我希望你觉得这篇文章有趣/有用。如果你有任何问题,请留下评论。这篇文章的代码可以在 GitHub 上找到。祝好运,机器学习快乐!

驾驭熊猫

原文:https://towardsdatascience.com/mastering-pandas-4e0018c9658f?source=collection_archive---------25-----------------------

熊猫的数据操作

照片由像素上的 Hitesh Choudhary 拍摄

Pandas 是一个流行的 python 库,用于数据操作和分析。它支持多种数据格式的各种读取功能。它还提供了各种数据操作工具,如合并、连接和连接。在本帖中,我们将重点介绍如何使用 pandas 的计算工具进行统计分析、开窗和生成滚动统计数据。熊猫的文档可以在这里找到,熊猫计算工具的文档可以在这里找到。

我们开始吧!

我们将使用“TSLA”和“AAPL”的历史股票价格(过去 5 年的数据)在熊猫身上演示这些方法。“TSLA”的数据可以在这里找到,而“AAPL”的数据可以在这里找到

首先,让我们使用 pandas 导入数据:

import pandas as pd 
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)df_TSLA = pd.read_csv("TSLA.csv")

让我们打印前五行:

print(df_TSLA.head())

我们可以做的第一件事是使用“pct_change”方法,该方法可用于熊猫系列和数据帧。让我们在“开放”栏中尝试一下:

print(df_TSLA[‘Open’].pct_change().head())

我们也可以对“打开”、“高”、“低”和“关闭”进行同样的操作:

print(df_TSLA[["Open", "High", "Low", "Close"]].pct_change().head())

您还可以在“pct_change”方法中指定一个期间。例如,如果我们想计算每列每 3 条记录的百分比变化:

print(df_TSLA[["Open", "High", "Low", "Close"]].pct_change(periods = 3).head(6))

您还可以计算列之间的协方差。让我们计算“TSLA”价格和“AAPL”价格之间的协方差。首先,让我们读入‘AAPL’的数据:

df_AAPL = pd.read_csv("AAPL.csv")

让我们指定两个系列,一个是“TSLA”公开价格,另一个是“AAPL”公开价格:

Series_TSLA = df_TSLA['Open']
Series_AAPL = df_AAPL['Open']

现在让我们打印协方差:

print("Covariance Between TSLA and AAPL:", Series_TSLA.cov(Series_AAPL))

您还可以计算数据框中系列之间的成对协方差。对于“TSLA”,我们得到:

print(df_TSLA.cov().head())

对于“AAPL”:

print(df_AAPL.cov().head())

我们可以对相关性做同样的事情:

print("Correlation Between TSLA and AAPL:", Series_TSLA.corr(Series_AAPL))

对于“TSLA”数据帧内的系列的成对相关:

print(df_TSLA.corr().head())

对于“AAPL”:

print(df_AAPL.corr().head())

pandas 中提供了几种计算窗口和滚动统计的方法。这包括总和、平均值、中间值、相关性等等。我们将在下面演示其中的一些。

让我们计算未平仓“AAPL”价格的累计总和:

print(df_AAPL['Open'].cumsum().head())

我们也可以用我们选择的窗口大小来计算滚动平均值。让我们计算窗口大小为 10 的“AAPL”的滚动平均开盘价:

print(df_AAPL['Open'].rolling(window = 10).mean().head(20))

我们也可以将这些结果可视化。首先,让我们将日期转换为日期-时间对象,将日期-时间设置为数据框索引,并选择“打开”列:

df_AAPL = df_AAPL[['Date', 'Open']]
df_AAPL['Date'] = pd.to_datetime(df_AAPL['Date'])
df_AAPL.set_index('Date', inplace = True)
df_AAPL = df_AAPL['Open']

现在让我们使用 matplotlib 和 seaborn 绘图:

import seaborn as sns
import matplotlib.pyplot as pltsns.set()
plt.xlabel('Date')
plt.ylabel('Price')
df_AAPL.plot(style = 'k--')df_AAPL.rolling(window = 10).mean().plot(style = 'k')

我就说到这里,但是你可以随意使用我在这篇文章中提到的一些方法。尝试寻找额外的数据集,这些方法可以提供对数据趋势的有用见解。我也鼓励你探索 pandas 中的一些额外的计算工具,比如自定义函数应用、时间感知窗口、聚合等等。

概括地说,在这篇文章中,我讨论了 python pandas 库中可用的一些计算工具。我讲述了如何生成汇总统计数据,如熊猫系列之间的协方差和相关性,以及如何生成滚动统计数据,如累积和及滚动平均值。我希望这篇文章对你有用。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

掌握熊猫小组

原文:https://towardsdatascience.com/mastering-pandas-groupby-efc6600d093?source=collection_archive---------25-----------------------

了解 Groupby 方法

来源

Pandas 是一个 python 库,提供数据转换和统计分析工具。pandas 中的“groupby”方法允许我们对大量数据进行分组,并对这些组执行操作。在本帖中,我们将讨论如何在熊猫中使用“分组”方法。出于我们的目的,我们将使用全球冠状病毒数据集,它可以在这里找到。

我们开始吧!

首先,我们将名为“2019-nCoV-cases-JHU.csv”的文件读入一个熊猫数据框:

import pandas as pd 
df = pd.read_csv("2019-nCoV-cases-JHU.csv")

接下来,让我们打印前五行数据:

print(df.head())

为了简单起见,让我们将数据限制为仅包括美国的记录:

df = df[df['Region'] == 'US'] #filter to only include US data
df.reset_index(inplace = True) #reset index
del df['index'] # remove old index
print(df.head())

我们可能不需要考虑“省”的“未分配位置(来自钻石公主)”值,所以我们也把它去掉:

df = df[df['Province'] != 'Unassigned Location (From Diamond Princess)']
print(df.head())

现在,让我们通过提取“省”列中字符串值的最后两个字符来创建一个“州”列:

df['State'] = df['Province'].str[-2:]

我们可以做一些类似的事情来创建一个“县”列。让我们提取“省”列中字符串值的所有字符,不包括最后 4 个字符:

df['County'] = df['Province'].str[:-4]
print(df.head())

接下来,让我们将日期列转换成熊猫的“日期时间”:

df['Date'] = pd.to_datetime(df['Date'], format ='%m/%d/%Y %H:%M')

我们现在处于执行一些有趣的“分组”操作的有利位置。让我们在州级生成一些对应于数字列值的统计数据,如死亡、确诊病例和恢复。

为此,让我们首先在州级执行“分组”:

gb = df.groupby('State')

这里,我们创建了一个“groupby”对象。接下来我们可以做的是拉一个特定的组。我们可以使用“get_group”方法来实现这一点。让我们得到对应于 CA 的组,并将索引设置为日期:

df_ca = gb.get_group('CA').set_index('Date')
print(df_ca.head())

我们还可以迭代“groupby”对象,并为每个州创建一个包含一列的数据框:

deaths = pd.DataFrame()
for name, group in df.groupby('State'):
    if deaths.empty:
        deaths = group.set_index('Date')[["Deaths"]].rename(columns={"Deaths": name})
    else:
        deaths = deaths.join(group.set_index('Date')[["Deaths"]].rename(columns={"Deaths": name}))

让我们打印包含分组死亡统计数据的结果数据框:

print(deaths.head())

请注意,该数据包含有限数量的状态。我们还可以使用 describe 方法来获得关于新数据的基本统计信息:

death_stats = deaths.describe()
death_stats = death_stats.astype(int)
print(death_stats)

这里,计数对应于行数。我们还有死亡人数的平均值、标准差、百分位数、最小值和最大值。请注意,该数据中的最新记录对应于 2020 年 3 月 3 日,这是在病例大规模爆发之前。我们可以定义一个函数,为给定的数字列自动生成这些统计信息:

def get_statistics(column_name):
    column_df = pd.DataFrame()

    for name, group in df.groupby('State'):
        if column_df.empty:
            column_df = group.set_index('Date')[[column_name]].rename(columns={column_name: name})
        else:
            column_df = column_df.join(group.set_index('Date')[[column_name]].rename(columns={column_name: name}))

    column_df.fillna(0, inplace = True)    

    column_stats = column_df.describe()
    column_stats = column_stats.astype(int)
    print(column_stats)

让我们用“已确认”列作为输入来调用这个函数:

get_statistics("Confirmed")

并且恢复了:

get_statistics("Recovered")

我们也可以将索引设置为天数。让我们创建一个日列,并使用日编号作为索引为“已确认”列生成分组统计信息:

df['Day'] = df['Date'].dt.daydef get_statistics_day(column_name):
    column_df = pd.DataFrame()

    for name, group in df.groupby('State'):
        if column_df.empty:
            column_df = group.set_index('Day')[[column_name]].rename(columns={column_name: name})
        else:
            column_df = column_df.join(group.set_index('Day')[[column_name]].rename(columns={column_name: name}))

    column_df.fillna(0, inplace = True)    

    column_stats = column_df.describe()
    column_stats = column_stats.astype(int)
    print(column_stats)get_statistics_day("Confirmed")

这些是对应于各州每日确诊病例的统计数据。我就讲到这里,但我鼓励您继续研究代码和数据。例如,您可以尝试在县一级生成这些统计数据。您只需将“groupby('State ')”更改为“groupby('County ')”。

结论

总之,在这篇文章中,我们讨论了如何使用熊猫的“分组”方法。我们对冠状病毒引起的美国确诊病例、康复和死亡进行了分组统计。我们使用日期时间值和天数值作为索引来生成这些统计数据。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

掌握 Spark 3.0 中的查询计划

原文:https://towardsdatascience.com/mastering-query-plans-in-spark-3-0-f4c334663aa4?source=collection_archive---------1-----------------------

简单地说,Spark 查询计划。

在 Spark SQL 中,查询计划是理解查询执行细节的切入点。它携带了大量有用的信息,并提供了关于查询将如何执行的见解。这一点非常重要,尤其是在工作负载较重或者执行时间较长且成本较高的情况下。基于来自查询计划的信息,我们可以找出哪些是低效的,并决定重写部分查询以获得更好的性能。

对于不熟悉查询计划的人来说,乍一看,这些信息可能有点神秘。它有一个树形结构,每个节点代表一个操作符,提供一些关于执行的基本细节。官方的 Spark 文档在其他方面写得很好,信息量也很大,但在涉及到执行计划时就显得不够了。这篇文章的动机是提供一些熟悉的物理平面图,我们将参观一些最常用的运营商,并解释他们提供什么信息以及如何解释它。

这里介绍的理论主要基于对 Spark 源代码的研究,以及日常运行和优化 Spark 查询的实践经验。

基本示例设置

为了简单起见,让我们考虑一个查询,其中我们应用了一个过滤器,执行了一个聚合,并与另一个数据帧连接:

# in PySpark API:query = (
  questionsDF
  .filter(col('year') == 2019)
  .groupBy('user_id')
  .agg(
     count('*').alias('cnt')
  )
  .join(usersDF, 'user_id')
)

你可以以这样一种方式来考虑这个例子中的数据,即 usersDF 是一组用户,他们提出由 questionsDF 表示的问题。问题由栏划分,这是提出问题的年份。在查询中,我们对 2019 年问的问题感兴趣,对于每个用户,我们想知道他/她问了多少个问题。同样对于每个用户,我们希望在输出中有一些额外的信息,这就是为什么我们在聚合之后加入了 usersDF

有两种基本方法可以看到物理平面图。第一种是在显示计划文本表示的数据帧上调用解释功能:

Spark 3.0 在这方面有了一些改进,现在解释函数有了新的参数模式。该参数的值可以是下列值之一:格式化成本代码生成。使用格式的模式将查询计划转换为组织更好的输出(这里只显示了计划的一部分):

因此,在格式化的计划中,您可以看到“裸”树,它只有带括号的操作符名称。在树的下面,有一个由数字引用的每个操作符的详细描述。成本模式除了显示物理计划之外,还将显示优化的逻辑计划,以及每个操作员的统计数据,这样您就可以看到在不同的执行步骤中,数据大小的估计值。最后, codegen 模式显示了将要执行的生成的 java 代码。

查看计划的第二个选项是 Spark UI 中的 SQL 选项卡,其中列出了所有正在运行和已完成的查询。通过单击您的查询,您将看到物理规划的图形表示。在下面的图片中,我将图形表示与格式化的文本树结合起来,以查看它们是如何相互对应的:

这里的区别在于,图形表示的叶节点在顶部,根节点在底部,而文本树是颠倒的。

崩溃代码生成阶段

在物理计划的图形表示中,您可以看到操作符被分组到蓝色的大矩形中。这些大矩形对应于代号阶段。这是一个优化特性,发生在物理规划阶段。有一个名为 CollapseCodegenStages 的规则负责这一点,其思想是将支持代码生成的操作符合并在一起,通过消除虚函数调用来加速执行。不是所有的操作符都支持代码生成,所以有些操作符(例如交换)不是大矩形的一部分。在我们的例子中,有三个 codegen 阶段对应于三个大矩形,在格式化的计划输出中,您可以在操作符的括号中看到 codegen 阶段的 id 。同样从树中,你可以看出一个操作者是否支持代码,因为如果代码被支持,括号中会有一个对应阶段代码 id 的星号。

现在让我们简要描述一下如何解释查询计划中的每个操作符。

扫描拼花地板

Scan parquet 操作符表示从 parquet 文件格式中读取数据。从详细信息中,可以直接看到从源中将选择哪些列。尽管我们没有在查询中选择特定的字段,但是在优化器中有一个 ColumnPruning 规则将被应用,它确保只从源中选择那些实际需要的列。我们在这里还可以看到两种类型的过滤器:分区过滤器推送过滤器PartitionFilters 是应用于列的过滤器,数据源通过这些列在文件系统中进行分区。这些非常重要,因为它们允许跳过我们不需要的数据。检查过滤器是否在这里正确传播总是好的。这背后的想法是读取尽可能少的数据,因为 I/O 是昂贵的。在 Spark 2.4 中,还有一个字段 partitionCount ,它是实际扫描的分区数量,但是这个字段在 Spark 3.0 中不再存在。

另一方面, PushedFilters 是字段上的过滤器,可以直接推送到 parquet 文件,如果 parquet 文件按这些过滤的列排序,它们会很有用,因为在这种情况下,我们也可以利用内部 parquet 结构跳过数据。parquet 文件由行组组成,文件的页脚包含关于每个行组的元数据。该元数据还包含统计信息,例如每个行组的最小和最大,基于该信息,Spark 可以决定是否读取该行组。

过滤器

Filter 操作符非常直观易懂,它只是表示过滤条件。可能不太明显的是操作符是如何创建的,因为它通常不直接对应于查询中使用的过滤条件。原因是所有的过滤器首先由催化剂优化器处理,催化剂优化器可以修改和重新定位它们。在将逻辑过滤器转换为物理运算符之前,有几个规则应用于它们。让我们在这里列出一些规则:

  • PushDownPredicates 此规则将通过其他几个运算符(但不是所有运算符)将过滤器推至更靠近源的位置。例如,它不会通过不确定的表达式来推动它们。如果我们使用诸如第一个最后一个collect_setcollect_listrand (和其他一些)之类的函数,那么过滤器将不会被推过它们,因为这些函数在 Spark 中是不确定的。
  • CombineFilters 将两个相邻的运算符合并为一个运算符(它将两个后续筛选器中的条件收集到一个复合条件中)。
  • InferFiltersFromConstraints —该规则实际上创建了一个新的过滤器操作符,例如从一个连接条件(从一个简单的内部连接它将创建一个过滤条件连接关键字不为空)。
  • PruneFilters —删除多余的过滤器(例如,如果一个过滤器总是评估为)。

项目

该操作符只是表示将要投影(选择)的列。每次我们在数据帧上调用 selectwithColumn、drop 转换时, Spark 会将 Project 操作符添加到逻辑计划中,然后转换为物理计划中的对应项。同样,在转换之前,会对其应用一些优化规则:

  • ColumnPruning —这是我们上面已经提到的规则,它删除不需要的列,以减少将要扫描的数据量。
  • CollapseProject —它将相邻的项目操作符合并为一个。
  • PushProjectionThroughUnion —该规则将推动项目通过联合操作符的两侧。

交换

交换操作符代表 shuffle,这是集群上的物理数据移动。这种操作被认为是非常昂贵的,因为它通过网络移动数据。查询计划中的信息还包含有关如何对数据进行重新分区的详细信息。在我们的示例中,它是 hashpartitioning(user_id,200) ,如下所示:

这意味着数据将根据 user_id 列重新划分为 200 个分区,并且具有相同值 user_id 的所有行将属于同一个分区,并且将位于同一个执行器上。为了确保正好创建 200 个分区,Spark 将总是计算 user_id 的散列,然后计算模 200 的正数。这样做的结果是更多不同的 user_id 将位于同一分区中。还可能发生的情况是,一些分区可能会变空。还有其他类型的分区值得一提:

  • RoundRobinPartitioning —通过这种分区,数据将随机分布到 n 个大小大致相等的分区中,其中 n 由用户在 repartition(n) 函数中指定
  • SinglePartition —通过这种分区,所有数据都被移动到单个执行器的单个分区中。例如,当调用一个窗口函数时,该窗口成为整个数据帧(当您没有在窗口定义中为 partitionBy() 函数提供参数时)。
  • RangePartitioning —在调用了 orderBysort 转换之后,在对数据进行排序时使用这种分区。

哈沙格雷特

该运算符表示数据聚合。它通常由两个运算符组成一对,可能会也可能不会被一个交换所分割,正如您在此处看到的:

为了更好地理解这些情况下的交换背后的逻辑,您可以查看我以前关于 Spark SQL 中数据分布的文章,我在那里详细描述了它。使用两个 HashAggregate 操作符的原因是,第一个操作符执行部分聚合,分别聚合每个执行器上的每个分区。在我们的示例中,您可以在 Functions 字段中看到,它表示 partial_count(1) 。部分结果的最终合并在第二个散列集合中进行。操作员还有字段,显示数据分组所依据的列。结果字段显示了聚合后可用的列。

BroadcastHashJoin & BroadcastExchange

BroadcastHashJoin (BHJ) 是一个表示特定连接算法的运算符。除此之外,Spark 中还有其他可用的连接算法,如 SortMergeJoinShuffleHashJoin ,要了解更多,你可以查看我的另一篇关于 Spark 3.0 中连接的文章。 BHJ 总是与 BroadcastExchange 成对出现,BroadcastExchange 是一个代表广播洗牌的操作符——数据将被收集到驱动程序,然后发送到每个执行器,在那里它将可用于加入。

ColumnarToRow

这是 Spark 3.0 中引入的一个新操作符,它被用作列执行和行执行之间的过渡。

结论

Spark SQL 中的物理计划由携带关于执行的有用信息的操作符组成。对每个操作者有一个正确的理解可能有助于获得关于执行的洞察力,并且通过分析计划,我们可能发现什么不是最佳的,并且可能尝试修正它。

在本文中,我们描述了 Spark 物理计划中经常使用的一组操作符。这个集合决不是完整的,但是我们试图把重点放在常用的并且很可能出现在基本分析查询计划中的操作符上。

掌握随机森林:综合指南

原文:https://towardsdatascience.com/mastering-random-forests-a-comprehensive-guide-51307c129cb1?source=collection_archive---------9-----------------------

随机森林是每个数据科学家或机器学习工程师的工具包中应该拥有的最强大的算法之一。在本文中,我们将采用代码优先的方法来理解 sklearn 的随机森林所提供的一切!

库纳尔·辛德在 Unsplash 上拍摄的照片

决策树

为了理解随机森林,有必要了解它们是由什么构成的。决策树是所有基于树的算法的基础构件。其他所有基于树的算法都是复杂的决策树集合。因此,理解决策树的各个方面将是一个很好的起点。

根据“医疗预约数据集”训练的决策树[图片由作者提供]

由于决策树可以是任何深度(如果深度没有被明确指定),决策树倾向于过度适应每个数据点。这将导致 100%的准确性,但是该模型不会推广到它在训练期间没有看到的数据,因此在训练和验证准确性之间会有很大的差异。

训练数据集上的完美准确性[图片由作者提供]

测试数据集的准确性差[图片由作者提供]

决策树的基本思想是可靠的,但是由于缺乏模型复杂性,它们往往表现不佳。每个基于树的算法都试图通过增加额外的复杂性来解决这个问题。

随机森林

就像森林是树的集合一样,随机森林只是决策树的集合。在我们深入研究随机森林在机器学习中的相关性之前,让我们简单地讨论一下随机森林是如何工作的。

假设我们正在用 15 棵树构建一个随机的森林分类器。随机森林通过所有 15 棵树运行数据点。

每棵树的预测可以认为是一个‘投票’,投票数最多的类就是随机森林的预测。听起来很简单,对吗??这是最强大的机器学习算法之一,它的潜力是无穷的。

如何提高随机森林的性能:

sklearn 库提供的随机森林模型有大约 19 个模型参数。超参数调整时,我们需要调整的最重要的参数是:

  • n_estimators :随机森林中决策树的数量。
  • max_depth :每个决策树允许进行的分裂次数。如果分割数太低,模型会对数据进行欠拟合,如果分割数太高,模型会过拟合。一般来说,我们的最大深度是 3、5 或 7。
  • max_features :显示给每个决策树的列数。传递给每个决策树的特定特征在每个决策树之间会有所不同。
  • Bootstrap:Bootstrap 模型只需要选择列和行的子集来训练每个决策树。因此,模型变得不容易过度拟合数据。

注:通过应用 bootstrap,数据集被分为袋内和袋外(OOB)数据集。这消除了创建验证数据集的需要。

  • max_samples :如果 bootstrap 设置为 true,可以传递给每个决策树的最大行数由 max_samples 参数控制。

可用于超参数调整的建议参数网格:

好了,现在我们知道了如何建造一个随机森林,让我们来看看如何充分发挥它们的潜力!

随机森林的用途:

与许多其他机器学习算法不同,随机森林不仅可以用于预测能力。

  • 易于构建:

随机森林没有基于回归的算法或支持向量机那么多的模型假设。这使我们能够快速建立随机森林,以建立一个基础分数。

此外,即使没有超参数调整,随机森林也能提供一流的精度。与 XGBoost 等大型模型相比,超参数调整的过程要简单得多。

  • 特征重要性

sklearn 库提供的 Random Forest 类允许您获得数据集中每个列的特性重要性。这在与商业客户打交道时尤其有用。让我们通过考虑一个例子来进一步研究这个问题:

让我们假设我们的客户是一个虚构的房地产公司(XYZ 公司)。这家公司向我们提供了一个相对较小的数据集,记录了过去 5 年他们所在城市的所有销售情况,请求帮助他们将营销活动集中在正确的区域,并非常确定地预测房地产价格。他们提供的数据集中的要素是-买家的年龄、房产的位置、房产的土地面积、房屋/结构的年龄和房产的成本(因变量)

一个很好的方法是通过随机森林。我们必须从建立一个随机森林开始,然后调整上面提到的超参数。

接着,我们可以通过随机森林计算特征重要性,我们可以很容易地找出哪个特征对模型预测贡献最大。假设随机森林告诉我们最重要的特征是买家的年龄。有了这些信息,房地产公司现在就可以根据人们的年龄有针对性地开展营销活动。

来源

对于随机森林来说,整个过程需要几个小时才能完成,而对于其他特征选择算法(如 Boruta)或通过比较回归模型的单个斜率来说,同样的过程会非常乏味。

  • 功能选择

这可以认为是上一点的延伸。通过计算特征重要性,我们可以丢弃不太重要的特征,从而降低模型的维度,提高准确性并减少训练时间。

执行特征选择的另一种方式是递归地混洗数据集中的各个特征,使得它们丢失由该列提供的信息。在这个修改的数据集上评估该模型,以查看分数是如何被影响的。特征越重要,它对分数的影响就越深远。

结论

在本文中,我们广泛地研究了随机森林参数、超参数调优,以及在一个示例的帮助下,随机森林在业务用例中仍然非常重要的原因。

了解随机森林的其他来源:

掌握 Python 中的随机采样

原文:https://towardsdatascience.com/mastering-random-sampling-in-python-ac2df84b7d3f?source=collection_archive---------15-----------------------

在 Python 中使用随机模块

上由 Artem Beliaikin 拍照

Python 提供了许多有用的随机采样工具以及生成随机数的函数。随机抽样在统计学中有应用,在统计学中经常观察到人口的随机子集,并用于对整个人口进行推断。此外,随机数生成在科学中有许多应用。例如,在化学和物理中,蒙特卡罗模拟需要生成随机数。在本帖中,我们将讨论如何从列表中随机抽取项目,以及如何在 python 中生成伪随机数。

我们开始吧!

python 中的 random 模块有许多用于生成随机数和随机采样的函数。

使用“random.choice()”在列表中选择随机项目

考虑一下生活在农村地区的人们的身体质量指数价值观列表:

bmi_list = [29, 18, 20, 22, 19, 25, 30, 28,22, 21, 18, 19, 20, 20, 22, 23]

让我们使用' random.choice()'方法从列表中随机选择单个身体质量指数值:

import random 
print("First random choice:", random.choice(bmi_list))
print("Second random choice:", random.choice(bmi_list))
print("Third random choice:", random.choice(bmi_list))

如果我们再次运行这段代码,我们应该会得到另一组随机选择的 BMI:

使用“random.sample()”在列表中选取随机项目

“random.sample()”方法对于从列表中随机抽取 N 个项目非常有用。例如,如果我们想从我们的身体质量指数列表中抽取 N =5 个项目,我们执行以下操作:

print("Random sample, N = 5 :", random.sample(bmi_list, 5))

让我们试着对 10 件物品进行取样:

print("Random sample, N = 10:", random.sample(bmi_list, 10))

使用“random.shuffle()”随机排列列表中的项目

除了随机选择和采样之外,random 模块还有一个在列表中混排项目的功能。让我们打印我们的身体质量指数列表,然后打印改组我们的身体质量指数列表的结果:

print("BMI list: ", bmi_list)
random.shuffle(bmi_list)
print("Shuffled BMI list: ", bmi_list)

使用“random.randint()”生成随机整数

随机模块具有在给定值范围内生成随机整数的功能。让我们生成一个范围从 1 到 5 的随机整数:

print("Random Integer: ", random.randint(1,5))

使用这个函数,我们可以很容易地在 for 循环中生成一个随机整数列表:

random_ints_list = []
for i in range(1,50):
    n = random.randint(1,5)
    random_ints_list.append(n)
print("My random integer list: ", random_ints_list)

生成随机浮点值

随机模块还具有用于生成 0 和 1 之间的随机浮点值的功能:

print("Random Float: ", random.random())

我们还可以生成一个 0 到 1 之间的随机浮点数列表:

random_float_list = []
for i in range(1,5):
    n = random.random()
    random_float_list.append(n)
print("My random float list: ", random_float_list)

此外,我们可以缩放随机浮点数。如果我们想要 0 到 500 之间的随机数,我们只需将随机数乘以 500:

random_float_list = []
for i in range(1,5):
    n = random.random()*500
    random_float_list.append(n)
print("My random float list: ", random_float_list)

如果我们想添加一个下界,我们可以在追加之前添加一个条件语句。例如,为了生成 100 到 500 之间的随机数,我们执行以下操作:

random_float_list = []
for i in range(1,10):
    n = random.random()*500
    if n>=100.0:
        random_float_list.append(n)
print("My random float list: ", random_float_list)

用“random.uniform()”计算均匀分布的数

随机模块具有计算均匀分布数的功能。例如,要生成 50 个介于-10 和 1 之间的均匀分布的数,我们执行以下操作:

import numpy as np
uniform_list = np.random.uniform(-10,1,50)
print("Uniformly Distributed Numbers: ", uniform_list)

用“random.gauss()”计算正态分布数

最后,random 模块有一个计算正态分布数的函数。例如,要生成 50 个介于-50 和 0 之间的正态分布数,我们执行以下操作:

normal_list = np.random.uniform(-50,0,50)
print("Normally Distributed Numbers: ", normal_list)

我就讲到这里,但是我鼓励你自己去研究代码。

结论

总之,我们讨论了如何在 python 中从列表中随机选择和采样项目。我们展示了如何使用' random.choice()'方法从列表中随机选择一个条目。我们还使用了“random.sample()”方法,它允许您从列表中随机选择 N 个项目。我们还讨论了如何使用“random.shuffle()”方法对列表中的项目进行排序。此外,我们展示了如何使用 random 模块生成随机数。我们使用“random.randint()”生成随机整数,使用“random.random()”生成随机浮点值。最后,我们讨论了如何分别用“random.uniform()”和“random.gauss()”生成均匀分布和正态分布的数字。我希望你觉得这篇文章有用/有趣。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

掌握日常任务的正则表达式(Regex)

原文:https://towardsdatascience.com/mastering-regular-expressions-for-your-day-to-day-tasks-b01385aeea56?source=collection_archive---------51-----------------------

可以应用正则表达式(Regex)的用例数量是巨大的。无论您是收集数据的数据科学家、自动化业务流程的白领还是旨在从更大规模的学术期刊中提取数据的学生,Regex 都可能成为您最好的朋友。

想想万维网是一个难以置信的全面的(结构化的、半结构化的或相当非结构化的)数据来源,有趣的事实和数字经常保存在网页上,你可能会发现自己处于想要访问这些数据的情况。在大多数情况下是网页、软件提供商等。没有提供一个简单的 API 来访问或下载数据(免费),这就是为什么您可能想要找到一个定制的解决方案来自己获取数据。

这都是关于我的模式

这就是我们在快速阅读中处理正则表达式的方式

我经常发现阅读涉及正则表达式的文章,其中有简短的不相关的例子和解释,很难理解。我将尝试用不同的方式来处理这个话题:

  1. 提供一个非常简短和方便的正则表达式备忘单
  2. 快速浏览一下和他们如何完美地增强我们的模式
  3. 问题的定义,而不是给定模式的描述,例如“作为一个用户,我想找到所有数据,直到点”。“是达成了

为了让您对几个简单的正则表达式示例有个印象,我们将浏览一个丰富多彩的用例组合——无论我们去哪里,正则表达式都将允许我们掌握所有的请求。

我们为什么要这么做?数据分析和数据科学学科的进一步发展在很大程度上依赖于准确和干净的数据,正因为如此,清理和组织以及收集数据大约占数据科学专业的 80%! 对正则表达式的正确理解会让你的工作变得更容易。

涵盖大部分数据科学日常业务— 福布斯

你会在网上找到详尽的备忘单——我更喜欢在需要的时候准备好最常用的字符。如果你对这些很精通,你应该很容易就能适应写作模式:

感谢 cheatography

[## 最佳正则表达式备忘单

如果您处理文本,正则表达式是有用的,并且您将会体会到在 Linux 中通过锁定…

rumorscity.com](https://rumorscity.com/2014/08/21/best-regular-expressions-cheat-sheet/)

我们将重点介绍两个例子:

  1. 茶的历史 (tea_text)
  2. 足球成绩表

在我们开始之前,让我们先看看下面的小抄,然后是对团队的简短介绍。

组( )

在处理(部分)模式结果时,组是必不可少的。我经常避免使用组,但是这使得很难只提取相关数据。通过在模式中使用'('和')'定义组。组允许显式定位一组字符,即使该组嵌入在另一个模式中。
编程语言允许查询这些特定的组,然后
直接寻址它们。要概述分组的一般目的,请遵循以下示例,并确保您理解了这个想法:

“This is the day you will always remember as the day ***you almost caught***Captain Jack Sparrow”
“This is the day you will always remember as the day ***you have not caught*** Captain Jack Sparrow”
“This is the day you will always remember as the day ***you have caught*** Captain Jack Sparrow”
“This is the day you will always remember as the day ***you certainly have caught*** Captain Jack Sparrow”

杰克·斯派洛,抱歉,杰克·斯派洛船长或多或少经常被抓,但是我们想知道用了哪些确切的词。所以我们通过一个组来定义我们模式中的相关词。

通过我们的模式‘you \ s**(\ w * \ s ?\ w )【scat ed】我们能够提取位于我们确定的模式之间的值。
根据您使用的编程语言(我将使用 Python),实现正则表达式的语法会有所不同,但是思想总是相同的。如果您的模式找到一个匹配,您可以提取整个匹配,但也可以只提取单个组。方便!
现在,我们已经掌握了小组知识,让我们来看一下例子。

首先,我们从茶文开始。

Chinese small-leaf-type tea was introduced into India in 1836 by the British in an attempt to break the Chinese monopoly on tea.[57] In 1841, Archibald Campbell brought seeds of Chinese tea from the Kumaun region and experimented with planting tea in Darjeeling. The Alubari tea garden was opened in 1856 and Darjeeling tea began to be produced.[58] In 1848, Robert Fortune was sent by the East India Company on a mission to China to bring the tea plant back to Great Britain. He began his journey in high secrecy as his mission occurred in the lull between the Anglo-Chinese First Opium War (1839–1842) and Second Opium War (1856–1860).[59] .....
[57] Tea was originally consumed only by anglicized Indians; however, it became widely popular in India in the 1950s because of a successful advertising campaign by the India Tea Board.[57]

假设我们想从 tea 摘录中提取注释。为此,我们使用分组逻辑,只提取值,不提取括号——但是我们认为括号是识别注释所必需的,而不是接收任何一位或两位数。

pattern = “\[(\d{1,2})\]”
annotations = re.findall(pattern,tea_text)
**[‘57’, ‘58’, ‘59’, ‘57’, ‘57’]**

如果我们忽略组的用法,我们将获得文本中出现的注释——用括号括起来。

pattern = “\[\d{1,2}\]”
annotations = re.findall(pattern,tea_text)
**['[57]', '[58]', '[59]', '[57]', '[57]']**

可能需要提取所有时间跨度,因此我们不想提取例如 1836,但我们希望获得 1839–1842。

pattern = “\(\d*.\d*\)” # . could also be explicitly '-'
years = re.findall(pattern,tea_text)
**[’(1839–1842)’, '(1856–1860)’]**

更具体地说,我们可能希望提取已经能够定位的时间跨度的年份。为此,我们将极大地依赖于前面概述的群体观念。

pattern = “\((\d*).(\d*)\)” # year range
first_years = re.search(pattern,tea_text)
first_years.group(0) # **'(1839–1842)'**
first_years.group(1) # **'1839'**
first_years.group(2) # **'1842'**
first_years.groups() # **('1839', '1842')****## Iterating over all year spans is the easy part:**
single_years = []
for match in re.finditer(pattern,tea_info):
    if match:
        for i in range(len(match.groups())):
            single_years.append(match.group(i+1))single_years # **['1839', '1842', '1856', '1860']**

替换值

Regex 不仅是查找模式的好方法,也是替换模式的好方法。根据您使用的语言,regex 可用于通过您想要的字符串替换模式。当您希望避免替换为可能影响其他单词的多个值时,这一点特别有用,例如,将“is”替换为“was”可能会产生类似 Thwas…的单词

pattern = "(First.*\(\d{4}.\d{4}\))\s*and.(Second.*\(\d{4}.\d{4}\))" # using \s and . to show that results are the same here# Provides the following elements:
**[('First Opium War (1839–1842)', 'Second Opium War (1856–1860)')]**pattern = "First\sOpium\sWar"
replace_word = "1st Opium War"
re.sub(pattern,replace_word, tea_text) **# inplace modification !**#[..] between the Anglo-Chinese **1st Opium War** (1839–1842) and **Second Opium War** (1856–1860).

计数值

经常发生的次数是一个有趣的事实。可能出现的问题是,值可能是大小写组合的混合,这使得很难将这些值组合在一起。

pattern = “[Cc]hinese.(?=[tT]ea)” **# positive lookahead**
occ = len(re.findall(pattern,tea_text)) 
**# normally we would use re.IGNORECASE to achieve this result**
print(‘There are {} occurrences of "Chinese Tea"’.format(occ))**# There are 3 occurrences of "Chinese Tea"**

在第二个例子中,最近几场足球比赛的比分被捕获为一个字符串。目的是能够提取球队和他们的进球,一半和全部时间。一个潜在的用例可能是,应计算一个最终表。

鉴于以下比赛结果:

game_day = """
Juventus F.C.     -    Napoli                 4:1 (2:0)
A.C. Milan        -    Internazionale F.C.    2:2 (1:0)
A.C. Fiorentina   -    Torino                 1:0 (0:0)
Lazio             -    Atalanta               0:3 (0:2)
Lazio             -    Juventus F.C.          0:4 (0:2)
"""

有许多方法来提取球队名称和分数,标点空格和特殊字符,但更复杂的是找到一个适合所有人的解决方案。

想想这两种模式——或者想出一个更好的!

**# A more generic approach**
pattern = "
([A-Za-z][\w\.\s]*)-
([a-zA-Z\.\s]*)
(\d):(\d)\s*
\((\d):(\d)"**# A very tailored approach**
pattern = "(\w*\s?\w\.\w\.**|**\w\.\w\.\s*?\w*|\w*) **# note the OR |**
\s*-\s*
(\w*\s?\w\.\w\.|\w\.\w\.\s*?\w*|\w*)\s*
(\d):(\d)\s*\
((\d):(\d)"

乍一看,上面的陈述似乎很复杂,但事实并非如此。我使用了两种方法来实现几乎相同的结果,但是一种模式旨在反映我们的示例数据中指出的确切模式,另一种模式遵循一种更通用的方法。

在关注字母、括号和数字之前,让我们先看看图案的整体结构。
通过 '('')' 可以看出,有几个组允许我们从每个组中提取和寻址数据。如果我们只想使用一个队的名字和比分,或者只是半场比分,等等,这是特别方便的。我们进一步看到' - '和':【T10]',它们根据给定的数据让我们清楚地了解正则表达式的结构。

**Pattern 1 (group 1 and 2):**
**#generic:**
[a-zA-Z0–9\.\s]* **#or more precise:**
(\w*\s?\w\.\w\.|\w\.\w\.\s*?\w*|\w*)\s*

括号为我们提供了我们允许的字母和字符,这些可以是字母和点。在另一种情况下,我们指的是任何单词字符(\w),显式点(\。)和空格(\s)。
然后首先接近【a-zA-Z0–9】。\s]*读起来很棒,但是有一个警告,尾随空格将包含在我们的结果中— 所以要确保你的程序可以处理这些。第二种方法更加具体,完美地覆盖了我们的测试数据点——这里的警告是,确保没有团队可能没有被模式覆盖。
请注意,我们通过 OR (|)来分隔第二种方法中的模式,这是必要的,因为俱乐部名称中不包含 F.C .或 A.C.。虽然“更丑”,但我更喜欢更具体的版本。
下一组又是同样的模式,因为我们又在寻找足球队了。

Pattern 2 - the score:
(\d):(\d)\s*\ **# note: groups!**

简单地查询小数(数字),所以为最终分数。我们没有考虑出现次数的限制,但是为了避免问题,我们也可以使用量词:

(\d{,2}):(\d{,2})\s*\ 
# we don’t expect any team to score higher than 99 goals a game.Pattern 3:
\((\d):(\d)# Just repeats the second pattern, however excludes 
# the first bracket ‘\(‘.

为了提供一个可以用提取的值做什么的想法,我在下面创建了一个简单的“表格计算器”。这个计算器使用输入的球队和分数,并分配他们的分数。
如果我们在所有给定的比赛中使用这个正则表达式,我们最终可以计算出整个排行榜——只是一个想法:

还有更多的东西有待发现,我希望这几行文字能够激发您对 regex 的兴趣。

下次见,注意安全!

# Regex # Python #数据科学#6040 #CS6040

Python 中高效的根搜索算法

原文:https://towardsdatascience.com/mastering-root-searching-algorithms-in-python-7120c335a2a8?source=collection_archive---------25-----------------------

在 Python 中实现高效的寻根和优化搜索算法

照片由 Matteo GrandoUnsplash 上拍摄

作为数据科学家/计算机科学家,我们经常在日常生活中处理求根算法,不管我们是否意识到这一点。这些算法设计用于有效地定位特定值、局部/全局最大值或最小值的附近。

我们使用求根算法来搜索特定值、局部/全局最大值或最小值的近似值。

在数学中,当我们说求根时,通常意味着我们试图解一个方程组,使得f(X) = 0。这也使得求根算法成为非常有效的搜索算法。我们所要做的就是定义g(X) = f(X) — Y,其中Y是我们的搜索目标,然后求解X,使得g(X) = f(X) — Y = 0

主要有两类不同的方法:包围法(如二分法)和迭代法(如牛顿法、割线法、Steffensen 法等。).在这篇博客中,我们将探讨如何用 python 实现这些算法,并对它们进行相互比较(随意点击算法名称跳转到不同的部分):

  1. 二分法算法
  2. 雷古拉-法尔西算法
  3. 伊利诺伊算法
  4. 割线算法
  5. 斯蒂芬森算法

在我们开始之前,让我们假设我们有一个连续函数 f,并且我们想要搜索一个值y。也就是说,我们正在求解f(x) — y = 0

1.二分法

对分算法,或者更著名的是它的离散版本(二分搜索法)或树变体(二叉查找树),是一种在界限内搜索目标值的有效算法。正因为如此,这个算法也被称为寻找算法的根的包围法。

关键强度:

  • 保证以合理的速度收敛到目标值的鲁棒算法

关键弱点:

  • 需要了解根的近似面积,例如 3 ≤ π ≤ 4
  • 工作良好在近似区域中只有一个根

假设我们知道xf(a)f(b)之间,这就形成了搜索的括号。该算法将检查x是大于还是小于f((a + b) / 2),后者是支架的中点。

需要一个误差范围来检查支架的中点。当搜索一个连续函数时,我们可能永远无法定位精确的值(例如定位π的末端)。当计算值足够接近目标值时,可以将误差幅度视为提前停止。例如,如果误差幅度为 0.001%,则 3.141624 非常接近π,大约为 3.1415926…

如果计算值足够接近目标值,则搜索完成,否则,如果x < f((a + b) / 2),则搜索下半部分的值,反之亦然。

2.错误位置算法

就像二分法一样,Regula Falsi 也使用一种包围式方法。然而,与二分法不同,它不使用每次迭代将问题空间一分为二的强力方法。相反,Regula Falsi 迭代地绘制从f(a)f(b)的直线,并且将截距与目标值进行比较。然而,不能保证搜索效率总是得到提高。例如,下图显示了只有下限以减少的速率增加,而上限仍然是一个停滞的界限

停滞的界限减缓了收敛。图片作者。

关键强项:

  • 通常比二分法收敛更快

Regula Falsi 利用了随着括号变小,连续函数将收敛到一条直线。

关键弱点:

  • 当算法遇到停滞边界时,收敛变慢
  • 需要了解根的近似面积,例如 3 ≤ π ≤ 4

Regula Falsi 和等分之间的关键区别在于c不再是ab之间的中点,而是被计算为:

3.伊利诺伊算法(修正的雷古拉-法尔西)

为了通过停滞边界,我们可以添加一个条件规则,当一个边界在两轮中保持停滞时。就拿前面的例子来说,由于b已经两轮没有移动,而且c还没有靠近根x,所以在下一轮,线将被划到f(b) / 2而不是f(b)。如果下界是停滞的,这同样适用于下界。

Illinois 算法避免了长时间停滞边界,加快了收敛速度。图片作者。

关键强度:

  • 通常比二分法和正则法收敛得更快
  • 通过将停滞边界到目标值的距离减半来避免停滞边界

关键弱点:

  • 当算法遇到停滞边界时,收敛变慢
  • 需要了解根的近似面积,例如 3 ≤ π ≤ 4

4.割线法(拟牛顿法)

到目前为止,我们一直在实施支架方法。如果我们不知道括号在哪里,怎么办?那么割线法会非常有用。割线法是一种迭代算法,从两个估计值开始,并试图向目标值收敛。虽然我们可以在算法收敛时获得更好的性能,并且我们也不需要知道根的粗略位置,但是如果两个初始估计值离实际根太远,我们可能会遇到发散的风险。

关键强度:

  • 不需要包含根的括号
  • 不需要知道根的大致面积

关键弱点:

  • 与所有以前的方法不同,割线不能保证收敛

基于 x1 和 x2 定位 x3 的割线法。鸣谢:维基百科

这个方法从检查两个用户定义的种子开始,假设我们想从x_0=4x_1=5开始搜索x² — math.pi=0的根,那么我们的种子是 4 和 5。(注意,这与搜索x相同,因此x²=math.pi)

然后,我们像在 Regula-Falsi 中所做的那样,通过画一条穿过f(x_0)f(x_1)的直线来定位目标值为x_2的截距。如果f(x_2)没有足够接近目标值,我们重复该步骤并定位x_3。一般来说,下一个x可以计算为:

5.斯特芬森方法

割线的方法进一步改进了 Regula-Falsi 算法,去掉了对包含根的括号的要求。回想一下,直线实际上只是两个x值(或 Regula-Falsi 和 Illinois 算法中的上下限)的切线(即导数)的简单估计。随着搜索的收敛,这种估计将更加准确。在 Steffensen 的算法中,我们将尝试用对导数的更好的估计来代替直线,以进一步改进割线法。

关键强项:

  • 不需要包含根的括号
  • 不需要知道根的大致面积
  • 如果可能的话,比正割法收敛得更快

关键弱点:

  • 如果初始种子离实际根太远,则不能保证收敛
  • 为了更好地估计导数,连续函数的计算将是正割方法的两倍

为了更好地估计导数,Steffenson 的算法将根据用户定义的初始种子x_0计算如下。

这相当于下面的公式,其中 h = f(x) :

取 h 的极限为 0,你将得到 f(x)的导数

然后,广义估计斜率函数将用于定位与割线法相似的下一步:

结论

在博客中,我们讨论了以下 5 种求根算法的优点、缺点和实现:

  1. 二分法
  2. Regula-Falsi 算法
  3. 伊利诺伊算法
  4. 割线算法
  5. 斯特芬森算法

我们已经实现的算法的比较

一旦你熟悉了这些算法,不要止步于此。实际上有更多的求根算法我们没有在这个博客中介绍,例如,牛顿-拉夫森法,逆二次插值法,布伦特法等。继续探索并将这些算法添加到您的工具库中。

注意上面的片段都是我自己写的,没有经过彻底的测试。我强烈建议您尝试一下,并以此为起点来修改您自己的用例。记住!在部署之前进行测试!它能在我的环境中工作并不意味着它能在所有的设置中工作!

再见!

在你走之前

您可能还想查看这些中型博客,了解如何改进您的数据科学游戏:

[## 熊猫数据帧上的高效条件逻辑

是时候停止过于依赖。iterrows()和。应用()

towardsdatascience.com](/efficient-implementation-of-conditional-logic-on-pandas-dataframes-4afa61eb7fce) [## Jupyter 的 Cookiecutter 插件:轻松组织你的数据科学环境

一个 Jupyter 扩展,帮助一键组织项目文件夹

towardsdatascience.com](/cookiecutter-plugin-for-jupyter-easily-organise-your-data-science-environment-a56f83140f72)

如果你从这里学到了新的东西,请告诉我!也请让我知道我是否还遗漏了其他一些巧妙的技巧!

[## Louis Chan-FTI Consulting | LinkedIn 数据科学总监

雄心勃勃的,好奇的和有创造力的个人,对分支知识和知识之间的相互联系有强烈的信念

www.linkedin.com](https://www.linkedin.com/in/louis-chan-b55b9287)

用熊猫掌握统计学

原文:https://towardsdatascience.com/mastering-statistics-with-pandas-ce7580971072?source=collection_archive---------24-----------------------

用熊猫来生成统计数据

来源

Pandas 是一个 python 库,可用于数据操作、数据插补、统计分析等等。具体来说,Pandas 统计函数对于从数据中获得洞察力非常有用。在本帖中,我们将回顾一些从数据中生成统计数据的基本方法。

出于我们的目的,我们将使用粮农组织的化肥副产品数据,这些数据可以在这里找到。这些数据包含了全世界化学和矿物肥料的生产、贸易和农业使用的信息。

我们开始吧!

首先,让我们将数据读入熊猫数据框:

import pandas as pddf = pd.read_csv("FertilizersProduct.csv",encoding = "ISO-8859-1")

接下来,让我们打印一些关于数据的基本信息:

print(df.info())

我们看到该数据包含 11 个整型、浮点型和分类类型的列。现在,让我们打印前五行数据:

print(df.head())

我们看到第一行数据对应的是 2011 年阿富汗进口的 4.49 吨无水氨。让我们继续考虑阿富汗的所有数据:

df_afghanistan = df[df['Area'] == 'Afghanistan'].copy()

接下来,我们可以用'来看数量值的分布。“hist()”方法:

import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
plt.title("Distribution in Imported Fertilizer Quantities")
df_afghanistan['Value'].hist(bins=30)

此外,使用'查看以吨为单位的平均进口数量。“mean()”方法:

print("Average Quantity: ", df_afghanistan['Value'].mean())

我们还可以使用'来查看数量的标准偏差。“std()”方法:

print("Standard Deviation in Quantity: ", df_afghanistan['Value'].std())

我们也可以使用。corr()'方法来计算两个数值列之间的相关性。让我们计算一下阿富汗的化肥数量和年份之间的关系:

print("Correlation between Year and Quantity: ", df_afghanistan['Value'].corr(df_afghanistan['Year'])

我们还可以看看最小值和最大值:

print("Minimum Quantity: " df_afghanistan['Value'].min())
print("Maximum Quantity: " df_afghanistan['Value'].max())

接下来,我们可以查看分类列中最频繁出现的值或模式。让我们计算原始数据中“面积”列的模式:

print("Mode in Area: ", df['Area'].mode()[0])

我们还可以使用“Counter()”方法来可视化分类值出现的频率。让我们将“Counter()”方法应用于原始数据中的“Item”列:

from collections import Counter
print(Counter(df['Item']))

现在,让我们生成一个柱状图来直观显示这一点:

plt.title("Frequency in Fertilizer Items")
plt.bar(dict(Counter(df['Item'])).key(), dict(Counter(df['Item'])).Values())

我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。

结论

总之,在这篇文章中,我们讨论了如何使用 Pandas 库从数据中生成基本的统计见解。我们看了如何使用 pandas 方法计算平均值、标准差、相关性、最小值和最大值。此外,我们可视化了数值列中的分布,并使用 counter 方法和 Matplotlib 来可视化分类“Item”列中的分布。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

掌握熊猫的弦乐方法

原文:https://towardsdatascience.com/mastering-string-methods-in-pandas-8d3cd00b720d?source=collection_archive---------22-----------------------

开始时你需要知道的

像素上的摄影记者拍摄的照片

Pandas 是一个流行的 python 库,它提供了易于使用的数据结构和数据分析工具。熊猫可以用于读入数据、生成统计数据、聚合、机器学习的特征工程等等。Pandas 库还提供了一套字符串/文本操作工具。

在本帖中,我们将介绍熊猫提供的一些最重要的字符串操作方法。

我们开始吧!

首先,让我们导入熊猫库

import pandas as pd

现在,让我们定义一个包含字符串的示例熊猫系列:

s = pd.Series(['python is awesome', 'java is just ok', 'c++ is overrated'])

让我们打印这个系列:

print(s)

我们注意到该系列有“dtype: object”,这是自动推断的默认类型。一般来说,最好是专用型的。自从熊猫 1.0 发布以来,我们现在能够指定专用类型。通过在终端中执行以下命令来确保 Pandas 得到更新:

pip install -U pandas

我们可以如下指定“dtype: string ”:

s1 = pd.Series(['python is awesome', 'java is just ok', 'c++ is overrated'], dtype='string')

让我们打印系列:

我们可以看到系列类型是指定的。最好指定类型,不要使用默认的“dtype: object ”,因为它允许类型的意外混合,这是不可取的。例如,使用“dtype: object ”,您可以拥有一个包含整数、字符串和浮点数的序列。因此,“dtype: object”的内容可能是模糊的。

接下来,我们来看看一些具体的字符串方法。让我们考虑一下“count()”方法。让我们为这个例子修改一下我们的系列:

s = pd.Series(['python is awesome. I love python.', 'java is just ok. I like python more', 
                'c++ is overrated. You should consider learning another language, like java or python.'], dtype="string")

让我们打印新系列:

print(s)

让我们统计一下单词“python”在每个字符串中出现的次数:

print(s.str.count('python'))

我们看到这将返回一系列“dtype: int64”。

我们可以考虑的另一种方法是“isdigit()”方法,该方法根据字符串是否是数字来返回布尔序列。让我们定义一个新系列来演示这种方法的使用。假设我们有一个由字符串数字列表定义的序列,其中缺少的字符串数字的值为“未知”:

s2 = pd.Series(['100', 'unknown', '20', '240', 'unknown', '100'], dtype="string")

如果我们使用' isdigit()'方法,我们会得到:

print(s2.str.isdigit())

我们还可以使用“match()”方法来检查特定字符串的存在。让我们检查字符串“100”是否存在:

print(s2.str.match('100'))

我们甚至可以检查“un”的存在:

print(s2.str.match('un'))

所有这些都符合我们的预期。我们还可以使用方法来改变我们的系列字符串文本的大小写。让我们回到包含不同编程语言观点的系列,s1:

s1 = pd.Series(['python is awesome. I love python.', 'java is just ok. I like python more', 
                'c++ is overrated. You should consider learning another language, like java or python.'], dtype="string")

我们可以使用“upper()”方法来大写我们系列中的字符串中的文本:

s_upper = s1.str.upper()print(s_upper)

我们还使用“lower()”方法:

s_lower = s_upper.str.lower()print(s_lower)

我们还可以使用' len()'获得每个字符串的长度:

print(s1.str.len())

让我们考虑几个更有趣的方法。我们可以使用' strip()'方法来删除空白。为此,让我们定义并打印一个新的示例序列,其中包含带有多余空格的字符串:

s3 = pd.Series([' python', 'java', 'ruby ', 'fortran '])
print(s3)

正如你所看到的,在‘python’的左边和‘ruby’和‘fortran’的右边都有空白。我们可以用“strip()”方法来删除它:

print(s3.str.strip())

我们也可以用“lstrip”删除左边的空白:

print(s3.str.lstrip())

右边是“rstrip”:

print(s3.str.rstrip())

在前两个例子中,我使用的是“dtype=object ”,但是,如果您使用的是字符串,请尽量记住指定“dtype=strings”。

您也可以使用 strip 方法删除文本中不需要的字符。通常情况下,在真实的文本数据中会出现' \n ',它表示新的一行。让我们修改我们的系列,并在这种情况下演示 strip 的使用:

s3 = pd.Series([' python\n', 'java\n', 'ruby \n', 'fortran \n'])
print(s3)

我们可以用' strip()'删除' \n '字符:

print(s3.str.strip(' \n'))

在这个具体的例子中,我想指出“dtype=object”和“dtype= strings”之间的行为差异。如果我们指定“dtype= strings”并打印系列:

s4 = pd.Series([' python\n', 'java\n', 'ruby \n', 'fortran \n'], dtype='string')
print(s4)

我们看到' \n '已被解释。尽管如此,在新指定的系列上使用“strip()”仍然有效:

print(s4.str.strip(‘ \n’))

我们要看的最后一个方法是“replace()”方法。假设我们有一个新系列,其美元金额的格式很差:

s5 = pd.Series(['$#1200', 'dollar1,000', 'dollar10000', '$500'], dtype="string")
print(s5)

我们可以使用' replace()'方法去掉第一个元素中不需要的' # ':

print(s5.str.replace('#', ''))

我们也可以用一个实际的' $ '符号替换文本' dollar ':

s5 = s5.str.replace('dollar', '$')
print(s5)

最后,我们可以删除第二个元素中的',':

s5 = s5.str.replace(',', '')
print(s5)

我将在这里停下来,但是您可以随意使用这些方法。你可以尝试将 Pandas 的一些方法应用于免费的数据集,比如可以在 Kaggle 上找到的 Yelp亚马逊评论,或者应用于你自己的工作,如果它涉及处理文本数据的话。

总之,我们讨论了一些基本的 Pandas 字符串操作方法。我们回顾了基于特定字符串的存在生成布尔序列,检查字符串中数字的存在,删除不需要的空白或字符,并用选择的字符替换不需要的字符。

还有很多熊猫字符串方法我没有在这篇文章中介绍。这些方法包括连接、索引、提取子字符串、模式匹配等等。我将把这些方法留到以后的文章中。我希望你觉得这篇文章有趣和/或有用。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

掌握 Python 中的字符串方法

原文:https://towardsdatascience.com/mastering-string-methods-in-python-456174ede911?source=collection_archive---------14-----------------------

使用本指南,通过应用修改、转换和格式化字符串的方法,增长您对这种编程语言的知识。

照片由 克里斯蒂娜·莫里洛 发自 像素

“学习编写程序可以拓展你的思维,帮助你更好地思考,创造一种思考问题的方式,我认为这对所有领域都有帮助。”
—比尔·盖茨

正如微软的联合创始人所说,我邀请你继续拓展你的思维,努力拓宽你的编程技能,在许多领域有潜在的应用。这篇文章的目的是作为一个基本 Python 数据类型的内置方法的备忘单。字符串是 Python 编程语言中的一种数据类型,用于表示一段文本。它们非常灵活,并且对于在代码中恰当地表示文本输入是必要的。因此,学习如何充分利用它们是必须的。

一旦学会了这些数据类型的基本语法,你就可以开始增长你的 Python 知识,这将让你对字符串处理进行越来越有趣的操作。永远记住,学习过程的主要目标是编写干净高效的代码来自动化日常任务,不需要记忆任何方法,因为一旦你将它们付诸实践,你就会完全理解它们。

目录:

1.弦乐入门(3 分钟阅读)。

2.修改字符串(2 分钟读取)。

3.转换字符串(2 分钟读取)。

4.格式化字符串(1 分钟读取)。

1.弦乐简介

一个字符串是一种 Python 数据类型,用于表示一段文本。它写在双引号或单引号之间,可以短到零个字符,也可以是空字符串,也可以是您希望的长度。

字符串可以使用加号连接以构建更长的字符串,也可以将它们乘以一个数字,这导致字符串连续重复数字指示的次数。此外,如果我们想找出字符串的长度,我们只需使用 len ()函数,如下例所示:

我们可以在脚本中用字符串做很多事情。例如,我们可以通过查看文件名并查看它们是否符合我们的标准来检查文件是否以某种方式命名,或者我们可以通过检查我们系统的用户并连接我们的域来创建电子邮件列表:

电子邮件生成器功能

此外,我们可以访问字符串中的一个特定字符或一段字符。例如,如果我们有一个太长而无法显示的文本,并且我们想只显示它的一部分,我们可能想要这样做。或者如果我们想用短语中每个单词的第一个字母来缩写。我们可以通过一个叫做字符串索引的操作来实现。该操作让我们使用方括号和我们想要的位置号来访问给定位置或索引中的字符,如下例所示:

如果想打印一个字符串的最后一个字符,但不知道它有多长,怎么办?使用负索引可以做到这一点。在上面的例子中,我们不知道字符串的长度,但是我们知道单词' text '加上感叹号取五个索引,所以我们调用负五来访问它们。

记住 Python 是从 0 而不是 1 开始计算索引的。就像 range 函数一样,它会考虑第一个数字和比最后一个数字小一的数字之间的值的范围。

2.修改字符串:

除了尝试访问字符串中的某些字符之外,我们可能希望更改它们,以防它们不正确并且我们希望修复它,或者万一我们希望传达不同的东西。

切片对这个没有用,因为字符串是不可变的数据类型,就 Python 而言,这意味着它们不能被修改。我们能做的是基于旧字符串创建一个新字符串:

我们不会改变之前分配给它的底层字符串。我们赋予一个全新的字符串不同的内容。在这种情况下,很容易找到要更改的索引,因为字符串中的字符很少。如果字符串变大了,我们怎么知道要改变哪个字符呢?

为了实现我们的目标,我们将使用 index 方法,这是一个与特定类相关联的函数,当附加到一个点后面的变量时,它为某个函数服务。

具体来说, index 方法返回给定子串在字符串中的索引。我们传递的子串,可以根据我们的需要长短。如果这个字符串没有我们正在寻找的子字符串,会发生什么呢?index 方法不能返回一个数字,因为子串不存在,所以我们得到一个值错误:

为了避免这种回溯错误,我们可以使用中的关键字来检查一个子串是否包含在一个字符串中。这个关键字也用于循环的,正如我在这篇关于 Python 循环的上一篇文章中所解释的。

在循环的情况下,它用于迭代,而在这种情况下,它是一个条件,可以是如果子串是字符串的一部分,则为 true,否则为 false

3.转换字符串

有很多有趣的方法来转换我们的字符串文本。在那些更重要的方法中,我们可以找到 lower()upper()、strip()、count()join() 方法。

在处理用户输入时, strip() 方法很有用,因为它去掉了字符串中的空格。这意味着它不仅删除了空格,还删除了制表符和换行符,这些都是我们通常不希望在用户提供的字符串中出现的字符。

这个方法还有两个版本, lstriprstrip ,分别消除字符串左边或右边的空白字符,而不是两边。

其他方法给你关于字符串本身的信息。方法 count 返回给定的子串在一个字符串中出现的次数。方法 endswith 返回字符串是否以某个子串结尾,而方法 startswith 返回字符串是否以某个子串开头:

另一种连接形式是应用 join 方法。要使用 join 方法,我们必须在将要用于连接的字符串上调用它。在这个例子中,我们使用了一个带有空格的字符串。该方法接收字符串列表,并返回一个字符串,每个字符串由初始字符串连接。让我们用一个简单的例子来检查它的功能:

最后,字符串的一个重要应用是 split 方法,它返回初始字符串中所有单词的列表,并自动按任何空格进行拆分。它可以选择接受一个参数,并用另一个字符(如逗号或点号)分割字符串:

4.格式化字符串

String 对象具有进行格式更改的内置功能,其中还包括连接字符串的额外方式。让我们来看看:

在上面的例子中,我基于两个已经创建的变量的输入值生成了一个新的字符串,通过使用花括号占位符来显示变量应该写在哪里。然后,我将变量作为参数传递给 format 方法。

另一方面,我们可能希望格式化浮点变量的数字输出。例如,在含税产品的情况下:

在本例中,在花括号之间,我们正在编写一个格式化表达式。当我们想要告诉 Python 以不同于默认的方式格式化我们的值时,这些表达式是需要的。表达式以冒号开头,以区别于我们之前看到的字段名。在冒号后面,我们写“ .2f ”。这意味着我们要格式化一个浮点数,小数点后应该有两位数字。所以不管价格是多少,我们的函数总是打印两位小数。

您也可以使用大于运算符来指定文本对齐方式: > 。例如,表达式 {: > 3.2f} 将文本向右对齐三个空格,并指定一个带两位小数的浮点数。

结论

在本文中,我提供了大量的字符串数据类型指南,包括一些方法和实际应用,以及相应的理论解释。当然是很多附加的方法!但是没有必要记住它们,因为一旦你把概念付诸实践,你就会完全理解它们。

在未来的系列文章中,我将深入探讨其他 Python 数据类型的更重要的方法。如果你喜欢这篇文章中的信息,不要犹豫,联系我分享你的想法。它激励我继续分享!

深入了解 Python 编程的相关文章:

理解 Python 中的循环:

[## 用一篇文章理解 Python 中的循环

读完这篇文章后,你将不再有机会被 Loops 抛出。

towardsdatascience.com](/understand-loops-in-python-with-one-article-bace2ddba789)

创建股票价格模拟器:

[## 用 Python 创建股票价格模拟器

几何布朗运动过程的简单应用来模拟股票价格。

towardsdatascience.com](/create-a-stock-price-simulator-with-python-b08a184f197d)

了解如何用 Python 编写令人惊叹的可视化代码:

[## 用 Python 实现商业智能可视化

我准备了一份详尽的指南来展示漂亮的可视化效果,以增强度量、KPI、预测和其他…

towardsdatascience.com](/business-intelligence-visualizations-with-python-1d2d30ce8bd9)

使用 Python 的电子商务数据科学:

[## 使用 Python 的电子商务数据科学

我为电子商务行业准备了一份广泛的数据科学应用指南。

towardsdatascience.com](/data-science-for-e-commerce-with-python-a0a97dd7721d) [## irbnb 租赁-使用 Python 分析纽约

towardsdatascience.com](/airbnb-rental-analysis-of-new-york-using-python-a6e1b2ecd7dc)

感谢您花时间阅读我的文章!如果您有任何问题或想法要分享,请随时联系我的电子邮件,或者您可以在以下社交网络中找到我以了解更多相关内容:

用熊猫掌握汇总统计

原文:https://towardsdatascience.com/mastering-summary-statistics-with-pandas-d515e17756be?source=collection_archive---------15-----------------------

使用 Pandas 库生成汇总统计数据

照片由安德鲁·尼尔像素上拍摄

Pandas 是一个 python 库,用于数据操作和统计分析。这是一个快速易用的开源库,支持多种数据操作任务。这些包括合并、重塑、争论、统计分析等等。在本帖中,我们将讨论如何使用 Pandas 库计算汇总统计数据。

我们开始吧!

出于我们的目的,我们将探索网飞、Prime Video、Hulu 和 Disney Plus 数据集上的电影。数据可以在这里找到。

我们开始吧!

首先,让我们将数据读入熊猫数据框:

import pandas as pd 
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
df = pd.read_csv("MoviesOnStreamingPlatforms_updated.csv")

接下来,我们将打印该数据中可用的列:

print(df.columns)

我们不需要“Unamed: 0”列,所以我们可以用“del”关键字删除它:

del df['Unnamed: 0’]

现在,让我们使用“head()”方法打印前五行数据:

print(df.head())

计算平均值、标准差、中值、最大值和最小值

我们要看的第一个方法是 Pandas 的“mean()”方法。让我们显示平均 IMDb 评级:

print("Mean IMDb Rating: ", df['IMDb'].mean())

我们可以使用 Numpy 'round()'方法将平均值四舍五入到最接近的十分之一:

import numpy as np
print("Mean IMDb: ", np.round(df['IMDb'].mean(), 1))

我们还可以显示“IMDb”列的标准偏差、中值、最大值和最小值:

print("Standard Deviation in IMDb Rating: ", np.round(df['IMDb'].std()))
print("Median IMDb Rating: ", np.round(df['IMDb'].median(), 1))
print("Max IMDb Rating: ", df['IMDb'].max())
print("Min IMDb Rating: ", df['IMDb'].min())

为了方便起见,我们可以编写一个函数,给出任意数字列的汇总统计信息:

def get_statistics(column_name):
    df_copy = df.copy()
    print(f"Mean {column_name}: ", np.round(df_copy[column_name].mean(), 1))
    print(f"Standard Deviation in {column_name}: ", np.round(df_copy[column_name].std()))
    print(f"Median {column_name}: ", np.round(df_copy[column_name].median(), 1))
    print(f"Max {column_name}: ", df_copy[column_name].max())
    print(f"Min {column_name}: ", df_copy[column_name].min())

如果我们用“IMDb”调用我们的函数,我们得到如下结果:

get_statistics('IMDb')

让我们调用“运行时”列中的函数:

get_statistics('Runtime')

最后,让我们试试“烂番茄”专栏:

get_statistics('Rotten Tomatoes')

我们得到以下错误:

很明显我们需要分开处理这个案子。如果我们打印“烂番茄”值的前五行,我们会看到这些值是字符串:

print(df[‘Rotten Tomatoes’].head())

在我们的函数中,我们可以检查“列名”输入是否为“烂番茄”。如果是,我们在计算汇总统计信息之前,删除“%”符号并将字符串转换为浮点型:

def get_statistics(column_name):
    df_copy = df.copy()
    if column_name == 'Rotten Tomatoes':
        df_copy[column_name] = df[column_name].str.rstrip('%')
        df_copy[column_name] = df_copy[column_name].astype(float)
        ...

现在我们可以用“烂番茄”来调用我们的函数:

get_statistics('Rotten Tomatoes')

使用“describe()”方法

我们可以使用 describe 函数来生成上面的统计信息,并将其同时应用于多个列。它还提供了下限、中间值和上限。让我们将“describe()”方法应用于“IMDb”和“运行时”:

print(df[['IMDb', 'Runtime']].describe())

如果我们想在这些统计数据中包含“烂番茄”,我们需要像前面一样将其转换为浮点型:

df['Rotten Tomatoes'] = df['Rotten Tomatoes'].str.rstrip('%')
df['Rotten Tomatoes'] = df['Rotten Tomatoes'].astype(float)
print(df[['IMDb', 'Runtime', 'Rotten Tomatoes']].describe())

使用“groupby()”进行聚合

假设我们想知道每个流派的平均运行时间。我们可以使用“groupby()”方法来计算这些统计数据:

runtime_genre = df[["Genres", "Runtime"]].groupby("Genres").mean()
print(runtime_genre.head())

我们也可以按“国家”来看平均“烂番茄”:

rottentomatoes_country = df[["Country", "Rotten Tomatoes"]].groupby("Country").mean().dropna()
print(rottentomatoes_country.head())

最后,我们可以编写一个函数,允许我们对任何分类列和数字列重复使用这个逻辑:

def get_group_statistics(categorical, numerical):
    group_df = df[[categorical, numerical]].groupby(categorical).mean().dropna()
    print(group_df.head())

让我们用“流派”和“运行时”来调用我们的函数:

get_group_statistics('Genres', 'Runtime')

我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。

结论

总之,在这篇文章中,我们讨论了如何使用 Pandas 库生成汇总统计数据。首先,我们讨论了如何使用 pandas 方法生成均值、中值、最大值、最小值和标准差。我们还实现了一个函数,该函数在给定一个数字列名的情况下生成这些统计信息。接下来,我们讨论了“describe()”方法,该方法允许我们为任何数字列生成除平均值、中值、最大值、最小值和标准偏差之外的百分位数。最后,我们展示了如何为分类列生成聚合统计信息。如果你有兴趣学习更多关于熊猫的数据操作、机器学习甚至只是 python 编程的一些基础知识,请查看Python for Data Science and Machine Learning:Python 编程、熊猫和 Scikit-初学者学习教程 。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

通过 5 个简单的步骤掌握 TensorFlow 张量

原文:https://towardsdatascience.com/mastering-tensorflow-tensors-in-5-easy-steps-35f21998bb86?source=collection_archive---------7-----------------------

← Part 1 |深度学习用 TensorFlow 2。X —第 2 部分| 第 3 部分→ | 第 4 部分→

了解 TensorFlow 的构建模块如何在底层工作,并了解如何充分利用张量对象|使用 TensorFlow 2.x 进行深度学习

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

照片由 Esther JiaoUnsplash 拍摄

在本帖中,我们将深入 TensorFlow 张量的细节。我们将通过这五个简单的步骤涵盖 Tensorflow 中与张量相关的所有主题:

  • 第一步:张量的定义→ 什么是张量?
  • 步骤二:创建张量→ 创建张量对象的函数
  • 第三步:张量的资格→ 张量对象的特性和特征
  • 步骤四:张量运算→ 索引、基本张量运算、形状操作和广播
  • 第五步:特殊张量类型→ 除常规张量以外的特殊张量类型

开始吧!

张量的定义:什么是张量?

图一。秩 3 张量的可视化(作者提供图片)

张量是 TensorFlow 的多维数组,类型统一。它们非常类似于 NumPy 数组,并且是不可变的,这意味着它们一旦创建就不能被更改。您只能使用编辑内容创建新副本。

让我们看看张量如何与代码示例一起工作。但是首先,要使用 TensorFlow 对象,我们需要导入 TensorFlow 库。我们经常在 TensorFlow 中使用 NumPy ,所以我们也用下面几行来导入 NumPy:

张量的创建:创建张量对象

有几种方法可以创建一个tf.Tensor对象。先说几个例子。您可以使用几个张量流函数创建张量对象,如下例所示:

tf.constant、tf.ones、tf.zeros 和 tf.range 是一些可用于创建张量对象的函数

**Output:**
tf.Tensor([[1 2 3 4 5]], shape=(1, 5), dtype=int32)
tf.Tensor([[1\. 1\. 1\. 1\. 1.]], shape=(1, 5), dtype=float32) 
tf.Tensor([[0\. 0\. 0\. 0\. 0.]], shape=(1, 5), dtype=float32) 
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)

如你所见,我们用三种不同的函数创建了形状为(1, 5)的张量对象,并用tf.range()函数创建了形状为(5, )的第四个张量对象。注意,tf.onestf.zeros接受形状作为必需的参数,因为它们的元素值是预先确定的。

张量的资格:张量对象的特性和特征

TensorFlow 张量是作为tf.Tensor对象创建的,它们有几个特征。首先,他们有一个基于维度数量的排名。其次,它们有一个形状,一个由所有维度的长度组成的列表。所有张量都有一个大小,即一个张量中元素的总数。最后,它们的元素都记录在统一的数据类型(data type)中。让我们仔细看看这些特性。

等级系统和维度

张量根据其维数进行分类:

  • Rank-0(标量)张量:包含单值且无轴的张量(0 维);
  • 秩-1 张量:包含单轴(1 维)值列表的张量;
  • 秩-2 张量:包含 2 轴(2 维)的张量;和
  • 秩 N 张量:包含 N 轴(N 维)的张量。

图二。秩 1 张量|秩 2 张量|秩 3 张量(图由作者提供)

例如,我们可以通过将一个三级嵌套列表对象传递给tf.constant函数来创建一个秩为 3 的张量。对于本例,我们可以将数字拆分成一个三级嵌套列表,每级包含三个元素:

创建秩 3 张量对象的代码

**Output:** tf.Tensor( [[[ 0  1  2]   
             [ 3  4  5]]   

            [[ 6  7  8]   
             [ 9 10 11]]],
  shape=(2, 2, 3), dtype=int32)

我们可以用. ndim '属性查看我们的 rank_3_tensor '对象当前拥有的维数。

**Output:** The number of dimensions in our Tensor object is 3

形状

形状特征是每个张量都有的另一个属性。它以列表的形式显示每个维度的大小。我们可以查看用.shape属性创建的rank_3_tensor对象的形状,如下所示:

**Output:** The shape of our Tensor object is (2, 2, 3)

如你所见,我们的张量在第一层有 2 个元素,在第二层有 2 个元素,在第三层有 3 个元素。

大小

大小是张量的另一个特征,它意味着张量的元素总数。我们不能用张量对象的一个属性来度量大小。相反,我们需要使用tf.size()函数。最后,我们将使用实例函数.numpy() 将输出转换为 NumPy,以获得可读性更好的结果:

**Output:** The size of our Tensor object is 12

数据类型

张量通常包含数字数据类型,如 floats 和 ints,但也可能包含许多其他数据类型,如复数和字符串。

然而,每个张量对象必须以单一的统一数据类型存储其所有元素。因此,我们也可以使用.dtype属性查看为特定张量对象选择的数据类型,如下所示:

**Output:** The data type selected for this Tensor object is <dtype: 'int32'>

张量运算

索引

索引是项目在序列中位置的数字表示。这个序列可以引用很多东西:一个列表、一个字符串或者任意的值序列。

TensorFlow 也遵循标准的 Python 索引规则,类似于列表索引或 NumPy 数组索引。

关于索引的一些规则:

  1. 索引从零(0)开始。
  2. 负索引("-n ")值表示从末尾向后计数。
  3. 冒号(":")用于切片:start:stop:step
  4. 逗号(“,”)用于到达更深的层次。

让我们用下面的代码行创建一个rank_1_tensor:

**Output:** 
tf.Tensor([ 0  1  2  3  4  5  6  7  8  9 10 11], 
  shape=(12,), dtype=int32)

测试我们的第一、第二和第三条规则:

**Output:** 
First element is: 0 
Last element is: 11 
Elements in between the 1st and the last are: [ 1  2  3  4  5  6  7  8  9 10]

现在,让我们用下面的代码创建我们的rank_2_tensor对象:

**Output:** tf.Tensor( [[ 0  1  2  3  4  5]  
            [ 6  7  8  9 10 11]], shape=(2, 6), dtype=int32)

用几个例子来测试第四条规则:

**Output:** 
The first element of the first level is: [0 1 2 3 4 5] 
The second element of the first level is: [ 6  7  8  9 10 11] 
The first element of the second level is: 0 
The third element of the second level is: 2

现在,我们已经介绍了索引的基础知识,所以让我们来看看可以在张量上进行的基本操作。

张量的基本运算

您可以轻松地对张量进行基本的数学运算,例如:

  1. 添加
  2. 逐元素乘法
  3. 矩阵乘法
  4. 寻找最大值或最小值
  5. 寻找 Max 元素的索引
  6. 计算 Softmax 值

让我们来看看这些操作的运行情况。我们将创建两个张量对象并应用这些操作。

我们可以从加法开始。

**Output:** tf.Tensor( [[ 3\.  7.]  
            [11\. 15.]], shape=(2, 2), dtype=float32)

让我们继续逐元素乘法。

**Output:** tf.Tensor( [[ 2\. 12.]  
            [30\. 56.]], shape=(2, 2), dtype=float32)

我们也可以做矩阵乘法:

**Output:** tf.Tensor( [[22\. 34.]  
            [46\. 74.]], shape=(2, 2), dtype=float32)

注: Matmul 运算奠定了深度学习算法的核心。因此,尽管您不会直接使用 matmul,但了解这些操作是至关重要的。

我们上面列出的其他操作的例子:

**Output:**
The Max value of the tensor object b is: 7.0 
The index position of the Max of the tensor object b is: [1 1] 
The softmax computation result of the tensor object b is: [[0.11920291 0.880797  ]  [0.11920291 0.880797  ]]

操纵形状

就像在 NumPy 数组和 pandas 数据帧中一样,你也可以改变张量对象的形状。

tf.reshape 操作非常快,因为不需要复制底层数据。对于整形操作,我们可以使用tf.reshape()功能。让我们在代码中使用tf.reshape函数:

**Output:** The shape of our initial Tensor object is: (1, 6) 
The shape of our initial Tensor object is: (6, 1) 
The shape of our initial Tensor object is: (3, 2) 
The shape of our flattened Tensor object is: tf.Tensor([1 2 3 4 5 6], shape=(6,), dtype=int32)

正如你所看到的,我们可以很容易地重塑我们的张量对象。但是要注意,在做重塑操作的时候,一个开发者一定要讲道理。否则,张量可能会混淆,甚至会产生错误。所以,小心点😀。

广播

当我们尝试使用多个张量对象进行组合运算时,较小的张量可以自动伸展以适应较大的张量,就像 NumPy 数组一样。例如,当您试图将一个标量张量与一个秩为 2 的张量相乘时,该标量被拉伸以乘以每个秩为 2 的张量元素。请参见下面的示例:

**Output:** tf.Tensor( [[ 5 10]  
            [15 20]], shape=(2, 2), dtype=int32)

多亏了广播,在张量上做数学运算的时候不用担心大小匹配的问题。

特殊类型的张量

我们倾向于生成矩形的张量,并将数值存储为元素。但是,TensorFlow 也支持不规则或特殊的张量类型,它们是:

  1. 参差张量
  2. 弦张量
  3. 稀疏张量

图 3。参差张量|弦张量|稀疏张量(作者提供图片)

让我们仔细看看它们分别是什么。

参差张量

不规则张量是沿着尺寸轴具有不同数量元素的张量,如图 x 所示。

您可以构建一个不规则张量,如下所示:

**Output:** <tf.RaggedTensor [[1, 2, 3], 
                  [4, 5], 
                  [6]]>

弦张量

字符串张量就是张量,存储字符串对象。我们可以创建一个弦张量,就像你创建一个常规的张量对象一样。但是,我们将字符串对象作为元素传递,而不是数字对象,如下所示:

**Output:**
tf.Tensor([b'With this' 
           b'code, I am' 
           b'creating a String Tensor'],
  shape=(3,), dtype=string)

稀疏张量

最后,稀疏张量是针对稀疏数据的矩形张量。当数据中有空洞(即空值)时,稀疏张量就是要处理的对象。创建稀疏张量有点耗时,应该更主流。但是,这里有一个例子:

**Output:**
tf.Tensor( [[ 25   0   0   0   0]
            [  0   0   0   0   0]
            [  0   0  50   0   0]
            [  0   0   0   0   0]
            [  0   0   0   0 100]], shape=(5, 5), dtype=int32)

恭喜

我们已经成功地介绍了张量流张量对象的基础知识。

给自己一个鼓励!

这应该会给你很大的信心,因为你现在对 TensorFlow 框架的构建模块有了更多的了解。

查看本教程系列的第 1 部分:

[## 深度学习应用 TensorFlow 2.x 初学者指南

了解 TensorFlow 平台以及它能为机器学习专家提供什么

link.medium.com](https://link.medium.com/yJp16uPoqab)

继续系列的第三部分:

[## 用 5 个简单的步骤掌握 TensorFlow“变量”

了解如何使用张量流变量,它们与普通张量对象的区别,以及它们何时优于…

towardsdatascience.com](/mastering-tensorflow-variables-in-5-easy-step-5ba8062a1756)

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

如果你想获得 Google Colab 的全部代码和我的其他最新内容,可以考虑订阅邮件列表:

立即订阅

喜欢这篇文章吗?

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

最后,如果你对应用深度学习教程感兴趣,可以看看我的一些文章:

[## 使用 MNIST 数据集在 10 分钟内完成图像分类

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

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

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

towardsdatascience.com](/image-generation-in-10-minutes-with-generative-adversarial-networks-c2afc56bfa3b) [## 使用卷积自动编码器在 10 分钟内降低图像噪声

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

towardsdatascience.com](/image-noise-reduction-in-10-minutes-with-convolutional-autoencoders-d16219d2956a) [## 使用递归神经网络预测比特币(BTC)价格

如果你能以某种方式预测明天的比特币(BTC)价格,这不是很棒吗?加密货币市场有…

towardsdatascience.comm](/using-recurrent-neural-networks-to-predict-bitcoin-btc-prices-c4ff70f9f3e4)

通过 5 个简单步骤掌握 TensorFlow“变量”

原文:https://towardsdatascience.com/mastering-tensorflow-variables-in-5-easy-step-5ba8062a1756?source=collection_archive---------11-----------------------

←Part 1|←Part 2|深度学习用 TensorFlow 2。X —第 3 部分| 第 4 部分→

了解如何使用 TensorFlow 变量,它们与普通张量对象的区别,以及它们何时优于这些张量对象|使用 TensorFlow 2.x 进行深度学习

警告:不要把这篇文章和用 5 个简单的步骤掌握 TensorFlow 张量”混淆!

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

图一。克里斯·贾维斯在 Unsplash 上拍摄的照片

在本教程中,我们将重点关注张量流变量。本教程结束后,您将能够有效地创建、更新和管理张量流变量。像往常一样,我们的教程将提供带有详细解释和概念性解释的代码示例。我们将通过 5 个简单的步骤掌握张量流变量:

  • 第一步:变量定义→简单介绍,与张量比较
  • 第二步:创建变量 →实例化 tf。可变对象
  • 第三步: 变量资格 →特性和特征
  • 步骤 4:变量操作 →基本张量操作、索引、形状操作和广播
  • 步骤 5:变量的硬件选择→GPU、CPU、TPU

系好安全带,我们开始吧!

变量的定义

在这一步,我们将简要介绍什么是变量,并了解普通张量对象和变量对象之间的区别。

简介

TensorFlow 变量是表示共享和持久状态的首选对象类型,您可以用任何操作来操纵该状态,包括 TensorFlow 模型。操纵是指任何值或参数的更新。这个特性是变量相比于tf.Tensor对象最显著的特征。TensorFlow 变量记录为tf.Variable对象。让我们简单比较一下tf.Tensortf.Variable物体,了解它们的异同。

图二。变量值可以更新(图由作者提供)

与张量的比较

所以,变量和张量最重要的区别是可变性。与张量相反,变量对象中的值可以更新(例如,用 *assign()* 函数)。

“张量对象的值不能更新,只能用新值创建一个新的张量对象。

变量对象主要用于存储模型参数,由于这些值在训练过程中会不断更新,因此使用变量而不是张量是一种必然,而不是一种选择。

可变对象的形状可以用reshape()实例函数更新,就像张量对象的形状一样。因为可变对象是建立在张量对象之上的,所以它们有共同的属性,比如.shape.dtype。但是,变量也有张量所没有的独特属性,如.trainable.device.name属性。

图 3。一个张量流变量实际上是一个带有附加特征的张量流的包装器(图由作者提供)

让我们看看如何创建tf.Variable对象!

变量的创建

我们可以用tf.Variable()函数实例化(即创建* ) tf.Variable对象。tf.Variable()函数接受不同的数据类型作为参数,比如整数、浮点数、字符串、列表和tf.Constant对象。*

在展示具有这些不同数据类型的不同变量对象示例之前,我希望您启动一个新的 Google Colab 笔记本并使用以下代码导入 TensorFlow 库:

现在,我们可以开始创建tf.Variable对象了。

1 —我们可以传递一个tf.constant()对象作为initial_value:

2 —我们可以传递一个整数作为initial_value:

3 —我们可以传递一个整数或浮点数列表作为initial_value:

4—我们可以传递一个字符串作为initial_value:

5—我们可以传递一个字符串列表作为initial_value:

如您所见,tf.Variable()函数接受几种数据类型作为initial_value参数。现在我们来看看变量的特性和特征。

变量的资格

每个变量都必须有一些属性,比如值、名称、统一数据类型、形状、等级、大小等等。在本节中,我们将了解这些属性是什么,以及如何在 Colab 笔记本中查看这些属性。

价值

每个变量必须指定一个initial_value。否则,TensorFlow 将引发一个错误,并指出Value Error: initial_value must be specified.因此,请确保在创建变量对象时传递一个initial_value参数。为了能够查看变量值,我们可以使用.value()函数和.numpy()函数。请参见下面的示例:

***Output:**
The values stored in the variables:
tf.Tensor( [[1\. 2.]  
            [1\. 2.]], shape=(2, 2), dtype=float32)The values stored in the variables:
[[1\. 2.]
[1\. 2.]]*

名字

Name 是一个变量属性,它帮助开发人员跟踪特定变量的更新。创建变量对象时,可以传递一个name参数。如果不指定名称,TensorFlow 会分配一个默认名称,如下所示:

***Output:**
The name of the variable:  Variable:0*

数据类型

每个变量都必须存储统一的数据类型。由于为每个变量存储了一种类型的数据,您也可以使用.dtype属性查看这种类型。请参见下面的示例:

***Output:**
The selected datatype for the variable:  <dtype: 'float32'>*

形状、等级和大小

shape 属性以列表的形式显示每个维度的大小。我们可以用.shape属性查看变量对象的形状。然后,我们可以用tf.size()函数查看变量对象的维数。最后,大小对应于一个变量拥有的元素总数。我们需要使用tf.size()函数来计算一个变量中元素的数量。请参见以下所有三个属性的代码:

***Output:**
The shape of the variable:  (2, 2)
The number of dimensions in the variable: 2
The number of dimensions in the variable: 4*

变量运算

使用数学运算符和张量流函数,您可以轻松执行一些基本运算。除了我们在本系列教程的第 2 部分中介绍的内容,您还可以使用以下数学运算符进行变量运算。

基本张量运算

图 4。你可能会受益于基本的数学运算符(图由作者提供)

  • 加减:我们可以用+符号进行加减运算。
*Addition by 2:
tf.Tensor( [[3\. 4.]  [3\. 4.]], shape=(2, 2), dtype=float32)Substraction by 2:
tf.Tensor( [[-1\.  0.]  [-1\.  0.]], shape=(2, 2), dtype=float32)*
  • 乘除:我们可以用*/符号进行乘除运算。
*Multiplication by 2:
tf.Tensor( [[2\. 4.]  [2\. 4.]], shape=(2, 2), dtype=float32)Division by 2:
tf.Tensor( [[0.5 1\. ]  [0.5 1\. ]], shape=(2, 2), dtype=float32)*
  • Matmul 和 modulo 操作:最后,您还可以使用@%符号进行 matmul 和 Modulo 操作:
*Matmul operation with itself:
tf.Tensor( [[3\. 6.]  [3\. 6.]], shape=(2, 2), dtype=float32)Modulo operation by 2:
tf.Tensor( [[1\. 0.]  [1\. 0.]], shape=(2, 2), dtype=float32)*

这些都是基本的例子,但它们可以扩展到复杂的计算中,从而创建我们用于深度学习应用的算法。

***Note:** These operators also work on regular Tensor objects.*

分配、索引、广播和形状操作

分配

使用tf.assign()功能,您可以在不创建新对象的情况下给变量对象分配新值。在需要重新赋值的地方,能够赋值是变量的优点之一。下面是一个值重新分配的示例:

***Output:**
...array([[  2., 100.],
          [  1.,  10.]],...*

索引

就像在张量中一样,您可以使用索引值轻松地访问特定元素,如下所示:

***Output:**
The 1st element of the first level is: [1\. 2.]
The 2nd element of the first level is: [1\. 2.]
The 1st element of the second level is: 1.0
The 3rd element of the second level is: 2.0*

广播

就像张量对象一样,当我们试图使用多个变量对象进行组合操作时,较小的变量可以自动扩展以适应较大的变量,就像 NumPy 数组一样。例如,当您试图将一个标量变量与一个二维变量相乘时,该标量将被拉伸以乘以每个二维变量元素。请参见下面的示例:

*tf.Tensor([[ 5 10]
           [15 20]], shape=(2, 2), dtype=int32)*

形状操作

就像在张量对象中一样,你也可以改变可变对象的形状。对于整形操作,我们可以使用tf.reshape()功能。让我们在代码中使用tf.reshape()函数:

*tf.Tensor( [[1.]
            [2.]
            [1.]
            [2.]], shape=(4, 1), dtype=float32)*

变量的硬件选择

正如您将在接下来的部分中看到的,我们将使用 GPU 和 TPU 加速我们的模型训练。为了能够看到我们的变量是用什么类型的设备(即处理器)处理的,我们可以使用.device属性:

*The device which process the variable:   /job:localhost/replica:0/task:0/device:GPU:0*

我们还可以通过将设备名作为参数传递来设置哪个设备应该使用tf.device()函数处理特定的计算。请参见下面的示例:

***Output:**
The device which processes the variable a: /job:localhost/replica:0/task:0/device:CPU:0The device which processes the variable b: /job:localhost/replica:0/task:0/device:CPU:0The device which processes the calculation: /job:localhost/replica:0/task:0/device:GPU:0*

尽管在训练模型时不必手动设置,但在某些情况下,您可能需要为特定的计算或数据处理工作选择一个设备。所以,要小心这个选项。

恭喜

我们已经成功地介绍了 TensorFlow 可变对象的基础知识。

拍拍自己的背!

这应该给了您很大的信心,因为您现在对 TensorFlow 中用于各种操作的主要可变变量对象类型有了更多的了解。

如果这是你的第一篇文章,考虑从这个系列教程的第一部分开始:

* [## 深度学习应用 TensorFlow 2.x 初学者指南

了解 TensorFlow 平台以及它能为机器学习专家提供什么

towardsdatascience.com](/beginners-guide-to-tensorflow-2-x-for-deep-learning-applications-c7ebd0dcfbee)

或者检查第二部分:

[## 通过 5 个简单的步骤掌握 TensorFlow 张量

探索 TensorFlow 的构建模块如何在较低的级别工作,并学习如何充分利用张量…

towardsdatascience.com](/mastering-tensorflow-tensors-in-5-easy-steps-35f21998bb86)

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

如果你想获得 Google Colab 的全部代码和我的其他最新内容,可以考虑订阅邮件列表:

现在就订阅

最后,如果你对更高级的应用深度学习教程感兴趣,请查看我的一些其他文章:

[## 使用 MNIST 数据集在 10 分钟内完成图像分类

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

towardsdatascience.com](/image-classification-in-10-minutes-with-mnist-dataset-54c35b77a38d) [## 使用卷积自动编码器在 10 分钟内降低图像噪声

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

towardsdatascience.com](/image-noise-reduction-in-10-minutes-with-convolutional-autoencoders-d16219d2956a) [## 利用生成性对抗网络在 10 分钟内生成图像

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

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

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

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

在 Python 中掌握条形图

原文:https://towardsdatascience.com/mastering-the-bar-plot-in-python-4c987b459053?source=collection_archive---------4-----------------------

在本教程中,让我们借助例子深入学习“条形图”可视化。

来源:Abhijeet Bhattviascoop hook(CCO)

介绍

数据可视化是数据科学家最重要的基本工具包之一。一个好的视觉效果是很难产生的。通常在演示过程中,人们对数据或涉及的统计数据理解得不够好,但向他们展示良好的可视化效果将有助于他们理解我们试图向他们传达的故事。因此,他们说一幅图胜过千言万语

我认为想象是实现个人目标的最有力的手段之一。哈维·麦凯

本教程的全部代码可以在下面给出的我的 GitHub 库 中找到。去看看吧:

[## 塔努-北帕布/Python

github.com](https://github.com/Tanu-N-Prabhu/Python/blob/master/Mastering_the_Bar_Plot_in_Python.ipynb)

图书馆

用于可视化的最好和最常用的库之一叫做 matplotlib 。这个库产生可出版的高质量的图。在整个教程中,我们将使用 pyplot 模块。如果您使用的是 jupyter 笔记本 那么您可以直接导入库,否则,您可以使用下面的命令手动安装:

安装库

matplotlib 目前的新版本是 3.2.1 。这里的 可以参考官方安装文档

**pip install matplotlib**

如果你用的是 jupyter 笔记本 那么你可能要加一个!”命令开始时。这只是通知内核正在输入命令。

**!pip install matplotlib**

条形图

柱状图或条形图是一种用矩形条表示分类数据的图表。矩形条可以是水平垂直分类数据这里可以是电影、国家、足球运动员等的名字。相应的可以是赢得奥斯卡的电影数量、一个国家的 GDP、进球最多的球员等等。

句法

下面是条形图的一般语法:

bar(**x**, **height**, **width**, **bottom**, *****, **align**) 

因素

  • x =杆件的' x '坐标。
  • 底部 =杆件的' y 坐标。默认值为 0
  • 高度 =横条的'高度'。
  • 宽度 =钢条的“宽度”。默认值为 0.8
  • 对齐 =基于“ x ”坐标的条对齐。默认值为“居中”,使基座在“ x 位置居中。类似地,替代值是“ edge ”,它相对于“ x ”坐标对齐条的左边缘。

其他参数

' ***** '代表备选参数,我将只提及最常用的参数,例如:

  • 颜色 =条形图的颜色。这些值必须是' r '、 g '、 b '以及这三个值的任意组合。同样,诸如'红色'、青色'等颜色也是有效的。
  • 方向 =钢条的方向。这些值是'水平和'垂直',它们的工作原理不言自明。

返回

bar 函数以条(水平或垂直)的形式返回所有的容器。

例子

现在,从这里开始,我将通过例子来解释这些概念,以便你能清楚地理解它的用法。

不涉及技巧的简单条形图(无特殊参数)

在这里绘制柱状图,我将使用来自 worldometer 的数据,这是来自前 6 个国家的冠状病毒死亡总数。数据拍摄于8–6–20上午10:18(CST)

**# Importing the matplotlib library** import matplotlib.pyplot as plt**# Categorical data: Country names** countries = ['USA', 'Brazil', 'Russia', 'Spain', 'UK', 'India']**# Integer value interms of death counts** totalDeaths = [112596, 37312, 5971, 27136, 40597, 7449]**# Passing the parameters to the bar function, this is the main function which creates the bar plot** plt.bar(countries, totalDeaths)**# Displaying the bar plot** plt.show()

在您的笔记本环境中执行此代码,您将获得一个惊人的条形图,其中包含最少的细节:

塔努·南达·帕布的简单条形图

通过启用特殊参数绘制条形图

在下面的图中,让我们添加一些香料到图中,香料的意思是添加更多的参数,使图看起来更好,信息更丰富。此外,我们可以使用一些属性来使条形图更具信息性。以下是我想补充的一些内容:

  • **figsize = (12,7)** : 帮助设置地块的高度宽度。但是其中一个扭曲是顺序互换,即(宽度,高度)或(y,x)。
  • **width= 0.9** : 帮助设置条形的宽度。
  • **color = ‘cyan’** : 它有助于设置条形的颜色。
  • **edgecolor = ‘red’** : 它有助于设置条形的边缘颜色。
  • **annotate = (‘text’, (x, y))** : 有助于标注条,包括文本或字符串以及 x 和 y 坐标的位置。
  • **legend(labels = [‘Text’])** : 帮助设置条形图的标签。
  • **title(‘Text’)** : 帮助提供条形图的标题
  • **xlabel(‘Text’), ylabel(‘Text’)** : 帮助提供绘图的 x 轴和 y 轴的名称。
  • **savefig(‘Path’)** : 它有助于将情节保存到你的本地机器或任何地方。您可以保存为不同的格式,如“ PNG ”、“ JPEG ”等。

这里的'文本可以用你选择的字符串代替,'路径代表你要存储地块的路径。

**# Importing the matplotlib library** import matplotlib.pyplot as plt**# Declaring the figure or the plot (y, x) or (width, height)** plt.figure(figsize = (12,7))**# Categorical data: Country names** countries = ['USA', 'Brazil', 'Russia', 'Spain', 'UK', 'India']**# Integer value interms of death counts** totalDeaths = [112596, 37312, 5971, 27136, 40597, 7449]**# Passing the parameters to the bar function, this is the main function which creates the bar plot** plt.bar(countries, totalDeaths, width= 0.9, align='center',color='cyan', edgecolor = 'red')**# This is the location for the annotated text** i = 1.0
j = 2000**# Annotating the bar plot with the values (total death count)** for i in range(len(countries)):
    plt.annotate(totalDeaths[i], (-0.1 + i, totalDeaths[i] + j))**# Creating the legend of the bars in the plot** plt.legend(labels = ['Total Deaths'])**# Giving the tilte for the plot** plt.title("Bar plot representing the total deaths by top 6 countries due to coronavirus")**# Namimg the x and y axis** plt.xlabel('Countries')
plt.ylabel('Deaths')**# Saving the plot as a 'png'** plt.savefig('1BarPlot.png')**# Displaying the bar plot** plt.show()

Tanu Nanda Prabhu 的更好的柱状图(信息更丰富)

水平条形图

是的,你没看错。通过添加一个额外的字符' h ',我们可以水平对齐这些条。此外,我们可以用两种或更多种不同的颜色来表示条形,这将增加图形的可读性。下面显示的是修改后的代码。

**# Importing the matplotlib library** import matplotlib.pyplot as plt**# Declaring the figure or the plot (y, x) or (width, height)** plt.figure(figsize=[14, 10])**# Passing the parameters to the bar function, this is the main function which creates the bar plot
# For creating the horizontal make sure that you append 'h' to the bar function name**
plt.bar**h**(['USA', 'Brazil', 'Russia', 'Spain', 'UK'], [2026493, 710887, 476658, 288797, 287399], label = "Danger zone", color = 'r')plt.bar**h**(['India', 'Italy', 'Peru', 'Germany', 'Iran'], [265928, 235278, 199696, 186205, 173832], label = "Not safe zone", color = 'g')**# Creating the legend of the bars in the plot** plt.legend()**# Namimg the x and y axis** plt.xlabel('Total cases')
plt.ylabel('Countries')**# Giving the tilte for the plot** plt.title('Top ten countries most affected by\n coronavirus')**# Saving the plot as a 'png'** plt.savefig('2BarPlot.png')**# Displaying the bar plot** plt.show()

Tanu Nanda Prabhu 的单杠图

将两个条形图堆叠在一起

有时,您可能想要将两个或多个条形图堆叠在一起。借助于此,您可以直观地区分两个独立的量。要做到这一点,只需遵循。

**# Importing the matplotlib library** import matplotlib.pyplot as plt**# Declaring the figure or the plot (y, x) or (width, height)** plt.figure(figsize=[15, 5])**# Categorical data: Country names** countries = ['USA', 'Brazil', 'Russia', 'Spain', 'UK', 'India']**# Integer value interms of death counts** totalCases = (2026493, 710887, 476658, 288797, 287399, 265928)**# Integer value interms of total cases** totalDeaths = (113055, 37312, 5971, 27136, 40597, 7473)**# Plotting both the total death and the total cases in a single plot. Formula total cases - total deaths** for i in range(len(countries)): plt.bar(countries[i], totalDeaths[i], bottom = totalCases[i] -  totalDeaths[i], color='black')
    plt.bar(countries[i], totalCases[i] - totalDeaths[i], color='red')**# Creating the legend of the bars in the plot** plt.legend(labels = ['Total Deaths','Total Cases'])**# Giving the tilte for the plot**
plt.title("Bar plot representing the total deaths and total cases country wise")**# Namimg the x and y axis**
plt.xlabel('Countries')
plt.ylabel('Cases')**# Saving the plot as a 'png'**
plt.savefig('3BarPlot.png')**# Displaying the bar plot**
plt.show()

Tanu Nanda Prabhu 将两个条形图堆叠在一起

在上图中,我们可以看到两种不同的数据变化,分别是总死亡数总病例数

绘制两个相邻的条形图(分组)

很多时候,你可能想把两个或更多的图组合在一起,只是为了表示两个或更多不同的量。同样在下面的代码中,你可以学习用你选择的名字覆盖 x 轴的名字。

**# Importing the matplotlib library** import numpy as np
import matplotlib.pyplot as plt**# Declaring the figure or the plot (y, x) or (width, height)** plt.figure(figsize=[15, 10])**# Data to be plotted** totalDeath = [113055, 37312, 5971, 7473, 33964]
totalRecovery = [773480, 325602, 230688, 129095, 166584]
activeCases = [1139958, 347973, 239999, 129360, 34730]**# Using numpy to group 3 different data with bars** X = np.arange(len(totalDeath))**# Passing the parameters to the bar function, this is the main function which creates the bar plot
# Using X now to align the bars side by side** plt.bar(X, totalDeath, color = 'black', width = 0.25)
plt.bar(X + 0.25, totalRecovery, color = 'g', width = 0.25)
plt.bar(X + 0.5, activeCases, color = 'b', width = 0.25)**# Creating the legend of the bars in the plot** plt.legend(['Total Deaths', 'Total Recovery', 'Active Cases'])**# Overiding the x axis with the country names** plt.xticks([i + 0.25 for i in range(5)], ['USA', 'Brazil', 'Russia', 'India', 'Italy'])**# Giving the tilte for the plot** plt.title("Bar plot representing the total deaths, total recovered cases and active cases country wise")**# Namimg the x and y axis**
plt.xlabel('Countries')
plt.ylabel('Cases')**# Saving the plot as a 'png'** plt.savefig('4BarPlot.png')**# Displaying the bar plot** plt.show()

Tanu Nanda Prabhu 对柱状图进行分组

在上面的图中,我们可以很容易地想象哪个国家在恢复或活跃病例等方面做得很好。

结论

条形图是 matplotlib 库中最简单、最有趣的图形之一。学习起来很有趣,希望你们已经完全理解了进出酒吧的情节。下面是我在教程的上一部分中提到的简要目录。去看看,把你脑子里的事情弄清楚,如果不行就回来找我。

目录:

  • 条形图的一般语法
  • 简单的条形图,不涉及任何技巧
  • 学习如何使用特殊参数
  • 水平绘制条形图
  • 将两个条形图堆叠在另一个之上
  • 绘制相邻的三条形图(分组)
  • 超越 x 轴,学习**xticks** 能做什么魔法。
  • 最后,将绘图保存为图像(png)。

谢谢各位了本教程就到此为止“掌握 Python 中的条形图”。希望你今天学到了一些新东西,随时探索更多创建酷吧的情节。在那之前,敬请关注更多更新注意安全

掌握数据科学求职

原文:https://towardsdatascience.com/mastering-the-data-science-job-hunt-b0738af0f132?source=collection_archive---------31-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

爱德华·哈里斯在 TDS 播客

编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:

被聘为数据科学家、机器学习工程师或数据分析师很难。如果有一个人花了很多时间思考这是为什么,以及如果你试图进入这个领域,你可以做些什么,那就是爱德华·哈里斯。

艾德是数据科学导师项目的联合创始人,该项目在你找到工作之前是免费的。他也是我的兄弟,这使得这成为我们最裙带关系的一集。以下是对话的一些亮点:

  • 求职公告板通常不是进入一家公司的最佳途径,因为它们将你的简历放在招聘人员面前,招聘人员无法评估你的代码质量或你的项目,而且他们对新员工没有决策权。
  • 最好联系的人通常是招聘经理,而不是求职板和招聘人员。这些通常是高级技术团队领导,他们实际上能够阅读和理解代码,并且有权对候选人说“是”。
  • 你获得公司关注的唯一方法是脱颖而出,而你不能通过做普通的事情来脱颖而出。具体来说:

→一般的事情:有一个 GitHub repo,里面装满了 juptyter 笔记本,这些笔记本导入了 sklearn 和 pandas,用于不同数据集上的分类/回归任务。通过求职公告板申请工作。

→正在发生的事情:每次构建项目时,强迫自己学习新的工具(例如 git、Docker、AWS、Flask、MySQL 等)。将您的模型部署到云中,并构建 web 应用程序来展示您的工作。通过电子邮件联系招聘经理,而不是通过求职公告板申请。

  • 不要陷入“装配线心态”——当人们按照说明手册中的步骤操作时,他们会进入这种无意识的模式。真正的数据科学并不总是遵循 MOOCs 和大学向学生灌输的从数据清理到模型构建的可预测流程。专注于提出具体的问题,并用数据来回答它们——如果你不需要一个模型来做这件事,不要强迫自己做一个,因为这是“通常接下来要做的”一步。

你可以在 Twitter 这里关注爱德华,或者在 LinkedIn 这里关注爱德华。

夹子

youtube.com

我们正在寻找能与我们的观众分享有价值的东西的客人。如果你碰巧知道谁是合适的人选,请在这里告诉我们:publication@towardsdatascience.com

基于香草深度神经网络的英雄联盟比赛预测

原文:https://towardsdatascience.com/match-prediction-in-league-of-legends-using-vanilla-deep-neural-network-7cadc6fce7dd?source=collection_archive---------18-----------------------

了解英雄联盟比赛预测模型,该模型通过其独特的输入功能显示约 70%的准确性。

马克西姆·罗西诺尔在 [Unsplash](https://unsplash.com/collections/1123297/esports-in-indonesia-(project-startup?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的照片

为什么要研究电子竞技游戏中的获胜预测?

公众的第一个反应是钱,的确,也许钱可以通过一个足够成功的预测模型来赚,但也许这只是看着一个小画面。

解剖模型可以看到更大的画面。成功的胜利预测模型准确地告诉我们是什么促成了比赛的胜利。

例如,假设预测模型中使用的数据点之一是球员身高。如果通过预测模型显示,球队的平均身高越高,该队赢得比赛的可能性越大,那么我们可以从预测模型中得出与我们的信念相反的结论,球员身高实际上在赢得联赛比赛中至关重要!这可能会从根本上改变世界各地职业联赛电子竞技队的球探系统。

你可能会问,为什么要首先关注电子竞技行业。嗯,在 2019 年的英雄联盟世界锦标赛中,4400 万人同时观看了 11 月 10 日的决赛, 1 亿独立观众在线观看了这场赛事。这超过了当年超级碗的观众人数。随着这个行业越来越受欢迎,预计这个数字还会继续增长。

研究电子竞技背后的数字的最后一个原因是可获得的数据。关于这个话题存在一些争论,因为 RiotApi(一种用于获取比赛数据的 Api,通过《英雄联盟》的出版商 RiotGames 提供)提供的数据有限且不准确,这可能是大多数关于同一游戏类型的研究论文都基于《英雄联盟》的竞争对手 DotA2 的原因。但是,数据是免费的。与足球等其他传统运动相比,这是一个巨大的优势,在足球等传统运动中,有意义的数据只能通过像 Opta 这样的公司的昂贵订阅才能获得。

电子竞技比赛预测的前期研究

如前所述,很少有关于英雄联盟比赛预测的先前研究,但 DotA2 比赛预测的情况相反。由于这两款游戏属于同一类型,游戏玩法相似,这些研究值得探讨。

例如,论文 Dota 2 获胜预测提供了一个具有 73%准确性的预测器,使用了诸如偏移、匹配、协同和对抗等特征。
另一篇论文赢或不赢提供了一个具有 74%准确率的预测器,使用共现网络来揭示英雄协同数据,并使用逻辑回归来做最后的魔术。

尽管这些结果令人惊讶,但对这些先前的研究有一定的改进,可以应用于获得更好的结果。

首先,两篇论文都将每个英雄视为输入中的一个单独的向量,或者在数据预处理过程中。这让你“考虑每个光芒四射和可怕的英雄对比赛结果的个人影响”,但也有对每个冠军训练预测模型过于狭隘的危险。以⁴为例,预测模型将无法把视为一个拥有坦克和大量魔法伤害的冠军,而只是把视为自己。它将错过定义单个冠军的特征,并且无法与其他类似的冠军进行归纳。

第二,两篇论文都没有考虑到玩家控制英雄的技能。很明显,一个职业玩家控制一个英雄会比一个普通玩家控制同一个英雄对游戏结果产生更大的影响。因此,虽然英雄的影响力、协同效应和反选择都很重要,但玩家的技能也很重要。这可能是提高预测能力的附加特征。

数据集

RiotApi 的问题是很难随时获得固定数量的比赛数据。有必要确定一个球员,然后浏览他的比赛历史,然后继续查看出现在他的比赛历史上的球员的比赛历史,以递归地收集比赛数据。

即使采集了数据,也必须经过过滤,以确保冠军的泳道位置标记正确。在超过一半的情况下,Riot 错误地标记了冠军的车道位置,在顶车道标记了三个冠军,在中间车道标记了四个冠军,在 bot 车道标记了零个冠军,等等。

RiotApi 还强制执行每 2 分钟 100 个请求的速率限制,加上损坏数据的高概率,这意味着我必须在自定义 AWS EC2 服务器上运行一个脚本几天,无休止地挖掘匹配数据。

在我的研究中,我收集了 1045 个匹配数据,其中 80%作为训练集,10%作为开发集,其余 10%作为测试集。

特征

我的模型与之前的研究的真正区别在于我对特征的选择。

我在模型中使用的特征是胜率

关于英雄联盟游戏的一个显而易见的事实是,一个由优秀玩家组成的团队控制强大的冠军将会获胜。在这里,成为一名“好球员”更具体地意味着球员擅长控制特定的冠军,因为球员必须能够匹配冠军的比赛风格,以最大限度地发挥冠军的潜力。

那么问题就变成了,有哪些数据在数字中表现出以下两个特征?

  1. 一个球员对某个冠军的控制有多好
  2. 当前元中的冠军有多强

第一个特征由玩家与特定冠军的胜率来捕捉。例如,一个只玩名为奈特利的冠军的玩家在玩那个冠军时很可能会有很高的胜率。

第二个特征是由当前元/补丁中特定冠军的胜率捕获的。众所周知,一个强有力的冠军有很高的胜率(通常等于或大于 53%,当从所有级别合计时)。

我们为每个队中的每个球员收集这些数据,因此神经网络的每个输入向量将有 20 个数据点大,如下所示:

[0.5114, 0.52, 0.5275, 0.619, 0.5074, 0.727, 0.4999, 0.517, 0.5187, 0.659, 0.5034, 0.0, 0.5005, 0.5, 0.4448, 0.257, 0.5065, 0.286, 0.5199, 0.544]

结果是我有一个只有 20 大的输入特征。与先前研究中使用的输入特征相比,这是非常小的。

每一个 2i* | 0≤i≤9 元素都是当前元/补丁中的冠军胜率, 1+i | 0≤i≤9 是玩家控制那个特定冠军时的胜率。

模型和结果

模型

如题,我用的是香草深度神经网络,意思是有四个隐层的全连接前馈深度神经网络。
我使用了 tflearn 库来构建模型,包含了批量训练。尝试了各种参数和超参数,包括隐藏层数。虽然四个隐藏层看起来过多,但它似乎产生了最好的结果,尽管两个或三个隐藏层的性能差别很小。我不会透露确切的参数/超参数,因为通过设置自己的参数应该很容易重现结果。

结果

神经网络的性能取决于参数/超参数,但最具代表性的数字如下:

训练精度:0.7255
验证精度:0.6905
测试精度:0.7033

此外,由于在输出层使用了 softmax 激活,输出向量将网络在比赛中获胜或失败的“置信度”显示为大小为 2 的向量(例如,[0.317,0.683]将显示模型认为比赛失败)。输出向量中的数字并不直接转化为赢或输的“概率”,特别是因为使用了批量训练,但它们确实给出了每个事件可能性的一般意义。因此,我收集了所有比赛,其中模型有 0.8 或更多的“信心”认为这场比赛会取得胜利,然后得到了 76.76%的准确率:对于某些比赛,我们可以非常确定它的结果。

很大的改进空间

这个模型仍然很有希望的是有很大的改进空间,因此,有可能获得更高的匹配预测准确性。

红边/蓝边

当进入英雄联盟比赛时,每个玩家被分配到红方或蓝方。传统上,胜率会因你站在哪一边而有所不同,而在当前的补丁中,胜率没有太大的差异(蓝边的胜率为 50.3%),这是一个随补丁而变化的数字,可以考虑在内。⁵

冠军协同效应

协同是之前研究中包含的特征之一,单独负责记录的 74%预测准确率赢或不赢。⁵ 想出一种方法来准确反映冠军协同效应,并将其作为输入特征,可以提高模型的准确性。

数据的细化

在当前用于培训/开发/测试集的数据中,有些数据是不可能找到的,因此只能靠运气。这些归功于我大量使用 op.gg 和其他英雄联盟分析网站来收集特定玩家的冠军统计数据。
例如,如果在预处理数据时,python 爬行脚本找不到某个玩家的冠军特定胜率,则该胜率会自动分配 0.5 的值。这是一个合理的选择,因为在大多数情况下,特定冠军的胜率不会出现,因为缺乏特定冠军的使用,这意味着玩家不擅长使用冠军的可能性与他/她擅长使用冠军的可能性一样大。
随着数据更加精确,漏洞更少,这种神经网络模型的性能可能会提高。

球员的形式

玩家之间的一个普遍现象是,有时候玩家会陷入“翻滚”这意味着当一个球员已经连续赢了几场比赛,他觉得他很可能在下一场比赛中再次获胜,反之亦然。在职业锦标赛中,根据球员的表现,一支球队可能会有非常不同的表现,这几乎是一个既定的事实。例如,2020 年 LCK 之春的 KT Rolster 在本赛季的大部分时间里表现极差,但在比赛的最后两周表现出非凡的实力,这是因为球员和球队的“状态”有所改善。这也可能是影响匹配预测的附加特征。

冠军作文

与冠军协同非常相似,但也有一点不同,冠军组合指的是比赛前一支球队的结构。例如,蓝队可能有一个治疗冠军,两个坦克冠军,两个经销商冠军,这取决于补丁/元可以影响该队的胜利可能性。另一个区别可能是“早期”冠军和“后期”冠军。这些标签根据冠军何时对游戏产生最大影响来区分冠军,因此可能是代表团队组成的另一种方式。

现在怎么办?

我有信心,用更多的特征和更好的数据来改进预测模型将会增强模型的预测能力,也许会超过先前的一项研究设定的 74%的基线。

希望有了更先进的预测模型,我们可以制定最佳团队构成的指导方针,以及在寻找未来职业球员时具体要寻找什么。通过提出一个成功的模型并检查权重,我们可以潜在地洞察到与团队组成相比,对冠军的掌握有多重要,等等。这不仅会影响职业球队的球探系统,还会影响他们在锦标赛中的策略。

因为我现在在军队服役,所以我能多快/多有效地进行这项研究是有限制的。但我还是会这样做,并继续发布我的收获。

后续步骤:

在 AWS 上学习和设置 DynamoDB。
创建脚本文件,在 DynamoDB 上建立我自己的数据库。
为 RiotApi 注册开发 Api 密钥。
学习如何表现冠军协同效应和组合。
等。

[1]裴,安妮,“这个电竞巨头吸引的观众比超级碗还多,预计会变得更大”,https://www . CNBC . com/2019/04/14/league-of-legends-gets-more-viewers-than-Super-Bowl whats-coming-next . html
【2】金凯德,尼古拉斯,“DOTA 2 赢预测。” (2015)。
【3】卡亚纳拉曼,考希克。“赢还是不赢?决定 DotA 2 比赛结果的预测模型。” (2015)。
【4】金凯德。
【5】卡利亚纳拉曼。
【6】红色 vs 蓝色图形(2020 . 04 . 17)https://www.leagueofgraphs.com/rankings/blue-vs-red/na

通过 4 个步骤将算法与业务问题相匹配

原文:https://towardsdatascience.com/matching-algorithms-to-business-problems-in-4-steps-ae7c87a7905b?source=collection_archive---------32-----------------------

照片由岩田良治Unsplash 上拍摄

世界上最杰出的人工智能思想家之一吴恩达表示,将人工智能应用到你的业务中的最佳方式是从小处着手。在最近的一次谈话中,他以自己在谷歌的经历为例,讲述了在解决广告部更大的商业问题之前,他如何使用机器学习(ML)来增加语音识别和谷歌地图的价值。然而,在经理们开始考虑人工智能之前,他们必须首先确定客户的问题,并考虑所有可能的解决方案。下面是经理在使用 ML 解决业务问题时应该遵循的 4 个步骤。

第一步:挑战你的假设

在人工智能的新世界中,公司可能犯的最大错误之一是寻找或制造问题,因为他们认为人工智能会很好地解决这些问题。他们创造了无人问津的聊天机器人,或者自动完成受益于人类接触的任务。通过与客户交谈并确定他们的关键痛点,公司可以避免产生问题并开始解决它们。只有当正确的客户发现完成后,经理才能继续寻找解决问题的最佳技术。

第二步:考虑所有解决方案

管理者可以通过理解人工智能的优势和局限性来增加巨大的价值。优秀的领导者可以在头脑中制定战略,但需要伟大的领导者才能理解使用人工智能没有好处的情况。通过了解人工智能无法解决的问题,经理们帮助公司节省了时间和金钱。一旦经理决定人工智能是(或不是)一个合适的人选。他们需要确定可用的数据源。

第三步:查找数据

在考虑所有解决方案时,应该对可用数据进行初步评估,并评估是否有足够的数据来成功训练 ML 算法。继续第三步,经理必须考虑 ML 算法提供的洞察力。

例如,一家银行希望在客户发现他们的账户有欺诈行为时提醒他们。为了创建一个检测欺诈的算法,它需要对过去发生的欺诈交易进行训练。在这种情况下,需要的数据是带有“欺诈”或“非欺诈”标签的交易。

如果第 1 步和第 2 步没有正确完成,第 3 步可能会出错。如果没有明确的客户问题需要解决,也没有对最佳解决方案的分析,就很难确定所需的合适数据源。通过正确完成前面的步骤,经理将有一个与数据科学家讨论的坚实基础,并可以确保整个团队致力于为客户创造最大价值的解决方案。

第四步:确定最佳算法

一旦数据科学家收集了所有的数据,并完成了一些预处理,管理人员就可以帮助确定哪种算法是最适合的。管理者不需要知道算法的细节,也不需要知道它们叫什么,如何工作等等。相反,他们只需要在输出中建立一个可接受的误差水平和算法的可解释水平。

如果检测欺诈的算法只有 50%的正确率,企业会接受吗?通过建立成功的指标和衡量标准,经理可以确保数据科学家朝着共同的业务目标努力。

领导者还必须确定模型可解释性的重要性。客户可能不希望知道银行是如何判定一项交易是欺诈性的,但解释算法拒绝他们贷款申请的原因可能非常重要。

通过了解客户的期望,以及他们如何与算法的输出进行交互,经理可以极大地改善客户体验,并避免因算法而产生无法解释和不准确的问题。仔细遵循上述步骤将会产生高价值的 ML 解决方案,为企业带来直接价值。

匹配估计器功能强大且简单

原文:https://towardsdatascience.com/matching-estimator-is-powerful-and-simple-82350f08515a?source=collection_archive---------55-----------------------

您可以使用 13 行 R 代码手动进行匹配

upslash.com

背景

为获得因果关系的许多观察研究面临的挑战是自我选择——在许多情况下,人们出于某些原因选择接受治疗,因此,接受治疗的人不能直接与未接受治疗的人进行比较。例如,来自富裕家庭的学生可能更有可能选择上私立大学。如果我们想知道上私立大学对收入的因果影响,我们应该排除(或控制)家庭背景的影响。

匹配估计量已广泛应用于统计学、经济学、社会学、政治学等学科,用于估计因果关系。这是一种准实验方法,目的是在许多未处理单元中寻找与处理单元相当的反事实单元。

匹配很简单,从技术上讲,很大程度上是数据处理。然而,我已经看到许多资料,使简单的方法难以理解。这太令人沮丧了!所以我决定通过这个方法向您展示,您可以用少于 15 行的 R 代码实现这个方法。我保证!

运行倾向评分匹配的 r 代码

我在这里重点介绍倾向得分匹配,因为它是一种流行的匹配方法。其他匹配方法和这个差不多。

首先,我们用下面的 R 代码模拟一些数据。这些都是不必要的。复制粘贴即可。在这些代码中,我指定了两个协变量:W1 和 W2。a 是二元处理,Y 是观察结果。Y.0 和 Y.1 是潜在的结果,所以真实的治疗效果只是 Y.0 和 Y.1 的差别。

# Make the libraries ready
library(dplyr)
library(Matching)generateData<- function(n) {
 # Generate baseline covariates:
 W1 <- runif(n, min = 0.02, max = 0.7) 
 W2 <- rnorm(n, mean = (0.2 + 0.125*W1), sd = 1) 
 # Generate binary treatment indicator
 A <- rbinom(n, 1, plogis(-.7 + 1.8*W1–1.4*W2))
 # Generate the potential outcomes
 Y.0 <- rnorm(n, mean = (-.5 + 2*poly(W1,2) — W2), sd=1)
 Y.1 <- rnorm(n, mean = (-.5 + 2*poly(W1,2) — W2 + 1.5 + 2*poly(W1,2) — W2), sd=1)
 # Generate the observed outcome
 Y <- ifelse(A == 1, Y.1, Y.0)
 return(data.frame(W1,W2,A,Y,Y.1,Y.0))
}
set.seed(101)
data <- generateData(n = 1000) # Generate 1000 data.

用于匹配的 r 代码:

第一步。估计 logit 模型以获得倾向得分:

logitmodel <- glm(A ~ W1 + W2, data = data, family=’binomial’) # L1

第二步。在与已处理单元的估计倾向得分差异最小的未处理单元中进行搜索。发现的单元然后被用作反事实单元,用于估算处理单元的潜在结果。

# Add the estimated ps to the data. 
data <- mutate(data, pscore = logitmodel$fitted.values) #L2
data1 <- filter(data, A == 1) # Treated units data #L3
data0 <- filter(data, A == 0) # Untreated units data #L4match.data <- data1 #Make a copy of treated units data #L5
for(i in 1:nrow(match.data)){#Now find counterfactual units #L6
 temp <- data0 %>% # Search among untreated units #L7
 mutate(pscorei = data1$pscore[i], # PS of the treated unit i #L8
      dif.score = abs(pscorei — pscore)) %>% # Score difference
      arrange(dif.score) %>% # Arrange the data  #L10
      slice(1) %>% # Choose the top one with lowest score dif
      dplyr::select(!!colnames(match.data)) # Keep needed cols# L11
 match.data[i,] <- temp[1,] # Replace with the found unit #L12
}

第三步。计算观察到的 Y 和匹配的 Y 之间的平均差异。该平均差异是被治疗者的平均治疗效果(ATT)。

mean(data1$Y — match.data$Y) #L13

结束

我刚刚展示了如何使用 13 行 R 代码进行匹配。还有其他方法可以加速编码,计算标准误差,估计治疗对未治疗者的影响,等等。但这些都不是本文的目标。敬请关注我的下一篇文章!

万一你不相信我,你可以运行下面的代码从匹配包得到相同的 ATT 值。

m.out <- Match(Y = data$Y, Tr = data$A, X = data$pscore, distance.tolerance = 0)
summary(m.out)mean(data1$Y.1 - data1$Y.0) # True ATT

管理人类和机器智能

原文:https://towardsdatascience.com/matching-human-and-machine-intelligence-41125c88a9fa?source=collection_archive---------22-----------------------

管理者需要超越数据和算法,探索人工智能如何改变管理的本质

图片来源:Gearstd

在为人工智能管理做准备的热潮中,学术界和企业界都在整合统计学、信息技术和信息科学项目,为商业和工业培养未来的专业人才。在混乱中迷失的是需要解决人工智能如何改变今天的管理实践,以及它将如何在可预见的未来影响管理职业生涯。让我们花点时间强调一下显而易见的事实——大多数经理永远不会成为数据科学家,但所有经理都需要超越数据和算法,探索人工智能如何改变管理的本质。

商科和工科学生需要了解 AI 在管理方面的哪些内容?在这个三部分系列的第一篇文章中,我们研究了人工智能如何影响企业战略的基础,解决“人工智能就绪”概念的需要,以及人工智能项目管理的特殊性。[i]在这篇文章中,我们将探讨人工智能在商业环境中的三个额外基础:培养协作智能的重要性,改善管理决策的需要,以及数字化转型的影响。

协作智能

商业的未来不属于聊天机器人、电子机器人和合作机器人,而是属于那些已经学会调整组织以利用人机合作新形式的管理者。协作智能指的是人机代理网络的设计,它们在促进知识、专业知识和偏好的众包方面发挥各自的优势。只有管理才能定义人机代理之间的分工,并建立管理可接受行为的规则。随着算法证明了它们在自动化重复任务方面的价值,管理者证明了它们在理解如何以及在哪里匹配人类和机器智能方面的价值。管理层需要鼓励交流和有意义的讨论,这种讨论将越来越异步和虚拟化。最后但同样重要的是,当算法被用于解决人类互动的复杂性时,管理者将负责解决不可避免的冲突。

如果人工智能的目标是增强人类的潜力,那么管理层就有责任去辨别它对人类意味着什么。培养合作智能的培训管理可以专注于如何高效和有效地实施“增强策略”。[ii]关于该主题的案例研究可以探索在虚线组织中利用人机代理的网络效应的挑战,在虚线组织中,经理和员工作为独立的承包商。讲习班可以侧重于变革管理的实践和设计调整变革步伐的转型模式的挑战。远离数据和算法的机制,管理层必须准备好鼓励他们的生态系统利用人工智能来共同开发人类和机器智能

图片来源:GDPR 信息员

机器代理永远不会比他们背后的计算机程序更好

自动化决策提供了一个恰当的例子。从好的方面来看,算法向我们承诺了更高效的流程和更一致的决策,这将使经理们有更多的时间专注于改善业务。不利的一面是,机器代理永远不会比它们背后的程序更好。在代理依赖于集成人工神经网络或支持向量机的深度学习算法的情况下,每个决定的方式和原因可能很难解释。他们的输出将不断被质疑为不公平、非法或错误的。因此,像欧洲 GDPR 这样的法规要求公司为每个影响就业、健康、采购或信贷的基于算法的决策提供具体的理由。人类和机器代理将需要在相互之间以及与消费者的交流中发展协作智能。

管理决策

管理者不是根据数据行动,而是根据他们对数据所代表的东西的理解行动。机器学习是关于开发能够从数据中学习的算法,阐明模式和联系,并提供支持人类决策的见解。然而,在决策科学中,我们了解到决策的主要挑战是人类对我们做出决策的环境的复杂性、模糊性和不确定性的感知。在认知科学中,我们探索我们的先入之见和偏见如何扭曲我们看待问题的方式,以及如何限制我们提出创新解决方案的能力。孤立地研究人工智能既短视又无用,因为从业者需要理解人类决策的复杂性和多样性。

关于管理决策的程序可以关注机器学习在何时何地可以帮助管理者将数据转化为行动。课程作业可以帮助参与者理解建模的作用、特定决策环境的本质以及数据、算法和逻辑中认知偏差的影响。案例研究可以阐明启发法和算法在感知、预测评估和洞察力中的位置。总的来说,这些计划可以被设计来发展参与者通过分析方法“解决”商业问题的能力:评估背景,识别问题的根源,评估数据的质量,选择正确的方法来解决问题,以及为集体行动创造条件。

图片来源:灰色海岸媒体

只要我们购买和消费,营销的本质永远不会被算法捕捉到

B2C 营销提供了管理决策复杂性的多个例子。人工智能建模和模拟技术当然可以用来构建相关的买家角色和预测消费者行为趋势。[iii]然而,只要人类还在购买和消费,营销的本质就永远不会被算法捕捉到。每个营销决策都需要了解客户的需求,理解社区、文化和经济对消费的暂时影响,并调整每个组织的产品和服务。决策环境、认知偏差和消费者偏好固有地影响个人和组织如何看待手头的数据。B2C 营销不是数据和结果的问题,而是影响消费和生产的感知、预测、评估和洞察力的过程。[四]

数字化转型

数字转型一词表明,数字技术引发了企业向利益相关者交付价值方式的根本性变化。尽管这一概念最初反映了将原子转化为比特的愿景,但在过去十年中,它已经演变为包含管理者和股东如何看待其业务的思维模式。数字化转型不是关于硬件、软件和数据,而是技术在提供对业务核心内容的管理洞察力方面的作用,以及他们的组织如何与客户合作。同样重要的是,的经验表明,数字技术不会改变公司和市场,而是人会改变。

数字化转型的当前目标:人工智能和机器学习的使用,数字化运营模式的采用,新的数字化合作伙伴关系的创建,以及公司数字资产的评估,这些都强调了管理培训在任何数字化计划中的重要性。课程可以帮助参与者理解数字化转型不是一个 IT 项目,其成功的责任不在于数据科学或 IT 团队。案例研究可以为围绕管理在为每个项目设定适当愿景中的作用的辩论和讨论提供充足的空间,以及在特定背景下的相关方法和评估指标。研讨会可以提供必要的空间来探索培养冒险文化和克服组织变革障碍的必要性。

图片来源:Bate

如果这些公司认为数据只不过是其市场现实的反映,那么他们认为数据驱动的决策不亚于他们如何向客户提供价值的愿景

Airbnb、优步或亚马逊等平台商业模式提供了丰富的思考素材。虽然每个人都广泛使用人工智能,但每个案例的价值既不在于他们捕捉的数据,也不在于他们使用的算法。他们认为数据只不过是市场现实的反映,他们认为数据驱动的决策只不过是他们如何向客户提供价值的愿景。[v]在分析这些公司内部数字化转型的影响时,我们需要超越他们的数字基础设施,探索他们的数据实践如何支持他们的业务模式、业务流程和收入流。他们的业务价值不能用他们的物质和非物质资源的总和来计算,而是看他们对数字化转型的愿景如何鼓励他们的客户和员工以不同的方式思考业务。

有哪些经验教训?

今天的人工智能培训需要帮助经理们超越数据和算法,探索人工智能如何改变了组织和市场。商业努力的未来成功不取决于人工智能,而是取决于能够利用数字技术提高人类潜力的管理者。在这篇文章中,我们探讨了应该成为任何数据科学项目核心的三个主题:协作智能、管理决策和数字化转型。在每个愿景中,管理技能而不仅仅是技术悟性被证明是将人工智能的承诺与每个组织的战略、资源和文化相结合的基础。在这一系列关于管理在人工智能中的作用的最后一篇文章中,我们将看看数字伦理的重要性以及人工智能对创新的影响。[六]

Lee Schlenker 是 BAI 的校长,也是商业分析和社区管理教授。他在 LinkedIn 上的个人资料可以在的查看

— — —

[i] Schlenker,L. (2020),人工智能课程中管理的位置,中等。

[ii] Wilson,H.J .和 Daugherty p . r .(2018),协作智能:人类和人工智能正在联手,HBR

[iii] Tjepkema,L. (2018),利用人工智能进行营销:机器如何优化决策,Emarsys

[iv] Schlenker,L. (2019),把人工智能放在第一位,走向数据科学

[v]冯,l .等(2017),Airbnb 如何与数据大学一起使数据科学民主化,走向数据科学

[vi] Schlenker,L. (2020),以人为中心的 AI 对管理意味着什么?,走向数据科学

配对:着火的考拉——第一部分

原文:https://towardsdatascience.com/matching-koalas-on-fire-part-1-17691bb85c23?source=collection_archive---------37-----------------------

什么是(多重)匹配?为什么它在观察研究和影响评估中很重要?

合著马加利德布鲁因

图片由 Jordan WhittUnsplash 上拍摄

TL;DR: 匹配是一种计算工具,用于提高因果推理的健壮性或可信度。为此,它将来自治疗组的数据点与来自对照组的数据点配对——基于它们在所选特征上的相似性。那又怎样?匹配使得观察性研究中揭示的因果关系更有可能反映现实,从而可能导致更好的知情决策和政策。

由于最近的森林火灾,树袋熊可能很快就会灭绝。但是这些自然灾害对这个可爱物种的生活有多大影响呢?

嗯,我们可以用数据来量化生活在有火的地区对考拉寿命的影响。把它作为一个因果推理的问题,我们感兴趣的是推断一种干预——火灾——对我们关心的结果——考拉的生计的治疗效果。

当然,随机对照试验(RCT)和附带的实验数据将是理解这种因果关系的理想方法。然而,我们不想仅仅为了实验的目的而引发更多的森林大火。

所以,我们只剩下(假设的)观测数据了。

不幸的是,观察数据有许多局限性,会影响测量的治疗效果。比如少吃桉树(不是竹子——那是熊猫的考拉!)可能更容易早死,也更可能生活在“火热”的森林中。这是一个选择偏差的例子:我们的单位(考拉)具有某些特征(协变量)更有可能被“分配”治疗:生活在森林大火中。

幸运的是,我们有一些工具来纠正这一点。介绍(drumroll,please):匹配!

什么是匹配,我们为什么需要匹配?

匹配就是它听起来的样子。我们将处理过的单元与具有相同背景特征的控制单元“匹配”。这种对数据的“处理”使我们能够得出更可靠的因果推断。

当我们想了解一个原因对一个结果的影响时,我们通常有一个控制组和一个处理组——在我们的例子中:来自安全和火热森林的考拉。我们假设除了治疗方法不同,各组是相同的。因此,从治疗组的相同平均值中减去对照组的结果变量的平均值将暗示潜在的治疗效果。当我们比较“暴躁的”考拉和“安全的”考拉的寿命(结果)时,假设除此之外它们是完全相同的样本种群(或者(1)它们在背景特征上完全相同,或者(2)它们从相同的种群中取样),我们可以假设寿命的差异是由于生活在受火灾影响的森林中(治疗)造成的。但是这种协变量的完美平衡在大多数观察研究中太好而不真实。通常,治疗组和对照组没有完全相同的特征。例如,我们可能从两个不同的地区选择树袋熊,因此它们有不同的饮食。这种混杂变量影响了我们测量的治疗效果,限制了我们结论的稳健性。

因此,匹配试图创建一个在所选特征上与治疗组非常相似的对照组。在我们的例子中,我们试图有一个“安全的”树袋熊样本种群,它每年吃的桉树与“火热的”树袋熊样本种群一样多。

我们如何知道这些组在所选特征上是相似的?现在,最被接受的实践是基于距离度量来测量平衡。这是通过比较对照组和治疗组的背景特征的平均值的统计显著性检验来完成的:“安全的”树袋熊吃掉的平均食物量与“暴躁的”树袋熊吃掉的平均食物量。输出是 p 值:p 值越高,两组平均值的相似性越大。匹配正是为此而优化的!它选择“暴躁”和“安全”的树袋熊对,产生最高的可能 p 值。

通过匹配方法进行数据预处理越来越受欢迎和有用,特别是在衡量社会政策的影响时。以下是一些最近的例子:

  1. 联合国建设和平行动对维和成功的影响;
  2. 阿根廷工作福利计划“A Trabajar”对收入的影响;
  3. 荜茇水对印度儿童健康的影响。

酷,所以我们想匹配。但是…

我们如何着手匹配呢?

我们用哪些「安全」的考拉做被处理考拉的火柴?通常,我们选择在所选的重要特征上与处理单元最相似的控制单元。对于我们的考拉案例(为了简单起见),我们只考虑一个匹配的协变量:每年食用的桉树数量。我们要确保在火灾之前(例如 2018 年),处理组和对照组的食物消耗量相匹配。否则,它们各自的协变量值可能会受到治疗(2019 年的火灾)的影响,并引入偏差。

我们如何决定哪个控制单元最像被治疗的单元?我们简单地把吃同样数量(以公斤计)食物的“安全的”考拉和“暴躁的”考拉配对。

如果我们有两只对照考拉,它们的食物消耗量与我们要匹配的“暴躁的”考拉相同或等距,参数“用领带匹配”允许我们使用两者并获得两者的平均值(同样适用于三只、四只等)。).

但是如果我们没有任何控制单位(“安全的”树袋熊)和治疗单位(“暴躁的”树袋熊)吃得差不多,那会怎么样呢?我们必须使用这种糟糕的匹配,或者我们可以从我们的最终数据集中完全排除处理过的单元(“火热的”无尾熊,没有“安全的”有相同食欲的无尾熊)。

或者——我们可以用 多个匹配。多重匹配包括将处理过的单元与多个控制单元配对。在实践中,我们决定了一些( M )的“安全”考拉,作为我们“暴躁”考拉的复合搭配。如果我们为每只“暴躁”的考拉决定两次比赛( M = 2),那么两只与“暴躁”考拉最相似的“安全”考拉的食物消耗量被平均(被赋予 0.5 的权重)。

这有什么了不起的?

我们可以达到更好的平衡。
如何?好吧,如果我们在对照组中没有处理过的单元的精确匹配,那么我们的来自多重匹配的复合匹配实际上可以比最接近的匹配更好地接近处理过的值。假设我们想要匹配一只每年吃 200 公斤的考拉,并且正在考虑两只潜在的分别吃 179 和 220 公斤的考拉。一对一的匹配( M =1)会将“安全的”树袋熊与“暴躁的”树袋熊配对,后者吃 220 公斤(因为这是最接近 200 公斤的)。现在让我们考虑多对一匹配,特别是二对一( M =2):复合匹配将平均“吃掉”179 和 220 公斤——返回 199.5 公斤的更接近的匹配(基于食物消耗协变量)。我们可以得到像这样更好的匹配,不仅仅是这只食量一般的考拉,还有许多其他“安全”的考拉,极大地改善了治疗组和匹配后对照组之间的平衡。

很酷,对吧?!我们将在第二部分中探索更多的例子。

但是它变得更好;由于多对一匹配,我们不仅可以获得更好的平衡,而且…

(2)我们使用更多的数据。 在我们的数据集中,控制单元通常比处理单元多。事实上,到目前为止,尽管火灾数量不断增加,谢天谢地,仍然有更多的树袋熊的家没有着火。因此,在我们的数据集中,“安全的”树袋熊比“暴躁的”树袋熊多得多。这太棒了!(不仅仅是为了考拉和物种保护。)

通常,我们使用的数据越多越好。大数定律确保了我们纳入的单位越多——样本量越大,我们的结果就越有可能不是由数据的随机性或特质造成的(方差)。多重匹配,通过使用来自对照组的多个(两个,三个,四个,…,也取决于您设置的 M 单位)用于每个处理单位,最大化样本数据集的使用,并且可以减少可变性

准备看如何?在下一部分中,我们将进一步探讨多重匹配。退房部分 2 这里 !我们试图理解多重匹配何时以及如何可能更好。我们将寻求发现一个最佳的匹配比例。

然而,当我们的数据集变得非常大时(即我们正在处理“大数据”),这种概括就不太适用了。例如,更多信息见此处

**鸣谢 **

感谢vini cius Miranda与我们一起研究我们的想法,并分享他关于因果推理和匹配的细致入微的知识,特别是关于共同支持的主题。我们还要感谢 Alexis Diamond,他鼓励并指导我们分析多对一匹配和一对一匹配的结构。

配对:着火的考拉——第二部分

原文:https://towardsdatascience.com/matching-koalas-on-fire-part-2-71083b81b50b?source=collection_archive---------43-----------------------

最佳匹配比例是多少?1:1 匹配还是 1:多匹配?

合著 斯维特拉娜米店科

此处 检出零件 1 。在这里,我们将告诉您所有关于称为(多重)匹配的工具,并介绍我们的示例数据集——考拉!

David ClodeUnsplash 上拍摄的图像

TL;博士: 匹配被认为是因果推理的黄金工具。我们同意这很棒,但我们大多数人默认将匹配比例参数设置为 1:1。每个被处理的数据单元然后与一个且仅一个控制单元配对,而不是多个控制单元。我们会不会因为依赖毫无疑问的违约而错失了一些额外的权力?我们认为我们可能…我们试图通过定量探索来解决这个问题。结果呢?这真的取决于——尤其是数据集的分布。在下面找出匹配和因果推理的所有细节。

酷,那有什么交易?

到目前为止,该领域的规范是使用一对一匹配( M =1)作为默认和匹配的起点。这放弃了使用多重匹配比率,假设 1:1 通常提供协变量的最佳平衡。然而,我们刚刚在之前的帖子中举例说明了情况可能并非如此。那么,我们如何知道对我们的数据集使用哪个匹配比率呢?下面我们用一些例子来探讨这个问题。

什么时候应该使用多对一匹配?

我们来分析一下。我们可以开始通过定量研究来寻找答案。现在,让我们把多对一匹配看作二对一匹配。我们还将坚持一维匹配——协变量:考拉吃掉的桉树的千克数。

二对一匹配( M = 2)什么时候比一对一匹配( M = 1)效果更好?

图一。有利于二比一匹配的数据点分布。我们可以看到,当红色的 M = 2 时创建的“合成”匹配比当 M = 1 (p 值= 0.88)时发现的单个匹配更接近处理的单位(p 值= 0.97)。同时,根本没有匹配实现了比一对一匹配更好但比二对一匹配更差的平衡(p 值= 0.92)。

图二。有利于二比一匹配的数据点分布。同样,与 M = 1 (p 值= 0)相比, M = 2 (p 值= 0.82)的“合成”匹配更接近于处理过的单位。

简而言之,当多个选择的控制单元的平均值一个最近的控制单元更接近被处理单元的值时,我们希望使用多重匹配。

理想情况下,控制单元与匹配的处理单元(几乎)在相反方向上等距;如果是这种情况,我们得到一个(几乎)完美的匹配(图 1)。

在实践中,如果控制单位与处理单位的平均距离小于一个最近控制的协变量值与处理单位的协变量值之间的差值,则“合成”控制将与协变量更接近。(唷,真拗口!)更简单地说,对照单位与被处理单位的偏差(几乎)“相互抵消”。从数学上讲,我们可以将所选最接近的质控品值与处理过的单位值之间的距离表示如下:

我们刚刚想出了一个定量的方法来衡量什么是最佳的匹配类型!

通过比较通过一对一匹配获得的“距离值”和多对一匹配获得的值,我们可以断定哪种匹配类型将为我们提供被处理单元的最接近匹配(见下文)。这可以使我们的决定不那么武断。

我们也可以对此进行编码(并有可能将其作为一个函数合并到与匹配的库中)。下面是一个伪代码开头:

高层解释

  1. 计算对照单位(匹配)和处理单位之间协变量值的差异。
  2. 如果进行多重匹配,对指定数量的最接近质控品(匹配)重复(1 ),并取这些差异的平均值。
  3. 将一对一匹配获得的值与指定的多对一匹配获得的值进行比较。
  4. 如果多对一匹配的值低于一对一匹配,则优先考虑多对一匹配;反之亦然。

伪代码

表 1。上面的伪代码比较匹配率,并确定单个协变量的最佳匹配率。不同类型的多重匹配比率也可以通过简单地将一对一匹配替换为另一种类型的多重匹配(比如二比一)并计算其各自的“距离值”来进行比较这种算法的进一步发展可以结合使用测径器来避免匹配太不相似单元的偏差。其他考虑因素(即控件和多维度的最大使用)将在【T4 考虑因素和进一步发展】一节中进一步讨论。*见脚注。

什么时候一对一(M = 1)匹配比二对一(M = 2)匹配效果更好?

图三。有利于一对一匹配的数据点分布。此处,二对一匹配导致最差的平衡(p 值= 0.49),因为一个处理单位的质控品存在左/右偏斜。M = 1 达到最佳平衡,p 值为 0.74。离群值的存在使得匹配平衡比一对一匹配(p 值 0.57)差,但仍然比 n M = 1 匹配好。

如果我们对协变量上的处理单位有精确匹配,一对一匹配保证了很大的平衡。如果有“安全的”树袋熊,它们吃 200 和 250 公斤,与我们的两只处理过的树袋熊一样,那么我们将获得 p 值 1,或“完美的”平衡(图 3)。对照组和治疗组的背景特征完全相同。

当除了精确匹配之外的其他控制单元几乎不分布并且仅分布在被处理单元的左侧或右侧时,二比一匹配将执行得更差。例如,如果某个处理过的考拉的所有潜在控制“候选对象”都比它重,那么它们的平均值将大于单个更接近的控制单位(如图 3 所示,当我们对 200 公斤的考拉进行多对一匹配时)。

什么时候一对一(M = 1)匹配和二对一(M = 2)匹配也可以工作?

图 4。一对一匹配和二对一匹配时的数据点分布。这里,在对照组和治疗组中绝对缺乏差异导致任何类型匹配的完美平衡(p 值= 1)。

图 5 。一对一匹配和二对一匹配时数据点的分布。这里,当进行 M = 1 匹配时,允许使用 ties 类似于 M = 2 匹配,并产生与二对一匹配相同的“合成”控制(p 值分别为 0.98 和 0.97)。没有一种匹配能达到更差但仍然很好的平衡(p 值= 0.92)。

如果我们有两只控考拉是精确匹配的,那么,当然,二比一匹配也会达到完美的平衡,就像一对一匹配一样(图 4)。

另一方面,一对一匹配可以采取二对一匹配的形式,并产生同样好的结果。当我们有两个等距控件用于某个单元,并且我们正在与 ties 匹配时,匹配功能将取这些控件的平均值进行一对一匹配。这在技术上与我们进行二对一匹配是一样的。

在这些情况下,我们会优先考虑多重匹配,因为它包含更多的观察结果,并创建更大和更具代表性的样本量。

这一切意味着什么?

在对照组中,每一个治疗单位都不可能完全匹配。考虑到这一点,在我们的理想世界中,我们处理过的单元将被两侧附近的控制单元包围,并“坐”在它们的中心;在被处理的单元周围将有相等的控制单元分布。多重匹配在这里会发挥很大的作用,包括许多控制单元,并生成一个“合成”单元,其特征与我们处理的单元非常相似。

然而,如果控制单元的协变量值都远离(在一个方向上)处理单元的协变量值,那么将处理单元与多个远处的控制单元匹配会使情况变得更糟(图 3)。在这里,我们只想将“暴躁”的考拉与最接近的“安全”考拉进行匹配(或者丢弃数据点)。我们不希望创建一个复合对照,其中包含的协变量值与治疗组的值相差甚远。

那么,我们如何才能巩固这两种对立的行动方针呢?我们可以使用公共支持(字面意义和象征意义)来分配匹配比率。我们为所有在共同支持范围内的处理过的单元确定多重匹配的优先次序——处理过的单元和控制单元之间的重叠范围。这假定在公共支架内控制单元的分布是平衡的。我们知道这些“暴躁”的树袋熊会被一些“安全”的树袋熊包围(就它们的桉树消耗量而言)。

同时,我们希望对协变量值位于边界上或控制单元值的公共支持之外的处理单元使用一对一匹配。这样,饮食模式与任何“安全”考拉明显不同的“暴躁”考拉将只与最接近的食客配对(而不是 2+个非常不同的)。

图 6。治疗组和对照组的假设分布。在这里,人们倾向于在共同支持区域(分布重叠的区域)进行多对一匹配,而在共同支持之外的处理单元进行一对一匹配。

这在实践中会是什么样子?当然,我们必须为它编码。可能是类似基因匹配的功能。我们可以在数据集上运行理想匹配率分类,并将公共支持外的处理单元分配给一对一匹配( M =1),将公共支持内的处理单元分配给多对一匹配( M =2)。产生的向量然后可以被传递到匹配函数中。

酷豆,既然我们调查研究出了一些定量的方法来决定用哪种配比,那就来总结一下吧。

总而言之……

多重匹配的更好性能是一种异常现象,还是经常发生?我们希望上面的例子表明,当前默认的一对一匹配可能不像我们假设的那样合理。对更大(非模拟)数据集的更多研究将有助于确定这一规范挑战在实践中是否成立。

这种调查将有助于归纳多重匹配何时更有可能执行得更好(或更差)。值得探索的领域包括弄清楚当我们匹配多个协变量时会发生什么。如果我们试图找到“安全”的考拉,它们吃得一样,但体重一样或年龄一样,多重匹配会怎么样呢?增加维度是否有利于一定的匹配比例?(仔细考虑如何解决维数灾难将是有价值的。)数据的稀缺性呢?它如何影响我们匹配选择的性能?或者天平的优化是否取决于数据的特定分布时刻?

正如你所看到的,尽管这篇博客很长,但仍然有很多探索的空间…匹配是一个很好的工具,它最近的发展意味着仍然有很多问题需要解决。

如果你还没看够,这里还有一些:

考虑因素和未来发展

虽然多重匹配允许我们利用更多的控制单元,但是我们希望确保避免过度使用特定的控制单元。如果我们允许将与替换匹配——同一个“安全的”考拉可以被用作多个“暴躁的”考拉的(部分)匹配,我们可能会一次又一次地使用同一个控制单元。这可能会导致我们得到一个不具代表性的对照人群样本,从而扭曲我们的最终分析。我们可以通过限制单个控制单元的最大使用量来减轻这种情况(在实践中,我们将修改库匹配并添加一个额外的参数)。

此外,从两个(或多个)与处理单位显著不同的匹配中创建对照也是不公平的。以我们的“火热”考拉科科为例,它每年要吃掉 200 公斤的桉树。如果我们将它与一只每年吃 50 公斤的“安全”小考拉和一只每年吃 350 公斤的异常饥饿的小考拉相匹配,我们将得到一只“合成”考拉,它吃的东西与我们处理过的考拉完全一样。但是我们不能仅仅说科科在其他特征上和我们的小考拉以及我们非常饥饿的考拉加起来是一样的。这可能是不公平的——或者用 CS 术语来说,会产生巨大的偏差— ,如果有不可测量的特征会受到这种选择的影响。对于这种情况,我们可以设定匹配的极限(通过卡尺参数的扩展),这样非常不同的单元就不会匹配。

卡尺、替换、尺寸、公共支持、分布……有很多因素会影响我们对一对一匹配而不是多对一匹配比率的偏好;也许选择最依赖于数据集本身。不过,有一件事我们可以肯定,那就是我们的树袋熊宁愿有一场(或更少)森林火灾,而不是多场…!

链接到上面例子中使用的代码

如果我们做出关键的假设,即距离度量是最大化协变量平衡的最佳方式(正如当前普遍的做法)。

*根据强制实施的距离公差和请求的匹配数量,这可能会导致我们丢弃处理过的单位并使用不同的处理过的样本大小。然后,我们需要将“距离值”(所有处理过的单元的匹配差的最终值(“总处理差”)归一化,方法是将它们除以匹配的处理过的单元的数量( T )。

致谢

感谢vincius Miranda与我们一起研究我们的思想,分享他关于因果推理和匹配的细致入微的知识,特别是关于共同支持的话题。我们还要感谢 Alexis Diamond 教授鼓励我们将多对一匹配与一对一匹配的分析写在博客上!

线性回归假设背后的数学

原文:https://towardsdatascience.com/math-behind-assumptions-of-linear-regression-451532318e8b?source=collection_archive---------34-----------------------

杰斯温·托马斯在 Unsplash 上的照片

在对他们的数据应用线性回归时,必须记住某些假设。当我开始阅读线性回归时,我无法理解这些假设背后的必要性。我们在线性回归中所做的就是最小化预测目标变量( ŷ )和原始目标变量( y )之间的差的平方和,以找到最佳拟合线或平面。在解决这个问题时,为什么下面的假设会出现?为什么要素之间的多重共线性是一个问题。为什么我们要检查残差的分布?为什么我们必须检查观测值之间的自相关性?在理解线性回归的同时,所有这些问题不断出现。所以,我决定在这上面多花些时间,是的,我得到了上述问题的答案。

在这篇博客中,我将通过研究用于解决这个优化问题的数学推导和概念,来解释这些线性回归假设背后的基本原理。

琐碎的假设:

  1. 特征和目标变量之间的线性:

考虑一下这个表达

这里,如果 m1 和 m2 都是实数,那么我们可以说 x1 和 x2 与目标变量(y)线性相关。如果 m1 和 m2 不是实数,那么我们可以说 x1 和 x2 与目标变量 y 没有线性关系。

例如,如果 m1 = x1 和 m2 = x2,那么 y = x13/2 + x23/2,这里 x1 和 x2 都不线性依赖于 y。

2。同方差:同方差意味着从数据中提取的样本的方差应该保持不变,也就是说,我们需要我们的数据点(观察值)更接近我们预测的平面(如果在空间上绘制的话)。

在下图中,您可以看到在第一种情况下方差保持不变(同方差行为),而在第二种情况下方差保持不变(异方差行为)。

同性恋行为

异方差行为

3。没有异常值:因为我们正在处理欧几里德距离,任何异常值都会显著影响我们预测的回归平面。去除异常值,然后执行任何机器学习算法(不仅仅是线性回归)总是更好。

非平凡的假设:

为了理解其他假设背后的原因,有必要进行一些推导。

选择成本函数:

选择【OLS】作为我们的代价函数是有代价的。为了最终确定 OLS 作为我们的成本函数,我们必须处理某些假设。下面的推导将使事情更加清楚。

任何线性方程都可以写成这样的形式,

引入术语 ε(i) 是为了捕捉给定θ(θ)引起的未建模效应和误差。换句话说,它可以被称为误差项或残差。

我们假设 ε 服从高斯分布(均值为零且有一些方差)ε(I)’s独立同相关((i.i.d .)。

页(page 的缩写)D.F 的 ε(i) 可以写成

的概率密度函数ε(i)

也可以写成,

我们的目标是在给定数据的情况下获得最高概率的y(I),也就是说,我们需要最大化每个点的 pdf 的可能性。

我们知道对数是一个单调函数。所以,【L(θ)log(L(θ)) 最大时最大。

利用对数属性展开 log(L(θ))

来源:http://cs229.stanford.edu/notes2020spring/cs229-notes1.pdf,第 10-12 页

l(θ) 在下式最小时最大。

这个表达式就是我们的 OLS(普通最小二乘)成本函数。

注:这是证明选择 OLS 作为成本函数的一种方法。可能有其他方法可以推断出相同的最终结果。

我们选择 OLS 作为成本函数的假设:

在上述推导中,我们假设残差( ε )具有正态分布,因此残差具有正态性。

还有,正如我们假设 ε(i)的 是独立同相关的((i.i.d),残差也应该是独立同分布的。这基本上意味着,残差和时间之间不应该有任何关系。= > 无自相关。

最小化成本函数:现在我们知道了我们的成本函数,我们的下一个目标就是最小化它。有多种方法可以最小化它。我们可以使用迭代算法,如梯度下降,牛顿法等。或者我们可以使用线性代数技术来寻找最优θ。与其他算法相比,后一种算法花费的计算时间少得多,收敛速度也快得多。

使用线性代数最小化成本函数:

在矩阵形式中,成本函数可以写成

应用适当的技术后,表达式最终简化为

推论:

显然,从上面的表达式可以看出,如果 xtx 可逆,则θ(θ)存在。为了使 X T X 可逆,X 应该具有线性独立的列。为了有独立的列,X 不应该有重复的列,因此没有多重共线性

Sklearn 的线性回归使用 LAPACK(用 FORTRAN 和 C 语言编写)进行矩阵的逆运算(XTX)。它根据 LAPACK 中使用的驱动程序,使用 LQ 或 QR 或奇异值分解来求逆。矩阵分解技术用于寻找 XTX 的逆矩阵,即使 XTX 不是满秩矩阵,即 X 没有独立列。

让我们来看一个解释这一点的例子

现在,让我们从 sklearn 的数据集模块加载一个玩具数据集

定义 x,y,然后添加虚拟列(重复列)来检查其性能

运行 sklearn 的线性回归

正如您所看到的,即使在添加了重复的列之后,它仍然工作得很好。

现在,让我们实现一个定制的线性回归模型

这里,由于 xTx 不是奇异矩阵,所以它不能执行运算。

结论

在这篇博客中,我们已经通过一些推导看到了线性回归假设背后的原因。我们也看到了为线性回归实现定制代码的缺点,而如果从 sklearn 的库中取出,它工作得很好,因为它使用了高级矩阵技术。

希望这篇博客能帮助你更好地理解线性回归。

参考文献:

cs-229 课程讲义二,http://cs229.stanford.edu/syllabus-spring2019.html

[## 线性最小二乘(LLS)问题

下一页:广义线性最小二乘法上一页:驱动程序上一页:线性方程内容索引…

www.netlib.org](https://www.netlib.org/lapack/lug/node27.html)

请点击这里查看我的其他博客:

[## 卷积神经网络(CNN)——实用的观点

深入了解卷积神经网络的主要操作,并使用 Mel 光谱图对心跳进行分类…

towardsdatascience.com](/convolutional-neural-networks-cnns-a-practical-perspective-c7b3b2091aa8) [## 端到端案例研究:自行车共享需求数据集

大家好!!

towardsdatascience.com](/end-to-end-case-study-bike-sharing-demand-dataset-53201926c8db)

机器学习的数学:动机

原文:https://towardsdatascience.com/math-for-machine-learning-motivation-25ebbbebff09?source=collection_archive---------13-----------------------

我对为什么我们应该钻研机器学习的数学的看法

一些介绍

大家好!我希望你在这个疫情期间保持安全和理智(在目前世界各地发生的其他前所未有的情况中)。这将是我在 Medium 上的第一篇文章,所以我会尽量简短(即没有真正深入的技术讨论或数学问题)。

简单介绍一下我:我是哥伦比亚大学计算机科学专业二年级的学生,主修应用 ML/NLP。我来自印度尼西亚的雅加达,之前是印度尼西亚 Bukalapak 的一名 ML 工程师,主要从事 NLP 项目,以增强其搜索和问题回答系统。

序言

这里有一个有趣的(在我看来)迷因:

来源:https://medium . com/lets prep/how-to-be-a-data-scientist-in-2019-BCD 64 c0a 1627

如标题所示,这篇文章将讨论理解这个有点被夸大的领域背后的数学的重要性,这样你就不会像上面那个孩子一样跳过重要的基本面。这篇文章是为那些对这个领域相当陌生的人准备的,例如,刚从其他领域转移过来的人,所以当你读完这篇文章的时候,你(希望)有动力去钻研数学。我不会为这篇文章引用任何参考资料,这都是我自己的观点(我希望你会多少同意),基于个人经历。

如果你来自这些背景中的一个或多个(比较科学、数学、统计、运筹学),或者如果你正在从事 ML 工作,你必须意识到 ML 工作现在变得相当容易。有很多工具,每一个都有其特定的用途,都是现成的(Scikit-Learn、Tensorflow、Keras 和 PyTorch 等等)。几行代码就能让你创造出一些新奇的东西(预测模型、聊天机器人、物体探测器等等)。).越来越多的工具出现了,这会让我们更没有动力去钻研数学吗?

答案是有也有没有(我喜欢给出模糊的答案供大家参考)。

如果你是一个被动用户,并且你想保持被动,答案是肯定的。作为一个被动的用户,我的意思是你在使用软件包的时候没有试图去理解那些神奇的软件包背后的数学,或者至少是逻辑。这基本上适用于计算机科学的几乎每个领域,事实上,甚至适用于一般的工程。我能想到的一个有趣的例子是,为什么印度尼西亚在拥有原材料的同时进口如此多有用的商品。我们从来没学过,是吗?

回到主题,如果你属于这些部落之一,答案是否定的:

  1. 你是个用户,但很聪明。这与我在前一段中提到的有关。一个测试你这方面知识的基本问题:“当你使用 Scikit-Learn 时,提及两个内核 PCA 优于标准 PCA 的真实用例!一个用例应该强调结果的有效性,而另一个用例应该强调过程的效率”。
  2. 你想实际上建立自己的 ML 产品。它不一定是顶级的全面研究,在一所著名的大学进行,在 ICML、ACL 等机构发表。事实上,它甚至不一定是什么大事。即使为 Tensorflow 贡献三到五行代码,如果它有助于优化以前效率低下的计算,也可能非常重要。稍后会有更多的介绍。

具体是哪种数学?

我认为这是个大问题,但是相信我,答案相当简单。虽然正确的答案应该是更全面的,但为了简单起见,我只想提到这两个:

1.概率统计(ProbStat)

我想,这是你们大多数人所期待的。当然,你必须掌握所有那些分布的东西(随机变量,期望,插入原理,最大似然法,偏差,等等。),包括传说中的贝叶斯推断(先验分布、后验分布、贝叶斯估计、共轭先验等。).然而,我想强调的是,你们中的一些人(关于你的职业目标)可能不需要深入研究这个话题,高层次的理解就足够了。据我所知,需要对这个主题有一个相当好的理解的人是那些作为(适当的)数据科学家或作为 Quant 工程师工作的人。

当然,数据科学家需要深入了解 ProbStat,因为他们日复一日地为问题定义正确的指标,设计和执行实验/模拟(这包括定义正确的样本),并最终根据某个测试方案(例如 A/B 测试)的结果定义要采取的行动。对于你们中不熟悉的人来说,量化工程师是开发和实现复杂数学模型的人,金融公司用这些模型来做出风险管理、投资和定价的决策。在印度尼西亚,这种工作可能不那么受欢迎。但是,我相信确实有一些,尽管它们可能有不同的名字。事实上,我认为精算工作可以归类为定量工作。我有一个熟人是精算师,他精通这个数学领域。每次我有关于 ProbStat 的问题时,他总能在几分钟内解决,这让我觉得很有趣。

2.线性代数和微积分

我想,这是很少有人会想到的。但是,相信我,如果你像我一样来自计算机科学背景(而不是数学),你可能会比 ProbStat 更喜欢这个主题。我一会儿会讲到的。

由于这个主题非常广泛,我猜你会问 LinAlg & Calc 到底哪一个与 ML 相关。因此,下面我向你展示一些你需要理解的最重要的话题(或者至少简单地了解一下),按照我认为最重要的排序:

  • 向量和矩阵运算/操作
  • 特征值和特征向量
  • 奇异值分解和谱定理
  • 函数凸性
  • 偏导数和链式法则
  • 优化算法(例如梯度下降系列)
  • 内核技巧
  • 矩阵近似

如果以上话题你听起来不熟悉,那也没关系。当我第一次在哥大开始我的旅程时,我很难满足机器学习课程的先决条件(COMS W 4771)。教授是 Daniel Hsu,他是一位出色的讲师和理论上的 ML 研究者,去找他吧()!我大概花了一个月左右的时间才真正适应听课,因为我需要在上课的同时掌握一些先决条件。

也就是说,上述主题在你如何看待机器学习中扮演着非常重要的角色。机器学习经常被说成是“被美化的统计学”。我不是不同意,事实上,我有点同意。但是,我觉得与 ProbStat 相比,ML 对 LinAlg 和 Calc 的重视程度较低。我甚至认为,如今,LinAlg & Calc 对机器学习(或深度学习)的进步贡献更大。一个例子是导致深度学习复兴的优化算法。优化算法(如 SGD)使计算变得轻得多,同时仍然试图在一定程度上保持准确(即,如果您还记得这个概念,试图获得最佳的局部最小值)。因此,我宁愿说机器学习是“被美化的数学”,如果这对你有任何意义的话。

关于实际工作,我还想指出,LinAlg & Calc 更重要,特别是在一定程度上保持正确性的同时尽可能提高计算效率。让我们不谈 ML,而只谈矩阵乘法。像我这样的菜鸟肯定会在立方时间内完成。对于熟悉算法的人来说,他们可能知道并实现了一些更有效的方法,例如 Strassen 算法,它比立方时间(确切地说是 n 的 2.8 次方,n 是输入的大小)快一点。

从这个简单的例子中,我相信你能明白我的意思。关于数值计算有太多的问题。其中的一部分(或者我应该说是大部分)被 Numpy 解决了,Numpy 是一个为优化数值运算而构建的 Python 包。Numpy 然后被 Scikit-Learn 和 Tensorflow 这样的大公司使用。这只是纯粹的数值计算,可能是机器学习层次的最低层(这是我自己编的,所以请不要引用我的话)。诸如以下问题:

  • 我们如何有效地计算大型稀疏矩阵或矩形矩阵的特征向量(例如 PCA)
  • 当矩阵不是满秩的(即解是无穷多的)或者当我们处理的矩阵是不可逆的时,我们如何有效地找到最简单的线性解
  • 我们如何设计一个有效的优化算法,使我们能够在资源不足的情况下处理大量的数据(参见批处理优化)
  • 给定神经网络的特定结构,我们如何得出最佳的初始化参数
  • 我们应该如何设计一个神经网络(特别是关于它的激活函数),以使梯度不会很大程度上消失(见 LSTM 和 GRU 建筑入门)

都在更高的层次上(再说一遍,这是我瞎编的)。有太多的事情需要研究,解决方案通常围绕着 LinAlg & Calc。

如果你渴望成为一名(合适的)ML 工程师,我也渴望成为,在那里你为你的产品构建一个有效的 ML 相关的代码(或者通过仔细选择正确的包和算法,或者甚至当你开始从头编写算法时,哎呀),那么你应该考虑学习我上面提到的 LinAlg & Calc 主题。我想中等水平的理解应该足够了,通过这些因素来衡量(同样,这是我编造的):

  • 您能够为某个问题确定正确的解决方案(预处理、特征表示、建模、后处理),同时考虑正确性(意味着您的解决方案在您的机构/公司期望的程度上是最优的)和效率(意味着您的解决方案可以在某个时间限制内进行推断)
  • 你能够发现某个 ML 产品中的数学瓶颈
  • 当需要时,你可以稍微调整某些 ML 框架(例如 Tensorflow ),使其符合你的需求,例如使用 Tensorflow 子类 API

如果你有很多空闲时间,想更深入地了解,直到你有一个高级的理解水平,你应该去做。在这个水平上,你应该能够为复杂的问题手工编写证明或导出解决方案(例如,证明某个优化算法可以在一定数量的步骤内给出特定问题的解决方案,误差不超过某个ε)。但是,那是在一个完全不同的水平上,我看不到自己在不久的将来能够接近那个水平。通常,拥有机器学习或相关领域(数学、统计学、物理学)博士学位的人是你可以一直依赖的人。

我希望上面的解释对有计算机科学和/或数学背景的人来说是清晰易懂的。我为那些背景之外的人们道歉,因为我需要使用许多技术术语,否则我认为这篇文章的深度会太浅。

结束语

我想现在就这样吧。在 2020 年的最后 3-4 个月里,如果我有时间和资源,我希望我能创造更多的职位,最好是一些更具技术性的职位。请在下面的评论区告诉我,关于机器学习的数学,你想看什么主题!

我想我甚至可以谈谈我在哥伦比亚大学所学课程中的一些 ML 问题集,这对于那些有兴趣看到 ML 中经常涉及的数学例子的人(以及它们是多么的严谨)或者那些计划在未来学习一些关于 ML 的研究生课程的人来说是很有趣的。同时,保持安全,并关心他人!

干杯,

热拉尔

机器学习的数学:概率和统计的先决条件

原文:https://towardsdatascience.com/math-for-machine-learning-prerequisites-7eb1e3faeb3e?source=collection_archive---------67-----------------------

复习一些问题集,包括机器学习的基本概率和统计(ProbStat)

大家好,欢迎来到我的第二篇帖子!这将是我第一篇文章的延续。这里我们要讲技术,或者我应该说有点“数学”。因此,对于已经远离动手数学一段时间的你,我建议你复习概率、统计和微积分方面的内容。你可以在阅读这个故事的过程中这样做,这样你就可以轻松地理解我的解释。

这个故事是受我在哥伦比亚大学所学课程的启发。课程的教学大纲和高级细节可以通过此链接访问:【COMS w 4771 机器学习 2019 秋季由 Daniel Hsu

正如你可能意识到的,你不能访问作业文件(这是教授想要的)。因此,我要讲的习题集也会有些不同,我会说它会是我在课程中所做的一些变化。这不会完全不同,我会尽我最大的努力,这样我就能给出同样水平的东西。

我将在这个故事中给你三个不同的问题,我觉得它们涵盖了你开始学习机器学习(特别是贝叶斯 ML)所需了解的所有基本概念。由于大多数解决方案都不是微不足道的,我要警告你,这个故事将会很长,所以请耐心等待!

最后,在我们开始之前,我想让你知道这个帖子包含了乳胶配方。为了正确地渲染它们,在阅读这篇文章时,安装Math Anywhere插件,并在你的浏览器(我建议使用谷歌 Chrome)上激活它。

问题 1:描述

首先,掌握你的基本概率!

我们将使用 k-最近邻(kNN)算法作为我们的背景故事。如果你不熟悉它,或者如果你需要一些新鲜的东西,我建议你看一看这个惊人的 故事 来自 fellow toward Data Science(TDS)作者。

让我们将范围限制为\(k=1\),即我们将只找到一个最近的邻居。假设我们有\(n\)个训练示例,那么这个算法的复杂度是\(O(n)\)因为我们只需迭代\(n\)个示例,每个示例计算\(L_2\)个差异,然后最后挑选具有最小\(L_2\)个距离的邻居。

假设你在一家公司工作,你的老板要求你加快这个 1-NN 过程的计算速度。他不在乎结果是不是寸寸完美,只要落到最少 10%的邻居身上。例如,如果有 100 万个数据,您挑选的邻居必须在 100k 个数据内,并且具有最小的\(L_2\)距离。

让我们称这个问题为“近似最近邻”,我们应该有下面的数学定义:

给定\mathbb{R}^d\(的测试点\)x,我们说 10%近似的最近邻点是$ x _ { I(x)} s . t . | | x _ { I(x)} | | _ 2 \(是到训练点\) | | x x1 | | _ 2、…,| | x xn | | _ 2 \(的最小 10%距离之一,其中\)n$是训练样本的数量

当然,从训练示例中抽取样本\(\lceil{0.9n}\rceil + 1\)就可以简单地解决上述问题。换句话说,如果您有一百万个数据,只需采样 900k + 1 个数据,无需替换,就可以了。然而,这并没有加快计算的速度,这是相当无用的。

所以,让我提出一些相当出乎意料的东西,至少这是我在处理与这个问题类似的问题时的感受。如果我说,通过精确地采样 50 个例子,称之为\(T=50\),我们可以确保,从数学上讲,我们得到具有最小$ L2 \(距离的 10%例子之外的邻居的概率非常小,最多 0.5%。这与数据量(\)n$)无关。你能证明吗?

问题 1:解决方案

问题 1 的解决方案实际上非常简单,尽管问题的描述有点让人不知所措。看到这基本上只是一个没有更换问题的抽样。我处理这个问题的方法是:既然我们在寻找所有采样数据不在前 10%的概率,那么这与计算所有采样数据(其中 50 个)在其余 90%的数据中的概率是一样的。

因此,我们可以把概率,比如说\(p\)写成:

$ $ p = \ frac { \ text {从 0.9n 个数据中选取 50 个样本的组合数} } { \ text {从 n 个数据中选取 50 个样本的组合数}}$$

*$ $ p = \ frac { \ binom { \ lce il { 0.9n } \ rce il { 50 } } { \ binom { n } { 50 } } = \ frac { \ frac { \ lce il { 0.9n } \ rce il!}{(\lceil{0.9n}\rceil-50)!:50!} } { n!}{(n-50)!:50!} } = \ frac { \ lce il { 0.9n } \ rce il :(n-50)!}{n!😦\lceil{0.9n}\rceil-50)!}=(\frac{(n-50)!}{n!})(\frac{\lceil{0.9n}\rceil!}{(\lceil{0.9n}\rceil-50)!})$ $

\[p=\frac{\lceil{0.9n}\rceil(\lceil{0.9n}\rceil-1)(\lceil{0.9n}\rceil-2)…(\lceil{0.9n}\rceil-49)}{n(n-1)(n-2)…(n-49)}=\prod_{i=0}^{49}\frac{\lceil{0.9n}\rceil-i}{n-i}$$* *不管数据大小如何,我们都有兴趣看看上述概率的值。因此,我的方法是我们取$n \to \infty$。由此得出的概率值将是最高的(试着解释为什么会这样)。因此,我们可以证明这种可能性至多是 0.5%。* *$$p_{n\to\infty}=\lim_{n\to\infty}\prod_{i=0}^{49}\frac{\lceil{0.9n}\rceil-i}{n-i}$$* *使用乘法法则求极限:* *$$p_{n\to\infty}=\prod_{i=0}^{49}\lim_{n\to\infty}\frac{\lceil{0.9n}\rceil-i}{n-i}$$* *这很容易解决,如果不是天花板函数的话。我将把如何解决如果$0.9n$不是整数的问题留给读者作为练习。在这里,我将只讨论更简单的情况,即当$0.9n$是整数时:* *$$p_{n\to\infty}=\prod_{i=0}^{49}\lim_{n\to\infty}\frac{\lceil{0.9n}\rceil-i}{n-i}=\prod_{i=0}^{49}\lim_{n\to\infty}\frac{0.9n-i}{n-i}=\prod_{i=0}^{49}\lim_{n\to\infty}\frac{0.9-i/n}{1-i/n}\]

\[p_{n\to\infty}=\prod_{i=0}^{49}\frac{0.9–0}{1–0}=\prod_{i=0}^{49}0.9={0.9}^{50}= 0.000 美元。20121.868686866667* *我们可以从上面看到,我们没有从前 10%的例子中得到哪怕一个样本的机会(不管数据大小)最多是 0.5%左右。* *这相当了不起,我们可以将复杂度从$O(n)$降低到$O(50)$这是常数!然而,在现实中,情况并非总是如此。在下面的评论部分,让我知道你是否知道为什么会这样!* *PS:您可能会发现另一个问题,请注意,$n \to\infty$的无替换问题抽样可能会被视为(或被视为)有替换问题的抽样!* ## *问题 2:描述* *这将是一个标准的教科书问题,当你学习统计学时,你可能会发现到处都是,这是为了推导最大似然估计(MLE)的公式。但是知道这一点意味着你有一个很好的基础去钻研 ML 的一些子领域,特别是贝叶斯推理。* *如果你不熟悉这个话题,可以考虑看看这篇很酷的文章,也是 TDS 的作者之一。你可能也想熟悉我下面要用到的术语(独立同分布,随机变量,概率密度函数,可能性,等等。).所以,我们开始吧!* > *考虑一个独立同分布随机变量$X_1,X_2,…,X_n$的统计模型,由\ theta \ in \ Theta $参数化。参数空间是 R:\ Theta > 0 \ }$中的正实数\ Theta = \ { \ theta。* > > *$X_1$的分布$P_\theta$如下:* > > *$ X _ 1 \ ~ P _ \有一个概率密度函数(P . d . f .)$ f _ \θ$满足:* > > *$ $ f _ \ theta \ propto 1 \ text { for all } 0 \ leq x \ leq \ theta $ $* > > *$ $ f _ \ theta = 0 \ text { for } x< 0 \text{ and } x >\ theta $ $* > > *给定数据$(X_1,X_2,…,X_n) = (x_1,x_2,…,x_n)$,推导出一个简单的最大似然估计公式!* ## *问题 2:解决方案* *我们将考虑 p.d.f 的两种定义:* 1. *对于$x <0$ and $x> \theta$,f_{\theta}(x)=0$。因此,在这种情况下,可能性总是为零,MLE 也将为零。* 2. *对于$0\leq{x}\leq{\theta}美元,$f_{\theta}(x)\propto1 美元。记住$\propto$意味着 p.d.f .与 1 成比例,但它并不完全是 1,而是某个常数。这意味着$f_{\theta}(x)=c$对于某个常数 c: $0 <c>使用 p.d.f 应该积分为 1 的性质,我们可以确定 c: $c\int_{0}^{\theta}dx=1$ $cx\big|_0^{\theta}=1$ $ $ c[\ theta-0]= 1 $ $ $ $ c = 1/\ theta $ $ 因此,$\{x_1,x_2,x_3,…,x_n\}$的可能性将是: $l(\theta|x)=\prod_{i=1}^{n} f _ { \ theta }(x _ I 因为我们知道$0\leq{x}\leq{\theta}$,所以最小的$\theta$可能是集合中最大的$x$。因此,MLE 公式将是: $\boldsymbol{\max(\{x_1,x_2,x_3,…,x_n\})}$由于$0\leq{x}\leq{\theta}$和$\theta > 0$,此 MLE 公式将总是大于或等于情况 1 的 MLE($ \ geq { 0 })$。因此,我们可以选择它作为我们的 MLE 公式。</c>* ## *问题 3:描述* *在这个问题中,你将看到一些模型来收集数据,确保某种程度的隐私保证,这是一个你可能会感兴趣的话题。* *由于一些国家的选举日即将到来,我认为在这里把它作为背景故事会很有趣。假设其中一个国家有两个总统候选人,称之为国家$U$,即 Murpt 先生和 Nebid 先生。将 Murpt 先生称为$M$而将 Nebid 先生称为$N$。* *想象一下,你是一名独立的数据科学家,一些团体雇用你来估计该国选择其中一名候选人的人口比例。你当然可以很容易地直接问人们他们会投谁的票,但有些人可能会觉得与你直接分享他们的信息很不舒服,因为你基本上什么都不是。* *在这里,我给大家介绍一个概念,叫做“随机化回答”。基本上,它试图通过不直接询问他们的选择来解决隐私问题。相反,您需要对每个被调查的个人进行以下操作:* > *让他/她扔两次硬币,告诉他/她不要让你知道结果* > > *如果至少有一次投掷是正面,告诉他/她如实回答(例如,如果他/她投了$M$那么他/她会告诉你$M$)* > > *如果两次投掷都是反面,告诉他/她给出相反的回答(例如,如果他/她投了$M$,那么他/她会告诉你$N$)* *我认为上面的方案保证了高度的隐私保证,当然,除非硬币被操纵了。* *现在我们来看主要问题。* > *考虑使用上述方案收集的$n$响应的统计模型,其中响应被视为 iid {0,1}值的随机变量$Y_1,Y_2,…,Y_n$,并且所有投掷硬币都是独立的。设[0,1]$中的$ \ theta \表示模型的参数,该参数等于人口中投票给$M$的个体比例。* *然后,回答这三个问题:* > *$Y_1=1$的概率是多少?答案应该以$\theta$的形式给出。* > > *给定数据$y_1,y_2,…,y_n \in {0,1}$的对数似然是多少?答案应该以$\theta$和$y_1,y_2,…,y_n$的形式给出* > > *假设$n=100$,也就是说,我们只从国家的每个州抽取几个人,等于 1 的$y_i$的数量是 40,也就是$\sum_{i=1}^n{y_i}=40$.用[0,1]$绘制对数似然作为$ \ theta \的函数。最有可能出现的$\theta$是什么?* ## *问题 3.1:解决方案* *设 X 是随机变量,表示在两次掷硬币中出现的正面数量($X=[0,1,2]$)。那么,我们可以在下面定义两个概率: $$P(X=0)=P(尾)。P(tails)=(1/2)(1/2)= 1/4 $ $ $ $ P(X \ ge Q1)= 1-P(X = 0)= 1-(1/2)(1/2)= 3/4 $ $* *使用这些概率,$Y_1=1$发生在当一个人选择$M$得到至少一个人头$P(X\geq1)$或当一个人选择$N$没有人头$P(X=0)$时。另外,请记住,选择$M$的概率为$\theta$,选择$N$的概率为$1-\theta$。因此,$P(Y_1)=1$是:* *$ $ P(Y _ 1 = 1)= P(X = 0)(1-\ theta)+P(X \ ge Q1)\ theta $ $ $ P(Y _ 1 = 1)=(1/4)(1-\ theta)+(3/4)\ theta $ $ \ bold symbol { P(Y _ 1 = 1)=(1/2)\ theta+(1/4)} $ $* ## *问题 3.2:解决方案* *因为这个问题涉及到离散的随机变量,我们可以用与建模概率相同的函数来建模可能性。为了计算概率,我们需要定义两个部分:* 1. *$\binom{n}{\sum_{i=1}^{n}y_i}$.说,事件(值为 y_i$)有多少种组合比如$n=2$有四种可能:[0,0],[0,1],[1,0],[1,1]。* 2. *对于每一个事件,如果$y_i=1$,概率将是$P(y_i=1)$,否则如果$y_i=0$,概率将是$P(y_i=0)$。这可以表述为$p(y_i=1)^{y_i}p(y_i=0)^{1-y_i}$,它基本上是一个二项分布。* *因此,可能性是:* *$$l(\theta|n,\sum_{i=1}^{n}y_i)=p(\sum_{i=1}^{n}y_i)|n,\theta)\]

\[l(\theta|n,\sum_{i=1}^{n}y_i)=\binom{n}{\sum_{i=1}^{n}y_i}\prod_{i=1}^{n}p(y_i=1)^{y_i}p(y_i=0)^{1-y_i} \]

\[l(\theta|n,\sum_{i=1}^{n}y_i)=\binom{n}{\sum_{i=1}^{n}y_i}\prod_{i=1}^{n}p(y_i=1)^{y_i}(1-p(y_i=1))^{1-y_i} \]

\[l(\theta|\sum_{i=1}^{n}y_i)=\binom{n}{\sum_{i=1}^{n}y_i}\prod_{i=1}^{n}({\frac{1}{2}\theta+\frac{1}{4}})^{y_i}({-\frac{1}{2}\theta+\frac{3}{4}})^{1-y_i} \]

那么,对数似然将是:

\[\ln{l(\theta|\sum_{i=1}^{n}y_i)}=\ln{\binom{n}{\sum_{i=1}^{n}y_i}\prod_{i=1}^{n}({\frac{1}{2}\theta+\frac{1}{4}})^{y_i}({-\frac{1}{2}\theta+\frac{3}{4}})^{1-y_i}} \]

\[\ln{l(\theta|\sum_{i=1}^{n}y_i)}=\ln{\binom{n}{\sum_{i=1}^{n}y_i}}+\ln{\prod_{i=1}^{n}({\frac{1}{2}\theta+\frac{1}{4}})^{y_i}({-\frac{1}{2}\theta+\frac{3}{4}})^{1-y_i}} \]

\[\ln{l(\theta|\sum_{i=1}^{n}y_i)}=\ln{\binom{n}{\sum_{i=1}^{n}y_i}}+\sum_{i=1}^{n}\ln({\frac{1}{2}\theta+\frac{1}{4}})^{y_i}+\sum_{i=1}^n\ln({-\frac{1}{2}\theta+\frac{3}{4}})^{1-y_i} \]

\[\ln{l(\theta|\sum_{i=1}^{n}y_i)}=\ln{\binom{n}{\sum_{i=1}^{n}y_i}}+\sum_{i=1}^{n}y_i\ln({\frac{1}{2}\theta+\frac{1}{4}})+\sum_{i=1}^n(1-y_i)\ln({-\frac{1}{2}\theta+\frac{3}{4}}) \]

$ $ \ bold symbol { \ ln { l(\ theta | \ sum _ { I = 1 } { n } y _ I)} = \ ln { \ binom { n } { \ sum _ { I = 1 } { n } y _ I } }+\ sum _ { I = 1 } { n } y _ I \ ln({ \ frac { 1 } { 2 })*

问题 3.3:解决方案

问题 3.3 的对数似然图

上面是给定 n=100 和\(\sum_{i=1}^{n}y_i=40\).时,对数似然作为$\ theta \ in[0,1]$的函数的曲线图我用来生成这样的图的代码片段在这个 GitHub Gist 中: log likelihood plot.ipynb

我们可以看到,可能性最大的\(\theta\)似乎在\(0.2\)\(0.4\)左右。让我们通过推导以下对数似然的最优\(\theta\)来验证,即\(\hat{\theta}_{MLE}\)

对应于该图的函数通过代入给定值而导出如下:

*$$l(\theta|n=100,\sum_{i=1}^{n}y_i=40 )=\ln{\binom{100}{\sum_{i=1}{100}y_i}}+\sum_{i=1}y_i\ln({\frac{1}{2}\theta+\frac{1}{4}})+(100-\sum_{i=1}^{100}(y_i))\ln({-\frac{1}{2}\theta+\frac{3}{4}})$$

\[l(\theta|n=100,\sum_{i=1}^{n}y_i=40)=\ln{\binom{100}{40}}+40\ln({\frac{1}{2}\theta+\frac{1}{4}})+(100–40)\ln({-\frac{1}{2}\theta+\frac{3}{4}}) \]

\[l(\theta|n=100,\sum_{i=1}^{n}y_i=40)=\ln({\frac{100!}{60!40!} })+40 \ ln({ \ frac { 1 } { 2 } \ theta+\ frac { 1 } { 4 } })+60 \ ln({-\ frac { 1 } { 2 } \ theta+\ frac { 3 } { 4 } })$ $$\boldsymbol{l(\theta|n=100,\sum_{i=1}^{n}y_i=40)=64.7906+40\ln({\frac{1}{2}\theta+\frac{1}{4}})+60\ln({-\frac{1}{2}\theta+\frac{3}{4}}})\]

为了确定可能性最大的\(\theta\),我们可以对\(L(\theta)\)求一阶导数,然后求出\(\theta\)使其等于零。
$ $ \ frac { d } { d \ theta } L(\ theta)= 0 $ \( \) $ \ frac { d } { d \ theta } \ ln({ \ frac { 100!}{60!40!} })+\ frac { d } { d \ theta } 40 \ ln({ \ frac { 1 } { 2 } \ theta+\ frac { 1 } { 4 } })+\ frac { d } { d \ theta } 60 \ ln({-\ frac { 1 } { 2 } \ theta+\ frac { 3 } { 4 } })= 0 $ \( \) \ frac {(40)(\ frac { 1 } { 2 })} { 1 } { 2 } \ theta*

我们可以看到,这与我们在图中看到的一致。

结束语

我想这就是这个故事的全部内容。很抱歉,我要求你安装Math Anywhere附件来阅读这个故事,因为我找不到任何更方便的方法来在介质上编写 LaTeX。**

我不喜欢上传数学符号的图像,而且 Tex 到 Unicode 对我来说不太好。在下面的评论区,如果你知道任何更好的在媒体上展示数学符号的方法,请告诉我,我会非常感激。

此外,请让我知道你是否对这个话题感兴趣,解释是否清晰简洁,因为我觉得我在这里有点罗嗦。

干杯,

热拉尔

程序员数学——从十进制到二进制的考虑

原文:https://towardsdatascience.com/math-for-programmers-considerations-from-decimal-to-binary-10a21ab980ee?source=collection_archive---------27-----------------------

照片由拉尔姆奇Pixabay 上拍摄

为什么计算机使用二进制数字系统?

众所周知,二进制数是约翰·冯·诺依曼构建的经典计算机世界的基础。是的,当我说经典计算机时,它是你此刻正在使用的设备,除非你是量子计算领域的研究人员。

两种不同的数制之间有什么考虑?还有为什么用二进制而不用十进制?作为计算机科学的基础知识,并不难,但很重要。在本文中,我将分享一些关于十进制和二进制数字系统的注意事项。

十进制数字系统

照片由 geraltPixabay 上拍摄

我还记得小时候,老师开始教我们一些大于 10 的数字。当她提到 11 时,我在纸上写下了“101 ”,并认为这应该是正确的。与英语中“十”和“一”不同于“十一”的“十”和“一”不同,在我的母语中,10 的发音后跟 1 的发音正是 11 的发音。

那堂课之后,我意识到某个地方的数字有它自己严格的含义:)然而,如果我们使用罗马数字,写十个“X”后面跟着一个“I”正好是 11->“Xi”。

当然,数字的位置在阿拉伯数字中起着重要的作用。在十进制数字系统中,我们有 10 个不同的数字,分别是 0、1、2、3、4、5、6、7、8 和 9。

考虑上面显示的数字 3105,它可以写成如下形式。

你一定已经找到了模式:

  • 所有指数的基数都是 10 ,因为数字是十进制数
  • 指数从右到左是 0,1,2,3,因为这个十进制数有 4 个数字。分别是位、十个位、百个位、千个位。

因此,我们可以使用 10 的指数来重写每个十进制数,它们必须遵循如上所示的模式。

那么,二进制数字系统怎么样?

二进制数字系统

照片由 GDJPixabay 上拍摄

你还记得十进制中有 10 个不同的数字吗?在二进制数字系统中,我们只有两个数字:0 和 1。

类似地,我们也可以使用相同的技术重写一个二进制数,遵循类似的模式,但不完全相同。

  • 所有指数的底数都是 2 ,因为这个数是一个二进制数
  • 指数从右到左是 0,1,2,3,因为这个十进制数有 4 个数字。分别是位、位、位、位。

二进制数的差异在上面以粗体文本显示。

知道了这些,我们就可以用我们找到的模式把二进制数转换成十进制数。例如,我们想将 3105 从十进制数转换成二进制数。我们可以首先准备 2 的指数列表如下。

然后,我们可以选择小于最接近我们要转换的数字的最大数字。4096 大于 3105,所以我们必须选择 2,也就是 2048。

然后,我们用 3105 减去 2048,还剩 1057。在那之后,2 ⁰,也就是 1024,是下一个最接近的被选择的,所以我们有 1057 减去 1024 等于 33。最接近 33 的指数是 2⁵的 32,然后我们只剩下一个 2⁰.

所以,我们选择了⁰、2⁵和 2 ⁰.回想一下,指数 11、10、5 和 0 表示位置,所以我们只需要在这些位置上对 1,在其他位置上对 0。

3105 的二进制数是 110000100001。

如果不想准备指数列表或者数量太大,有一个简单的方法。下面的方法可以通过每次将数字除以 2 来确定 1。

每当我们将数字除以 2 时,提醒必须是 0 或 1。提醒的反面将是由十进制数转换而来的二进制数。

为什么计算机使用二进制数?

blickpixelPixabay 上拍摄的照片

为了理解为什么计算机系统中使用二进制而不是十进制,我们需要从我们需要的数字类型的数量开始。

如上所述,十进制数字系统需要 10 个不同的数字来表示一个数。换句话说,每个地方有 10 种不同的可能性。但是,在二进制数系统中,我们只需要 2。

假设你有一个开关,它很容易有两种不同的状态:开和关。是的,这就是我们在计算机世界中表达 1 和 0 的方式。有没有可能设计这样一个可以有 10 种不同状态的开关?我不是电子工程师。我想说这是可能的,但是复杂性会高得多。

我们以加法运算为例,因为它是乘法等其他运算的基础。在二进制中,加法表如下。

但是,如果坚持使用十进制数系统,我们必须让 CPU 理解如下的加法表。

二进制数字系统有什么缺点吗?当然,想想我们刚刚转换成二进制数的数字 3105,也就是 110000100001。假设你和我,我们所有人都能读二进制数,我们需要写 12 位数来表示这样一个数。当你想告诉我三千一百零五这个数字的时候,你得说一一零零零零一零零零零一。我想我跟不上…

因此,二进制数的缺点是,它必须使用太多的数字来表示一个并不那么大的数。

然而,这个缺点并不适用于计算机。不管我们有多少位数,它们都将被存储在 CPU 缓存中。所以,计算机不在乎有多少位数字。相反,他们不擅长处理太多的规则,比如上图所示的加法表。因此,二进制系统成为计算机的完美选择。

摘要

Pixabay 上的 Skitterphoto 拍摄

在这篇文章中,我已经解释了我理解中的不同数制,十进制和二进制。我们人类使用十进制是因为它有更多类型的数字,但我们不必使用太多的数字来表示一个数。此外,我们都有 10 个手指,直观地用于计数。换句话说,十进制在位数和位数类型数之间有着近乎完美的平衡。计算机使用二进制系统,因为它们不需要这样的平衡。相反,他们需要尽可能少的规则,他们不关心数字的数量。所以二进制走在“规则少”的极端一边,成为计算机的完美选择。

** [## 通过我的推荐链接加入 Medium 克里斯托弗·陶

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@qiuyujx/membership)

如果你觉得我的文章有帮助,请考虑加入灵媒会员来支持我和成千上万的其他作家!(点击上面的链接)**

强化学习的数学分析——贝尔曼最优方程

原文:https://towardsdatascience.com/mathematical-analysis-of-reinforcement-learning-bellman-equation-ac9f0954e19f?source=collection_archive---------2-----------------------

度量空间,柯西序列,压缩映射和 Banach 不动点定理

强化学习在玩星际争霸(AlphaStar)和围棋(AlphaGO)这样的游戏中取得了显著的效果。所有这些成功项目的核心在于——马尔可夫决策过程(MDPs)的贝尔曼最优方程。

贝尔曼最优方程

贝尔曼最优方程是一个递归方程,可以使用动态规划(DP)算法来求解,以找到最优值函数和最优策略。在本文中,我将尝试解释为什么贝尔曼最优方程可以通过提供最优策略来解决每个 MDP,并对其进行简单(希望如此)的数学分析。

记号

  • S是状态空间。
  • V是价值函数。
  • V*是最优值函数。
  • V(s)是状态s的值。
  • π是政策。
  • π*是上策。
  • π(s)返回策略π下状态s的动作。
  • P是转移概率矩阵。
  • A是动作空间。

先决条件

尽管我尽了最大努力,但分析还是相当严谨的,我认为读者应该熟悉以下附加条件:

  1. 马尔可夫决策过程(MDP)
  2. 贝尔曼方程及其如何使用迭代法求解。
  3. RL 基础——价值函数、奖励、政策、折扣系数等。
  4. 线性代数
  5. 向量演算

概观

如果您研究过 RL 和 MDP,您一定遇到过这样的说法: “对于每个 MDP,总有至少一个策略优于或等于所有其他策略。”这既出现在萨顿和巴尔托的书中,也出现在大卫·西尔弗的系列讲座中。阅读/听到这些使这种说法变得非常直观,然而,我不得不更深入地挖掘并以更具体的方式理解这一点。因此,在本文中,我将从数学上证明以下定理:

定理:对于任何有限的 MDP,都存在一个最优策略π*,使得它优于或等于其他所有可能的策略π。

在找到最佳策略之前,我们需要了解策略的排序。什么时候一种政策(π1)被认为比另一种(π2)更好?

如果对于环境中的每个状态,使用π1导出的状态的值好于或等于使用π2导出的状态的值,则称策略π1 优于策略π2。从数学上讲,这可以写成如下形式:

政策比较

既然我们知道如何比较政策,我们需要证明总有一个政策比所有其他政策更好。

我们将使用 Banach 不动点定理来证明这一点,通过表明 Bellman 最优算子是具有度量L-无穷范数的实数的完全度量空间上的收缩。为此,我们将首先讨论关于柯西序列不动点问题完备度量空间

上面的段落听起来很吓人,但是一旦我们掌握了基本的术语,它实际上会变得非常简单和直观。我们将讨论以上段落中用粗体字表示的所有内容。让我们遵循自下而上的方法,学习每个概念并克服我们的恐惧:

1.不动点问题

我相信我们大多数人都熟悉求方程根的问题。我们求解x使得函数f(x) = 0。然而,在定点问题中,我们对x进行求解,使得f(x) = x。顾名思义,x是一个固定点,它即使在函数的应用上也不会改变。一个不动点问题可以通过形成另一个函数g(x) = f(x)-x = 0转化为一个求根问题。事实上,即使是求根问题也可以转换回不动点问题。然而,解决不动点问题真的很容易(对于特殊情况),这就是为什么它们非常有趣和有用(没有计算开销)。

解决一个不动点问题,选择一个随机的起始值 x,重复应用 f(x)无限次。如果函数收敛并且你很幸运,你会找到解决方案。

从数学上讲,这很简单,让我们首先描述一个符号:

f^n(x)符号

现在,如果函数是收敛的,那么它一定会收敛到某个值,比如说,x*。这个值,x*确实是不动点问题的解,如下所示:

让我们选择任意值x0并对x0应用函数f(.)无限次以得到x*,然后用它来解决不动点问题:

解决不动点问题

这背后的直觉很简单,如果一个函数在某个点收敛,那么这个函数在这个点的值就是这个点本身。所以,收敛点就是不动点本身。

这也可以从下面的笔记本中观察到:

2.度量空间

度量空间就是一个集合,其中定义了度量来度量该集合中任意两个元素之间的距离。例如,欧几里得空间是一个度量空间,其距离被定义为实数集合中的欧几里得距离。因此,度量空间M被表示为(X, d),其中X是集合而d是某种度量。度量标准d必须满足以下特性:

  1. 识别 d(x,x) = 0
  2. 非否定性
  3. 对称性 : d(x,y) = d(y,x)
  4. 三角形不等式 : d(x,z) ≤ d(x,y)+d(y,z)

3。柯西序列

对于度量空间(X, d),集合X(x1, x2, x3…. xn)的元素序列是柯西序列,如果对于每个正实数*ε*存在一个整数N,使得以下等式成立:

柯西序列

这里的数学解释不是很直观,也没有必要复杂。简而言之,度量空间的元素序列是柯西的,如果这个序列收敛于某点(它们之间的距离变成常数)。关于这一点,另一个很好的解释是由本网站给出的,内容如下:“对于任何小的距离,都有一个特定的指数,超过这个指数,任何两个术语都在彼此的距离之内,这抓住了术语变得接近的直观想法。”“项变得接近”的思想是级数收敛或极限背后的基本直觉。

4.完全度量空间

如果集合X中元素的每个可能的柯西序列收敛到也属于集合X的元素,则度量空间(X, d)是完备的。也就是说,集合的元素的每一个柯西序列的收敛极限都在于集合本身。这就是为什么它被称为“完整”。

5.收缩

如果存在某个常数γ∈[0,1)使得对于度量空间x1x2的任意两个元素,以下条件成立,则定义在度量空间(X, d)的元素上的函数(或算子或映射)是收缩函数(或收缩函数):

收缩映射

这意味着在元素x1x2上应用了映射f(.)之后,它们至少通过因子γ彼此更加接近。还有,这样一个常数*γ* 的最小值叫做 Lipschitz 常数(这是一个对于生成式对抗性网络很重要的常数)。同样,如果*γ=*1,映射不再是收缩而是短映射。直观地,可以观察到在应用收缩映射之后,元素的顺序值越来越接近。

6.Banach 不动点定理

这是我们证据的核心。非正式地,这个定理说,对于一个完全的度量空间,在集合的元素上一次又一次地应用收缩符,将最终使我们得到一个最优的、唯一的值。我们知道:

  1. 承包商将布景的元素组合在一起。
  2. 一次又一次地使用这个承包商,会得到一个序列。(柯西?)
  3. 完备度量空间中的柯西序列总是收敛于度量空间中的一个值。

形式上,这个定理可以表述为:

定理:设(X,d)是完备度量空间且函数 f: X->X 是收缩子那么,f 有一个唯一的不动点 x∈ X(即 f(x)=x)使得序列 f(f(f(…f(x)))) 收敛到 x

现在,为了从数学上证明这一点,我们需要证明x*的唯一性和存在性。

  1. 唯一性:我们用矛盾来证明这一点。假设收敛值不是唯一的,并且x1*x2*是承包商序列收敛的两个值,那么我们将有:

x1和 x2是最佳值,承包商已收敛于此,距离不再改变

另外,请注意f是一个承包商,因此它必须持有以下财产:

承包商财产

现在由于γ∈[0,1),不可能同时满足等式 1 和 2。因此,我们的假设一定是错误的。因此,通过矛盾,x*一定是独特的。

2.存在:现在我们已经证明了x*是唯一的,我们需要证明x*存在。设(x1, x2, x3, …. xn)为重复申请承包人形成的序列。

我们度量空间的一个元素

如果我们假设序列(x1, x2, x3, …. xn)是柯西,我们肯定知道这个序列会收敛到某个点,比如说x*。同样,由于度量空间是完整的,这个收敛点x*将属于度量空间(X,d)。现在,我们只需要证明这个序列是柯西序列。我们将这样做:取集合中的两个元素xnxm,使得m>>nm非常大,然后通过重复应用度量d的三角不等式属性,我们得到:

度量 d 的三角不等式的推广

现在,由于 f 是承包商,我们知道:

重复的承包商不等式

我们可以进一步简化d(xm, xn)如下:

现在,通过选择足够大的n,我们可以使上述等式的 RHS 小于任何正实数*ε* 。因此,序列(x1, x2, x3, …. xn)是柯西的,并且存在一个最优的x*∈X。这就结束了 Banach 不动点定理的证明。

回到贝尔曼最优方程

对于价值函数,V(s)我们定义了一个新的算子,最优贝尔曼算子,B,它接受一个价值函数并返回另一个价值函数。我们将该运算符定义如下:

行李员接线员

很容易观察到,B是一个递归运算符。因此,这将产生一系列的价值函数。如果我们可以证明B确实是某个度量空间(X,d)的收缩者,那么通过 Banach 不动点定理,我们可以得出结论:最优 Bellman 算子的重复应用将最终给出唯一的最优值函数,使用该函数可以导出最优(最佳)策略。因此,我们现在所有的工作都归结为证明B是一个承包商。首先,让我们如下定义度量空间:

度量空间 (X,d):集合X是实数的集合,定义如下:

价值函数属于实数集。底部的 X 表示完整值函数的集合,而顶部的 X 表示单一状态的值集合。

对于度量,我们使用定义如下的L-无穷大范数:

l-无穷范数

根据这个度量,两个值函数之间的距离将等于两者之间的最高元素绝对差。此外,对于具有有限回报的有限 MDP,价值函数将总是停留在实空间中。价值函数不可能不在实空间,因此,这个有限空间永远是完备的。

定理 : Bellman 算子B是有限空间中的压缩映射(R, L-infinity)

证明:设V1V2是两个值函数。然后:

B 是收缩的证明

  • 在上面的第二步中,我们通过将第二个值函数的a’替换为a来引入不等式。这是因为通过用一些其他动作a替换它的最优动作a’,我们减少了它的总价值,从而引入了一个不等式。
  • 在第四步中,我们通过在s’上取最大值来移除 L-无穷范数(回想一下我们设置中关于值函数的 L-无穷的定义)
  • 在最后一步,我们删除了 sigma,因为概率之和总是1

最后,对于贝尔曼最优方程,由于γ∈[0,1)(让我们暂时忽略γ=1的可能性),因此,贝尔曼算子是一个承包商。

现在我们知道:

  1. (R, L-infinity)是一个完备的度量空间
  2. 行李员操作员B是承包商

因此,通过 Banach 不动点定理,我们得出结论,对于每个 MDP,存在唯一的最优值函数V*。利用这个V*,我们可以得出最优策略π*

因此证明了,对于任何有限的 MDP,存在一个最优策略π*,使得它优于或等于所有其他可能的策略π

现在,如何找到这个最优政策和价值函数?一种方法是将 Bellman 算子反复应用于随机初始值函数,以获得最优函数。但是,这在计算上非常昂贵,并且通常完全不可行。因此,我们使用迭代方法,如值和策略迭代,或时间差分方法,如 Q-Learning 或 SARSA。有关这方面的更多信息,请参考我的博客强化学习:时态差异,SARSA,Q-Learning &预期的 python 中的 SARSA或者只是在我的 Github 上查看这些算法: RL_from_scratch

结论

我们学习了一些基本的数学工具,如度量空间,完全度量空间,柯西序列,压缩映射和 Banach 不动点定理。在所有这些的基础上,我们从数学上证明了每个 MDP 的贝尔曼最优方程的唯一最优性。

参考文献和致谢

尾注

我试图用尽可能简单的语言解释一切。如果我不清楚或者我犯了一些错误,请在回复中告诉我。此外,在乳胶方程中可能会有一些错误。如果你找到他们,请让我知道。最后但同样重要的是,感谢阅读!

数学营销:一块可以改变广告方式的微积分

原文:https://towardsdatascience.com/mathematical-marketing-one-piece-of-calculus-that-can-change-the-way-you-advertise-5b861bbbbd70?source=collection_archive---------16-----------------------

当我接受数字营销职位的面试时,有一个问题我很想问:

假设你在营销一种产品,每次转化的利润是 10 美元。你的目标是每次转换的成本是多少?

对于市场营销来说,这是一个相当基本的问题,也是我们在经营市场营销时都会含蓄地回答的一个问题,不管我们喜欢与否。这似乎也是一个非常简单的问题,但是完整地回答这个问题可以教会我们很多关于如何有效地进行营销的知识。

那么,你的目标是什么样的每次转换成本呢?

为了简单起见,我假设每个客户的终身价值与每次转换的利润相同。这实际上是说,每个客户可以转换一次产品,而且只能转换一次。这种假设是大量垂直行业的标准;例如在金融业,客户一生中只购买一次特定品牌的金融产品,如信用卡或保险。

假设不存在,让我们回到问题上来。让我们从问另一个问题开始回答这个问题,为什么你最终要营销这个产品?你想达到什么目的?

对此的回答通常是利润。你推销产品是因为你想获利。

在市场营销的背景下,利润是产生一次转化的成本(每次转化的成本)和转化的利润(毛利)之间的差额。

既然我们清楚自己想要什么,那么我们如何得到它呢?

我们必须意识到的是,利润和我们的目标转化成本之间存在关系。它通常看起来像这样:

在图表的左侧,利润为,每次转换的成本为。发生这种情况是因为,虽然每次转换的低成本可能意味着我们每次转换的高利润,但如此低的每次转换成本阻止了我们实际带来任何大量的转换。因此,我们的整体盈利能力较低。

在图表的右侧(每次转换的成本接近 10 美元),利润为,每次转换的成本为。发生这种情况是因为,虽然我们每次转化的高成本使我们能够带来大量的转化,但每次单独转化的盈利能力非常低。虽然我们可能会带来大量的转化,但每次转化的利润和广告成本之间的差异是如此之低,以至于我们没有产生多少实际利润。

在图表的中间,我们有一个利润高于左边或右边的区域。在这里,我们的每次转换成本既不太低也不太高。这意味着,虽然我们不能以更高的每次转换成本产生尽可能多的转换,但我们仍然产生了一个不错的数字。事实上,我们比上面的最后一个场景产生了更少的转化,这被我们从每个单独的转化中获得更好的利润这一事实所抵消。

因此,与上述两种情况相比,我们能够带来更多的总体利润。

我上面写的在理论上听起来应该是正确的,但是我们实际上如何将这种见解付诸实践可能并不明显。

很容易理解在光谱的两个极端之间有一些中间地带,但是我们实际上如何找到它呢?更简洁地说,什么样的每次转换成本能给我们带来最高的总体利润?

要回答这个问题,我们需要回到什么是利润:

这里的毛利是收入和销售成本之间的差额,所以当广告支出为零时,毛利等于利润。

像大多数数学方程一样,如果我们替换方程中使用的一些术语,我们可以开始更好地理解这个方程。我们知道总利润在某种程度上是我们花费多少的函数,所以我们可以将上面的等式改写为:

为了进一步简化这个等式,我们需要了解毛利到底是什么。特别是,我们需要能够准确理解它与支出的关系。

在我的另一篇文章中,我介绍了几个解决这个问题的方法。为了简单起见,我将只介绍那篇文章中概述的一种方法,这种方法适用于使用智能竞价的谷歌广告活动。

投标模拟器

如果你以前运行过谷歌智能竞价活动,你可能会熟悉一个叫做竞价模拟器的工具。

Bid simulator 可以让您估计如果您改变目标,您的指标会是什么样子。

例如,你可能目前每周带来 60 的转化,每次转化成本为 5 美元;出价模拟器可能会告诉你,如果你的目标是每转换 6 美元,你可以每周带来 63 次转换。

投标模拟器往往会给你一些不同的数据点看。除了您当前每次转换成本的指标之外,它通常会为您提供每次转换成本较低的 2 或 3 次模拟的指标,以及每次转换成本较高的几次模拟的指标。

来自 bid simulator 的数据是非常宝贵的,因为它可以让你准确地了解你的毛利如何依赖于成本。如果您从 bid simulator 复制数据并将其放入 Google Sheets,您可以创建一个如下所示的表格:

在这里,我通过将所有转换数乘以 10 美元(其中 10 美元是我们每次转换的毛利)来计算毛利。我通过将前两列相乘来计算广告成本。

投标模拟器已经基本上告诉我们,多少毛利,我们可以为每一个水平的支出。但是它只告诉我们一些可见的数据点,那么我们如何在更基本的层面上理解这种关系呢?

寻找关系

我们可以尝试找到一个方程来拟合 bid simulator 提供的数据。要做到这一点,让我们根据数据制作一个散点图,并添加一条最佳拟合线。

上图显示了最佳拟合的线性线。显然,我们可以看到上面的数据不是线性的,最佳拟合的线性线没有意义。

如果我们将最佳拟合线的设置切换到对数,看起来这条线更接近数据:

你会注意到在图表的顶部,我设置了 Google Sheets 来显示这条线的等式:

对于那些不熟悉“ln”术语的人来说,它代表一个自然对数。这与指数相反,如果你以前遇到过的话。

现在我们有了一个总利润的等式,我们可以把它代入前面的总利润等式,得到:

这看起来可能有些武断,但是如果我们把它绘制成图表,我们可以看到它向我们展示了一个有趣的形状:

这个图表很有用,因为它告诉我们两件重要的事情:

  • 它告诉我们,有一个大约值 800 美元的花费点,如果我们超过这个点,我们将在营销上赔钱。这是因为每次转换的成本,我们的目标是花费这么多,将等于或大于我们每次转换的毛利,10 美元。
  • 更重要的是,图中有一个大约 200 美元的点,在这个点上我们的利润最大。

这第二点是关键;如果我们能找出多少支出对应于那个峰值,那么这就是我们的最佳支出水平。这是产生最大整体利润的支出水平,因此是我们活动的理想支出金额。

找到最高消费水平

为了找到这个花费水平,我们必须做一点计算。我们之前说过,上图对应于以下等式:

我们知道在图的顶点,图的线是平的。这相当于说,当你处于高峰期时,支出的微小变化对利润的影响很小(如果有的话)。

我们可以通过谈论利润相对于广告支出的导数来数学地表达这一点。这表示广告支出的变化会带来多少利润变化:

  • 在图的左边,导数是正的。这意味着广告支出的增加导致利润增加,也就是说,图表指向上方。
  • 在图的右边,导数是负的。这意味着广告支出的增加导致利润减少,也就是说,图表指向下方。

你可能已经猜到了,图的顶点处的导数等于零。正如我前面所说的,这是因为在高峰期,支出的微小变化对利润没有影响;图表在那一点是平的。

这对我们有什么帮助?

如果你在学校或大学学过微积分,你可能会记得你可以计算方程的导数。如果我们的利润等式是:

然后我们可以算出利润对广告支出的导数是:

现在我们说等式的左边(利润相对于广告支出的导数)当我们在图的顶点时等于零。我们可以这样写:

然后我们可以如下求解:

这告诉我们的是,对应于之前图表峰值的广告支出值是 189 美元。回头看看图表,你会看到这条线。

因此,我们计算出可能给我们带来最大利润的支出水平是 189 美元。

我们可以利用这些信息,将我们的活动预算限制在每周 189 美元,或者我们可以将其转化为每次转化的目标成本。

要完成第二个选项,我们可以回到我们之前提取的投标模拟器数据,它为我们提供了每次转换的成本和支出的数据点:

我们可以像之前一样找出毛利和广告成本之间的关系,也就是找到两者之间的最佳匹配线:

这和我们之前所做的唯一区别是,这次我用多项式方程来拟合图表,而不是对数方程。

你可以在图表的顶部看到这一点。它告诉我们:

如果我们插入之前得到的广告花费的值(189 美元),我们最终得到的成本/转换为3.69 美元

这是我们对初始问题的最佳回答。假设出价模拟器数据在这种情况下是正确的,则使毛利为 10 美元的产品的利润最大化的每次转换成本是 3.69 美元。

  • 如果我们每次转化的成本稍微低一点,那么我们每次转化肯定会带来更多的利润,但这将被更少的转化所抵消。
  • 如果我们的每次转换成本稍微高一点,那么我们肯定会带来更多的转换,但这将被较低的每次转换利润所抵消。

如果我们的每次转换成本在这个范围内,我们带来的利润就会减少:

简单地说,在这种情况下,3.69 美元是每次转换的最佳成本。每次转换的成本不同,不可能产生更多的利润。

最初发表于【https://mackgrenfell.com】

用于研究传染病及其传播率的数学模型

原文:https://towardsdatascience.com/mathematical-models-used-to-study-infectious-disease-and-their-transmission-rate-234267d2714b?source=collection_archive---------40-----------------------

不同建模技术之间的比较

研究感染率的模型【来源:图片由贾科莫·卡拉Unsplash上提供】

我们经常听说数据科学家引用不同的数学模型来分析理论传染率。然而,尽管这些模型在本质上有些复杂,并且包括限制和挑战;然而,在研究任何传染病的传播和感染率时,它们仍然经常被提及。

我们将比较不同的数学模型,以了解它们在正确预测传染病传播率方面的性质和贡献。

  1. SIR (易感、传染、康复)是一种数学建模技术,早期曾用于研究任何传染病的传播率。该模型特别用于研究疾病的传播及其在人群中的感染率。
  2. 另一个研究传染病传播的现实模拟是 GLEaM (全球流行与流动模型)。然而,这个模型提供了一个传染病全球传播的真实模拟。
  3. TRANSIMS ( 运输分析模拟系统)已被用于研究【参考文献 4】中,以模拟由于个人或团体在全球不同地点的旅行或移动而产生的物理接触模式。
  4. IBM (基于个人的模型)(参考。5)辅以 SIR 模型 也被用于跨杂数据建模研究传染病传播率。

爵士型号

SIR 模型是一个常微分方程,用于预测流行病期间的疾病传播和感染率。

S 代表可从传染者处感染疾病的易感个体群体。

I 代表传染个体。

R 代表群体中免疫和死亡个体的“恢复”或“抗性”。

所有这些参数都是函数,可以用线性代数表示为:

S(t) +I(t)+R(t)= N,其中 N 代表总体,t 代表作为时间函数的参数。

S(t) 也可以写成-kIS。它是由于易感者和感染者之间的接触而导致的疾病传播率。

R(t) 可以写成 bI。就是被感染后恢复的速度。

aI 是由于感染导致的死亡率。

因此,从数学上讲,感染率可以写成:

I(t) =kIS-bI-aI。

该型号的局限性

  • 它没有考虑潜伏期(即疾病发作和出现症状之间的时间线)。
  • 其次,在整个建模技术中,假设人口 N 为常数,并且不应用全球旅行的影响。
  • 它没有考虑隔离期。

因此,Volpert 等人(2020 年)开发了一个模型,其中包括隔离的影响,以研究传染病传播率:

I(t)= kI(t)S(t)-kI(t-I)S(t-I)。 其中 I 是潜伏期。

同样,由于隔离而导致的新感染人数 Ro 可以假定为 Ro<1.

Wash your hands and stay safe [Source of Photo :by AllieonUnsplash】

GLEaM ( 全球流行病和流动模型)

这是一个计算流行病模型。这是一个大规模的元种群模型,它认为系统被划分为多个区域,这些区域之间的连接是由于移动基础设施引起的个体流入和流出而产生的。

GLEaM 计算模型考虑了跨地理区域发生的每日人口迁移。它由三个不同的层组成。

(1)人口层

(2)移动层

(3)疾病模型

人口层

地球表面被分成具有适当分辨率的 n×n 平方公里的网格单元。它们还有一个估计的人口值 n。

:为了简化建模,亚人群以机场为中心。同一城市区域中的多个机场的组在分割(分割)之前被聚集。

移动层

这由移动性数据层组成,用于表示上述子群体之间发生的交通或通信。它包括从短程到洲际飞行的不同类型的移动过程。

疾病模型

亚群体 k 中易感个体获得感染的速率用 I (t)表示。然而,与 SIR 模型不同,I(t)的大小受两个因素的影响。

(i)来自其宿主亚群体中另一个个体的感染,k.

(ii)来自通信网络中的个体的相互作用的感染,l.

TRANSIMS ( 运输分析模拟系统)

大多数研究关注的是在疾病爆发期间子人群中个体的均匀混合。然而,该模型利用动态二分图来模拟子群体之间移动期间的物理接触模式。它利用实际的人口普查移动性进行建模,通过在疫情爆发区域放置传感器可以有效地检测到这种移动性。

模拟生成动态接触图,而不是利用前面讨论的经典微分方程。

一个重要的参数是聚集系数,它对疾病传播的速度和程度有影响。它是通过子群体的边连接邻居的范围的度量。

IBM (基于个人的模型)

IBM 模型是基于个体有机体的表示。当在数学模型中使用家庭亚群体相互作用中的个体可变性时,使用它们。它们有多种模式,提供关于“家”亚种群动态的信息。

IBM 与 SEIR 模型相结合来研究意大利流行病[参考文献。5].由于该模型基于单个国家特定的人口统计数据,因此该数据可用于实时评估针对特定人口统计数据采取的措施,以缓解传染病的传播。

例如,国 A 采取的措施在国 B 应用时可能无效。

该模型与中的 SIR 模型(如参考文献 2 中所述)相结合,可以解释为什么减轻全球疫情的中心措施可能无效。

然而,这最后的评论是作者的唯一意见,并开放讨论。

结论

然而,所有这些模型都是理论模型,可能并不总是反映实际统计数据,因为有几个假设用于简化这些模型中的大部分。

参考文献

[1]奇纳齐,m .,戴维斯,J. T .,阿杰利,m .,焦安尼尼,c .,利特维诺娃,m .,默勒,s .,… &维布,C. (2020)。旅行限制对 2019 年新型冠状病毒(新冠肺炎)爆发传播的影响。科学,368(6489),395–400。

[2]Volpert,v .,Banerjee,m .,& Petrovskii,S. (2020)。冠状病毒感染的隔离模型及数据分析。自然现象的数学模型,15,24。

[3]Balcan,d .,Colizza,v .,Gonç alves,b .,Hu,h .,Ramasco,J. J .,& Vespignani,A. (2009 年)。多尺度移动网络与传染病的空间传播。美国国家科学院学报,106(51),21484–21489。

[4]尤班克,s .,古奇卢,h .,阿尼尔·库马尔,v .等人,《模拟现实城市社会网络中的疾病爆发》。《自然》杂志 2004 年第 429 期,第 180-184 页。https://doi.org/10.1038/nature02541

[5]德格利·阿蒂,M. L. C .,默勒,s .,里索,c .,阿杰利,m .,马萨里,m .,曼弗雷迪,p .,…,伊安内利,M. (2008 年)。意大利疫情流感的缓解措施:考虑不同情景的基于个体的模型。PloS one,3(3)。

[6]Balcan,d .,Gonç alves,b .,Hu,h .,Ramasco,J. J .,Colizza,v .,& Vespignani,A. (2010 年)。模拟传染病的空间传播:全球流行病和流动性计算模型。计算科学杂志1 (3),132–145。

[7]格林,沃尔克。"生态模型:基于个体的模型."(2019): 65–73.

Word2vec 模型训练背后的数学

原文:https://towardsdatascience.com/mathematics-behind-the-training-of-word2vec-model-62d7e0ff76e4?source=collection_archive---------15-----------------------

在本文中,我们将了解 Word2Vec 算法训练背后涉及的数学。

在我的上一篇文章中,我们介绍了单词嵌入的基本思想及其使用 genism 库的实现。不了解单词嵌入基础知识的人,我强烈建议他们看看我之前的文章。

[## 基于 Gensim 和 PCA 的单词嵌入向量可视化

在本文中,我们将学习如何使用单词嵌入来训练文本数据,并进一步使用…

towardsdatascience.com](/visualization-of-word-embedding-vectors-using-gensim-and-pca-8f592a5d3354)

Word2Vec 模型的训练可以使用两种算法来完成

单跳格模型

2-连续单词包(CBOW)

在本文中,我们将涉及 SG 模型背后的数学。

约翰·莫塞斯·鲍恩在 Unsplash 上拍摄的照片

跳格模型:

该模型假设在文本语料库中,一个单词可以用来预测其周围的单词。该算法背后的主要思想是,给定一个中心词( Vc ),它试图预测相邻词( Vw )的条件概率,并进一步试图最大化该出现概率。要考虑的相邻单词的数量取决于窗口大小 m。下图使用窗口大小=2 来解释这一想法。

我们假设,给定中心单词,上下文单词彼此独立地生成。在这种情况下,所有单词同时出现的概率公式如下

定义损失函数:

上面的概率计算只是在整个语料库中以某个随机词为中心。但是我们将不得不遍历整个语料库 (T) 以一次一个地将所有单词视为中心单词,并针对 m 的窗口大小来预测其各自的周围单词。最大似然函数可以写成如下

正如我们所知,在梯度计算方面使用对数似然函数总是很容易的,因此我们在两边取对数,并将其转换成对数形式。

现在让我们定义一些符号,因为我们将从这里开始使用它们-

Vc——中心词的向量表示。

Uo-上下文单词的矢量表示。

概率计算:

可以使用 softmax 函数来获得为给定的中心目标单词 c 生成上下文单词 o 的条件概率。为了说服你自己,你可以认为如果两个词是相同的,那么相似度是 1,概率是 1。

softmax 通过对整个词汇 v 进行归一化,将其转换为概率。点积表示两个单词向量之间的相似度。

现在让我们在将表达式代入概率后,写出最终的成本函数。

梯度计算:

我们的主要目标是在一个降维空间中找到文本中每个单词的向量表示。这里的诀窍是每个单词 w 将有两种不同的表示,当单词 w 是中心单词时有一个 Vw ,当单词 w 是上下文单词时有另一个 Uw 。因此,我们之前讨论过的参数θ将是 2V x d 维向量,其中每行代表词汇表中的一个不同单词,其跨列的 d 维向量表示。

现在每个单词有两个向量表示。为了训练我们的模型,我们将对 Vw 和 Uw 求导,并使用梯度下降更新这些向量。 Vc 和 Vw 基本相同。我们刚刚改变了符号,以避免任何混淆。根据矩阵θ,我们只有两个参数 Vc 和 Uw。

相对于 Vc 的梯度:

第一步:

第二步:对第二项应用链式法则。

第三步:

第四步:

相对于 Uw 的梯度:

这里 w 是上下文词。因此,可能有两种情况,o 是上下文单词 w,而 o 不是上下文单词 w。因此,我们将梯度分成两部分来计算相对于 Uw 的梯度。按照和上面 Vc 一样的计算方法,我们可以用对称性写出梯度 w.r.t Uw。

什么时候,

O ≠ W:

O = W:

梯度下降:

现在,我们将使用梯度下降算法更新整个语料库的计算梯度。该算法的伪代码如下所示

然而,这种方法有一个问题。正如我们所见,在梯度的分母中,我们必须取所有单词点积的指数,当我们有大量词汇时,这非常耗时。我们将需要训练数十亿个权重,这在计算上是昂贵的。因此,我们使用一种叫做负采样的技术来解决这个问题。在这种技术中,我们只从基于单字母分布的随机选择的词汇表中抽取少量单词。我不打算在这篇文章中讨论这些细节。

结论:

我希望这篇文章能让您对 Word2vec 模型背后的数学有一个基本的了解。由于嵌入了太多的图片,这篇文章可能看起来有点令人沮丧,但是如果你一步一步地去做,我相信它会非常有帮助。如果你们能给我一些反馈,那就太好了,这样我下次就能以更好的方式展示了。

参考文献:

1-https://papers . nips . cc/paper/5021-单词和短语的分布式表示及其组成性. pdf

感谢您的阅读!!!!

如果你喜欢我的工作并想支持我:

1-支持我的最好方式是跟随我上

2-在LinkedIn上关注我。

数学:科学之母

原文:https://towardsdatascience.com/mathematics-mother-of-science-da5d470d111c?source=collection_archive---------41-----------------------

数据科学之旅的起点

照片由曼塔斯·赫斯塔文Unsplash 上拍摄

在成为专业数据科学家的漫长旅程中,数学是最重要的一步。

在数据科学中的许多标准数据模型和结构的背后,有使它们工作的数学。要成为一名成功的数据科学家,理解数学方程和关系非常重要。实际上,在数据科学的每个步骤中,您将接触到广泛的数学概念和方法,并了解它们是如何出现在数据科学中的。

在本文中,我希望鼓励您熟悉一些最重要和最实用的数学科目,在接下来的文章中,我将为您提供更多关于这一数学子科目的信息,以帮助您成为一名自信而有效的数据科学家。

在数据科学生命周期的许多阶段,有许多相关的数学子课题。我想在这里提几个最重要的。

离散数学

自 17 世纪以来,数学上的许多进展都是在微分和积分方面取得的,微分和积分是实数的性质,是实数的函数。
对这些众多集合的研究导致了连贯和求导概念的出现,为此,这种数学被称为连续数学。但是与这种数学相反,数学中还有其他概念可以定义在有限集合和你的集合上。这些数学概念的集合称为离散数学。
近年来,由于计算机科学的进步,离散数学得到了发展。离散数学中最重要的主题是组合学、图论、数理逻辑、集合论和初步数论。

组合学

组合学是数学的一个领域,主要涉及计数,作为获得结果的手段和目的,以及有限结构的某些性质。它与数学的许多其他领域密切相关,并有许多应用,从逻辑到统计物理,从进化生物学到计算机科学等。我建议从组合学入门开始,这个主题的基础知识对任何从事数据科学的人来说都是至关重要的。

图论

在数学和计算机科学中,图论是对图形的研究。图是由边连接起来的一组顶点。简单来说,由线连接的一组点称为图。图的概念是由欧拉在 1736 年提出的,解决了哥尼斯堡桥问题,并逐渐得到发展。如今,图在数据科学中被广泛使用。

图表在我们周围随处可见。数据科学中最著名的图形类型之一是社交网络图。

数学逻辑和推理

推理在人类生活中的作用是不可否认的。我们都需要在日常生活或职业生活中获得力量。智力屈从于推理的神圣天赋,使人类有可能与人交往,发展各种科学,并在各个领域成长和发展。论证和证明在数学中也有特殊的地位。不考虑论证是无法理解数学的,会把数学教育限制在死记硬背算法上。熟悉数学中的推理和证明方法将有助于理解和发展数学。

集合论

集合论是现代数学的基石。所有数学概念的精确定义都基于集合论。此外,使用逻辑推理和集合论的组合来规范数学推理方法。集合论的语言是世界各地的逻辑数学家说和理解的通用语言。如果一个人要在数学或其实际应用方面取得进步,他必须熟悉集合论的基本概念和结果以及表达它们的语言。

数论

数论是历史背景可以追溯到古代的少数几个数学分支之一。当人类可能对其他科学一无所知,不得不用数字谋生时,这一数学分支被称为其问题的初学者。也就是说,虽然解决数论的很多问题极其困难,但他们的面孔却可以如此简单,甚至引起那些没有见过或讨厌数学教育的人的兴趣和好奇心,并试图去发现它。

微积分

“秋水仙碱”一词最初来自拉丁语,意思是算盘中用来计算的小石灰石卵石。这门学科的名称是一个时代的遗迹,当时古罗马通过在地面上放置石灰石鹅卵石来展示算术和几何概念。在中世纪时期,阿尔哈曾(出生于巴士拉,该地区当时是大伊朗的一部分,也是布伊德酋长国的一部分)推导出了一个四次方和的公式。他利用这些结果进行了现在被称为该函数的积分,其中积分平方和与四次幂的公式允许他计算抛物面的体积。现代微积分是由艾萨克·牛顿和戈特弗里德·威廉·莱布尼茨在 17 世纪的欧洲发展起来的(彼此独立,大约在同一时间首次出版),但是它的元素出现在古希腊,然后是中国和波斯(伊朗的旧称),再后来是中世纪的欧洲和印度。微积分中最重要的主题是函数、极限和连续性、导数及其应用、积分、某些积分、积分方法、双曲函数、向量函数、序列和级数。我想在这里进一步讨论其中的一些话题:

功能

在数学中,函数是为每个给定的输入产生唯一输出的生成器。反过来不能用来定义函数。这意味着一个函数甚至可以为几个不同的输入生成相同的输出。在数学表达式中,函数是第一个元素成对作为输入,第二个元素作为输出的关系。

极限和连续性

在数学中,极限的概念用于表示函数的行为,并在屏幕上的点或无穷远处检查该行为。极限在微积分以及数学分析中用来定义导数和连续性的概念。数学家们甚至在能够表达极限的确切含义之前就已经讨论过这个问题了。古希腊人对极限的概念有所理解。例如,当边数无限增加时,阿基米德通过使用由单一半径的圆包围的垂直多边形的顺序获得近似值。在中世纪,直到文艺复兴时期,各种极限的概念被用来获得各种形状的面积。

导数及其应用

导数的概念直到 17 世纪初才得到发展,直到法国数学家皮耶·德·费玛开始确定某些函数的极值。费马发现切线,其中最大或最小曲线是弯曲的,应该认为确定函数极值点的问题取决于解决另一个问题,即寻找水平切线,试图解决这个普遍问题。这进一步导致费马发现了导数概念的一些基本思想。但是现在形式的导数概念是在 1666 年由牛顿独立提出的,几年后由戈特弗里德·莱布尼茨提出。

导数不仅在数学和现实生活中有各种各样的应用,而且在科学、工程、物理等其他领域也有广泛的应用。一些最重要的主题是变化率,临界点,寻找局部和全局(极端)最大(最小)值,图形的形状,平均值,优化问题和线性近似。

积分和方法

在微分学和积分学中,函数的积分用来概括函数的面积、体积、质量的计算。一个连续的正函数在(a,b)范围内的积分,实际上是求直线 x = a,x = b,和负弯 F 之间的面积,所以 a 和 b 之间的积分 F 实际上是图下的面积。莱布尼茨第一次引入了整合的总督符号。

某些积分可以用数值积分方法来估计。最常见的方法之一叫做矩形法。它几乎是不可分的。估计积分值的其他流行方法是辛普森法和梯形法。虽然数值方法不能给出积分的精确数值,但当积分在函数上不可解或难以求解时,它们有时会给我们很大帮助。积分中最重要的定义是黎曼积分和勒贝格积分。黎曼积分是由波恩哈德·黎曼于 1854 年提出的,它提供了积分的精确定义。

双曲函数

在数学中,双曲函数类似于为双曲线而不是在圆上定义的普通三角函数:正如点(cos t,sin t)形成具有单位半径的圆一样,点(cos t,sinh t)形成等边双曲线的右半部分。

双曲函数出现在许多线性微分方程(例如,定义悬链线的方程)、一些三次方程、双曲几何中角度和距离的计算以及笛卡尔坐标中拉普拉斯方程的解中。拉普拉斯方程在物理学的许多领域都很重要,包括电磁理论、传热学、流体动力学和狭义相对论。

向量函数

vector 这个词的意思是载体,是从一个意思相同的拉丁词派生出来的。向量被定义为向量空间的元素,并且在 n 维空间中具有 n 个分量。所以很明显,页面上的向量有两个分量。或者它需要三维空间中的三个分量。向量在物理等各种科学中有很多应用,没有向量,很多物理分量如速度、加速度等。无法解释和定义。

向量可以相加、相减或相乘。每个向量有两个分量,分别是向量的长度和向量的方向。同样,每个向量都有起点和终点。有单位长度的向量称为单位向量,长度为零的向量称为零向量。在数学中,赋范向量空间中的单位向量是长度为 1 的向量。单位向量通常用带扬抑符的小写字母或“帽子”来表示。术语方向向量用于描述表示空间方向的单位向量,这些量通常表示为 d。

序列和系列

序列是自然数范围(或自然数子集)的函数。这些函数广泛应用于微积分和其他数学分支。有时,序列的名称会改变。例如,在解析数论中,数列被称为算术函数。序列有不同的类型:实数序列、有限序列、无限序列、边界序列、单调序列、算术序列、几何序列、收敛序列、发散序列、斐波那契序列、柯西序列、三角数序列、

级数是一系列项的总和。也就是说,数列是一系列数字,它们之间有加法运算。此外,还有各种级数,包括有限级数、无限级数、几何级数、幂级数、收敛级数、发散级数、交替级数、伸缩级数和带肯定句的级数。

在接下来的故事中,您可以看到成为一名有效和成功的数据科学家所需的其他数学基本要求,包括线性代数、优化和统计。

参考

比格斯,n;劳埃德,e;威尔逊,R. (1986),图论,1736–1936,牛津大学出版社

汤姆·Apostol(1976)。解析数论导论。数学本科教材。斯普林格。ISBN 978–0–387–90163–3。

Larson,r .,Hostetler,R. P .,Edwards,B. H.《微积分与解析几何》,第 7 版,Houghton Mifflin 公司,2002 年。ISBN 0–618–14918-X

(1999)柯林斯简明词典,第四版,哈珀柯林斯出版社,格拉斯哥,ISBN 0 00 472257 4,第 1386 页

西亚达提,萨曼。(2010).数学基础。10.13140/2.2 . 31142.75841/1。

如何在 Python 中使用数学来演奏音乐

原文:https://towardsdatascience.com/mathematics-of-music-in-python-b7d838c84f72?source=collection_archive---------6-----------------------

编程;编排

音乐数学

来源:图片由作者提供(使用 Canva 制作)

为什么一些音符在一起听起来很和谐?而其他人就是不知道。如果你是聋子,你能创作一首音乐吗?哪种声音的“物理结构”使旋律变得优美?

听这段音频,告诉我你听到了什么:

来源:作者视频

我喜欢弹钢琴,我喜欢编程和数学。所以今天我想,为什么不把它们融合在一起,创造出一些很棒的东西。

我的音乐会告诉你比我更多的关于我的事情

音频(上图)仅使用 NumpyScipy合成!如果您不熟悉这些 Python 包,也不用担心。它们并不难理解。**

在本文中,我们将看到如何生成不同频率的波,构建我们自己的虚拟钢琴,并演奏一首歌曲。所有这些,使用我们最喜欢的编程语言,Python。

所以让我们从一些基础开始。

音符只不过是频率

你知道吗?贝多芬,有史以来最著名的作曲家之一,他的大部分职业生涯都是在失聪中度过的!他完全依靠自己对模式的直觉,他发现这些模式对他的观众有效。他将自己的创造力与数学的逻辑(下意识地)混合在一起,谱写出了我们至今仍珍藏的音乐。

为了简单起见,我们将用钢琴作为我们的参考乐器。所以在开始之前,这里有一些基础知识。

钢琴基础

键盘(钢琴/乐器)的构造非常简单。它由多个八度音阶组成。一个八度音阶是一组 12 个键——7 个白键和 5 个黑键

每个键在按下时都会产生不同频率的声音,我们同时按下多个键来演奏和弦。就是这样!

纳米斯

白键被命名为 C、D、E、F、G、A、B ,而黑键则使用两个术语来命名——平(** b )和尖( # ) 。**

如果一个黑键在任何一个白键的右边,它被称为相应白键的升半音。如果它在左边,它就被称为相应白键的降半音。

比如 C 和 D 之间的黑键有两个名字: C# (C 调)和Db(D 调)。这是因为它在 C 的右边,也在 d 的左边。

来源:图片由作者提供(使用 Canva 制作)

为了避免混淆,我们将在本文中使用“尖锐”的术语。此外,“笔记”和“钥匙”这两个词可以互换使用。

记住这一点,让我们开始吧!

理解波浪——快速复习

你一定在物理课上听说过波。像电磁波、机械波、声波等波在某一给定的频率下围绕平衡反复振荡。

从数学上来说,波浪可以用一个波动方程来描述,比如—

g(f) = A sin(2πft)

在哪里,

A =振幅或峰值

f =频率

=时间

我们可以轻松地在 Python 中创建一个函数,生成一个关于时间的波的 NumPy 数组,如以下代码所示:

来源:作者的代码(在 Github 上)

您也可以使用一些库(如 matplotlib )来绘制这个数组,以清楚地了解正在发生的事情。

440 赫兹的频率意味着波在一秒钟内完成 440 个完整的周期。换句话说,它在 1/440 秒内完成一个周期。

由于我们将 1 秒钟分成了 44100 个部分,根据 sample_rate,我们可以通过打印从 0 到 int(44100/440) 的元素来绘制一个周期

****import matplotlib.pyplot as pltplt.plot(a_wave[0:int(44100/440)])
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.show()****

来源:图片由作者提供(使用 Matplotlib 制作)

注意:如你所见,图中的循环是而不是完全完成。理想情况下,这个周期在 100.227 完成,但是由于我们使用的是离散时间间隔(在 100),它稍微偏离初始值(即 0)。****

用 Python 制作你自己的钢琴

如前所述,一架钢琴由 多个 八度音阶组成。虽然每个八度音程在物理上是相同的,但它听起来可能相对于另一个有点高或低。

如果我们想创造一个单一的八度音阶(12 个键的集合),那么我们必须知道每个键是如何相对于另一个键被校准的。之后,我们可以将所有键的频率加倍(或减半),以获得下一个八度。

钢琴使用“平均律系统调音。这意味着键(音符)的频率之间的关系是这样的—

注意频率=基本频率 2^(n/12)*

其中 n 是远离基础音符的音符数。

例如,如果我们认为 c 是我们的基音,那么 C#的频率= base_freq * 2^(1/12)

来源:图片由作者提供(使用 Canva 制作)

我们可以用 python 中的一个 for 循环轻松构建这个逻辑(无需使用任何特殊的库)。

来源:作者的代码(在 Github 上)

现在我们已经准备好了虚拟钢琴,是时候弹奏一些东西了。

播放我们的第一首歌

你在本文开头听到的那首歌叫“啊!你好,妈妈。这是一首流行的法国儿童歌曲,配上简·泰勒的童谣“ 一闪一闪的小星星 ”。**

显然,我演奏了最简单的版本——最少的步骤如下:

第一步:获取你要演奏的歌曲的音符。

***music_notes = 'C-C-G-G-A-A-G--F-F-E-E-D-D-C--G-G-F-F-E-E-D--G-G-F-F-E-E-D--C-C-G-G-A-A-G--F-F-E-E-D-D-C'***

第二步:做一个函数把所有的音符串联起来。

第三步:使用 Scipy 将歌曲写入文件并播放。

***from scipy.io.wavfile import writewrite('twinkle-twinkle.wav', samplerate, data.astype(np.int16))***

结束语

显然,“音乐的数学”比我在这里描述的要多得多。许多问题仍未得到解答,如和声与不和声的理论、和弦与音阶的弹奏、钢琴的调音等等。

希望我稍后会介绍它们。

你可以在我的 Githubrepo上找到完整的源代码。

“难道音乐不能被描述为感觉的数学,数学不能被描述为理性的音乐吗?音乐家感受数学,数学家思考音乐:音乐是梦想,数学是工作生活”——詹姆斯·约瑟夫·西尔维斯特,数学家**

编程快乐!

如果你喜欢阅读这些故事,那么我相信你会很乐意成为一名中等付费会员。每月只需 5 美元,你就可以无限制地接触成千上万的故事和作家。你可以通过 支持我,使用此链接注册,我将赚取一小笔佣金,这将帮助我成长并出版更多这样的故事!**

您可能喜欢的其他一些文章—

*** [## 中等 API —文档

中型 API 入门

medium.com](https://medium.com/geekculture/medium-api-documentation-90a01549d8db) [## 为什么做一个 ML 研究员或者开发者超级难?

这一认识彻底改变了我的生活

medium.com](https://medium.com/towards-artificial-intelligence/why-its-super-hard-to-be-an-ml-researcher-or-developer-67fa62fc1971) [## 我是如何用我独特的“非正式方法”赢得国家级 ML 比赛的

像数据科学黑客一样思考——你不需要遵守规则就能获胜

towardsdatascience.com](/how-i-won-a-national-level-ml-competition-with-my-unique-informal-approach-e86fd95532fd) [## 为什么机器学习正在成为一个笑话?

这个被过度宣传的职业令人不安的真相

medium.com](https://medium.com/datadriveninvestor/machine-learning-is-becoming-a-joke-automl-downsides-c7634ce0572c)***

Matplotlib 备忘单

原文:https://towardsdatascience.com/matplotlib-cheat-sheet-f441c43971c4?source=collection_archive---------14-----------------------

基本情节,包括代码样本。

照片由乔治·特罗瓦托Unsplash 上拍摄

Matplotlib 是 Python 编程语言的绘图库。Matplotib 最常用的模块是 Pyplot,它提供了一个类似 Matlab 的接口,但它使用 Python,并且是开源的。

在本笔记中,我们将重点介绍基本的 Matplotlib,以帮助我们可视化数据。这不是一个全面的列表,但包含了常见类型的数据可视化格式。让我们开始吧!

这张纸条的结构是:

  1. Matplotlib 图形剖析
  2. 从 Pyplot 开始
  3. 图表类型

Matplotlib 图形剖析

人物剖析(作者图片)

一个包含发生绘图的整个窗口。

轴:就是我们一般认为的剧情。每个轴都有一个标题、一个 x 标签和一个 y 标签。

注意:我们可以在一个图形中有多个轴,这有助于构建多个图。

一个图形中可以有多个轴,这有助于构建多个图。(图片由作者提供)

是类似数字线的对象,有助于生成图形界限。每个轴都有一个 x 轴和 y 轴用于绘图。

记号是表示轴上数据点的标记,即用来表示坐标轴上特定点的值。这些值可以是数字或字符串。每当我们绘制图形时,轴会调整并采用默认刻度。Matplotlib 的默认刻度在一般情况下足够了,但绝不是对每个图都是最佳的。

一个图的脊线就是这个图的边。它连接轴刻度线并标注数据区的边界。

从 Pyplot 开始

Pyplot 是 Matplotlib 的一个模块,它提供了简单的功能来添加绘图元素,如线条、图像、文本等。当前图形中的当前轴。

首先,我们设置了用于绘制和导入我们将使用的包的笔记本:

import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid') # Set the aesthetic style of the plots

可以按如下方式创建图形和轴:

fig, ax = plt.subplots()print(type(fig))
print(type(ax))

创建图形和轴

我们通常使用变量名fig来指代一个图形实例,使用ax来指代一个轴实例或一组轴实例。

一旦我们创建了一个轴,我们可以使用plt.plot功能来绘制一些数据。先说一个简单的情节。也许所有图形中最简单的是单个函数y = 2x的可视化。

fig, ax = plt.subplots()
x = np.random.randint(1,10, size=10)
y = 2*x 
plt.plot(x,y) # same as ax.plot(x,y)
plt.show()

y=2x

如果我们想用多行创建一个图形,我们可以简单地多次调用plot函数:

# Multiple lines
fig, ax = plt.subplots()
x = np.random.randint(1,10, size=10)
y = 2*x 
plt.plot(x,y)
plt.plot(x,x+3)
plt.show()

多行

线条颜色和样式

plt.plot()函数接受可用于指定线条颜色和样式的附加参数。为了进行调整,我们可以使用color linestyle关键字,它接受一个表示几乎任何可以想象的颜色/样式的字符串参数。可以通过多种方式指定颜色和样式:

fig, ax = plt.subplots()
x = np.linspace(0,10,1000)
y = 2*x# set of default color and style
plt.plot(x, np.cos(x))# RGB tuple, values 0 to 1, solid style
plt.plot(x, np.sin(x), color=(1.0,0.2,0.3),linestyle='-')# specify color by name, dashed style
plt.plot(x, y, color='blue', linestyle='--')# short color code (rgbcmyk), dotted style   
plt.plot(x, x+3, color='g',linestyle=':')# Grayscale between 0 and 1, dashdot style    
plt.plot(x, np.log(x), color='0.75',linestyle='-.')# Hex code (RRGGBB from 00 to FF), dashed style  
plt.plot(x, x, color='#FFDD44',linestyle='--')

颜色和样式

轴限制

Matplotlib 在为我们的绘图选择默认轴限制方面做得很好,但有时更好的控制也不错。调整轴极限的最基本方法是使用plt.xlim()plt.ylim()方法:

plt.xlim(0, 11)
plt.ylim(-1.5, 10)

设置限制

标签图

作为本节的最后一部分,我们将简要地看一下图的标签:标题、轴标签和简单的图例。

plt.plot(x, np.sin(x), label='y=sin(x)')
plt.plot(x,np.cos(x), label='y=cos(x)')
plt.title('Sine and Cosine Functions ')
plt.xlabel("x-axis")
plt.ylabel("y-axis")
plt.legend() # Describing the element of the graph
plt.show()

给图标上标签

地块类型

使用 python Matplotlib 可以创建各种绘图。在本节中,我们将讨论最常用的数据可视化图。

我们使用来自 Kaggle世界幸福报告数据集。我清理了数据,将所有文件合并到happiness_rank.csv文件中。您可以下载并清理数据,或者只需在此处下载最终结果。我推荐你在 Github 上查看我的数据清理代码。

散点图

散点图是一种常用于统计和数据科学的图表。它由跨两个轴绘制的多个数据点组成。散点图中描绘的每个变量都有多个观察值。每当我们想要查看两组数据之间是否有任何关系时,这是一种非常有用的图表类型。

何时使用散点图

我们使用散点图来确定数据与每个变量的关系(即相关性或趋势模式)。)它还有助于检测图中的异常值。

在机器学习中,散点图常用于回归,其中 x 和 y 是连续变量。它们也用于聚类分散点或离群点检测。

何时避免散点图

如果我们对观察时间模式感兴趣,散点图是不合适的。

散点图用于数字数据或数字。因此,如果我们有三个部门、五个产品等类别,散点图不会揭示太多。

Python 实现

fig, ax = plt.subplots(figsize = (12,6))
x = df['GDP']
y = df['Score']
plt.scatter(x,y)
plt.title('GDP vs Happiness Score')
plt.xlabel('GDP')
plt.ylabel('Score')

散点图

三维散点图

3D 散点图有助于在三维图中显示三个数值变量。

from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(df['Year'],df['GDP'],df['Score'], s=30)
ax.set( xlabel='Year', ylabel='GDP',zlabel='Score')
plt.xticks(np.arange(2015,2020,step =1))
plt.show()

三维散点图

散点图,带有最佳拟合的线性回归线

我们将使用LinearRegression用 Scikit-learn 实现线性回归。创建线性回归对象后,我们可以通过调用 fit 方法来获得最适合我们的数据的直线。

x = df['GDP'].values.reshape(-1,1).astype('float32')
y = df['Score'].values.reshape(-1,1).astype('float32')# Split the data to train and test data
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)# Apply Linear Regression Algorithms
h = LinearRegression()  
h.fit(X_train,y_train)y_pred = h.predict(X_test)fig,(ax1) = plt.subplots(1, figsize = (12,6))
ax1.scatter (X_test, y_test, s = 8)
plt.plot(X_test,y_pred, color = 'black', linewidth = 2)
plt.show()

带有最佳拟合线性回归线的散点图

分叉棒线

发散条形图是一种条形图,其中某些维成员的标记指向上方或右侧,而其他维成员的标记指向相反的方向(分别为下方或左侧)。

N 注:

  • 向下或向左流动的标记不一定代表负值。
  • 发散线可以表示零,但也可以用于简单地分隔二维成员的标记。

何时使用分叉棒线

我们使用分叉棒线来查看项目如何基于单个指标变化,并直观显示这种变化的顺序和数量。如果我们的主要目标是比较每个维度成员的趋势,那么发散条形图是一个不错的选择。

何时避免分叉棒线

使用发散条形图的缺点是不像使用分组条形图那样容易比较维成员之间的值。

Python 实现

我们仅以 2019 年的数据为例。

# Data processing
top_economies = ['United States', 'China','Japan', 'Germany','United Kingdom','India', 'France','Brazil', 'Canada']
df_top = df_19[(df_19['Country'].isin(top_economies))].sort_values(['Country'])
df_top.reset_index(drop=True)x = df_top.loc[:, ['Score']]
df_top['Score_z'] = (x - x.mean())/x.std()
df_top['colors'] = ['red' if x < 0 else 'blue' for x in df_top['Score_z']]
df_top.sort_values('Score_z', inplace=True)
df_top.reset_index(inplace=True)# Draw plot
plt.figure(figsize=(8,6), dpi= 50)
plt.hlines(y=df_top.index, xmin=0, xmax=df_top.Score_z, color=df_top.colors, alpha=0.5, linewidth=20)# Decorations
plt.gca().set(ylabel='Country', xlabel='Happiness_Score')
plt.yticks(df_top.index, df_top.Country, fontsize=15)
plt.title('Happiness Score for Top Economies in 2019', fontdict={'size':20})
plt.grid(linestyle='--', alpha=0.5)
plt.show()

对比图

面积图的概念是基于折线图。彩色区域向我们展示了每个变量随时间的发展。

面积图有三种类型:常规面积图、堆积面积图和百分比堆积面积图。

何时使用面积图

我们用面积图来显示一个完整的部分是如何随时间变化的。例如,幸福分数有六个生成分区;我们希望看到每个分部的贡献。

此外,如果我们感兴趣的是每个分部产生的部分,而不是分部本身的总量,我们可以使用 100%堆积面积图。这将显示一段时间内每个部门的百分比贡献。

何时避免面积图

如果我们想比较不同股票的大小,面积图不是最好的选择。如果你想证明一股超越了另一股;或者,如果我们的值之间的差异非常小,考虑折线图。

Python 实现

# Regular Area Chart
# Create data
x = df_top['Score']
y = df_top['GDP']# Change the color and its transparency
plt.fill_between( x, y, color="skyblue", alpha=0.2)
plt.xlabel('Score')
plt.ylabel('GDP')
plt.plot(x, y, color="Slateblue", alpha=0.6)

规则面积图

# Stacked Area Chart
plt.stackplot(df_top.index,
              [df_top['GDP'], df_top['Health'],
               df_top['Support'], df_top['Freedom']],
              df_top['Generosity'], df_top['Corruption'],
              labels=['GDP', 'Health', 'Support', 'Freedom','Generosity','Corruption'],
              alpha=0.8)plt.legend(loc=2, fontsize='large')
plt.show()

堆积面积图

# 100% Stacked Area Chart
data_perc = df_top[['GDP', 'Health', 'Support', 'Freedom','Generosity','Corruption']]
data_perc = data_perc.divide(data_perc.sum(axis=1), axis=0)plt.stackplot(data_perc.index,
              [data_perc['GDP'], data_perc['Health'],
               data_perc['Support'], data_perc['Freedom']],
              data_perc['Generosity'], data_perc['Corruption'],
              labels=['GDP', 'Health', 'Support', 'Freedom','Generosity','Corruption'],
              alpha=0.8)plt.legend(loc=2, fontsize='large')
plt.show()

百分比堆积面积图

条形图

条形图是最常用的图表类型之一。顾名思义,条形图是由一系列显示变量发展的条形组成的。

条形图有四种类型:常规条形图、水平条形图、组条形图和堆积条形图。

何时使用条形图

当我们想要跟踪一个或两个变量随时间的发展时,条形图非常有用。图表的一个轴显示正在比较的特定类别,另一个轴代表测量值。

何时避免条形图

当我们有一个变量的单周期分解时,简单的条形图是不合适的。例如,如果我想描绘对公司收入有贡献的主要业务线,我不会使用条形图。相反,我会创建一个饼图或其变体。

Python Implementation

# Bar Chartcountries = ['United States','Japan', 'Germany','Brazil', 'India']
y_pos = np.arange(len(countries))
data = df_19[(df_19['Country'].isin(countries))].sort_values(['Country'])
data.sort_values('GDP', inplace=True)
data.reset_index(drop=True)plt.bar(y_pos, data['GDP'], align='center', alpha=0.5)
plt.xticks(y_pos, data['Country'])
plt.ylabel('GDP')
plt.title('Bar Chart')
plt.show()

条形图

# Horizontal bar chartdf_19[(df_19['Country'].isin(countries))].sort_values(['Country'])
data.sort_values('Score', inplace=True)
data.reset_index(drop=True)plt.barh(y_pos, data['Score'], align='center', alpha=0.5)
plt.yticks(y_pos, data['Country'])
plt.xlabel('Score')
plt.title('Horizontal Bar Chart')
plt.show()

# Group bar chart
index = np.arange(5)
width = 0.35fig, ax = plt.subplots(figsize=(9, 6))
rects1 = ax.bar(index - width / 2, data['GDP'],
                width, color='#1f77b4', alpha=0.5)
rects2 = ax.bar(index + width / 2, data['Health'],
                width, color='#1f77b4')
plt.xticks(index, gdp['Country'])
plt.legend((rects1[0], rects2[0]), ('GDP', 'Health'))plt.show()

组条形图

# Stacked bar chart
fig = plt.figure(figsize=(14,10))
rect1 = plt.bar(np.arange(5), data['Support'],
                width=0.5, color='lightblue')
rect2 = plt.bar(np.arange(5), data['Freedom'],
                width=0.5, color='#1f77b4')
plt.xticks(index, data['Country'])
plt.legend((rect1[0], rect2[0]), ('Support', 'Freedom'))plt.show()

堆积条形图

棒棒糖图表

棒棒糖图以一种视觉愉悦的方式提供了与有序条形图相似的用途。我们使用棒棒糖图来显示一个数值变量和另一个数值变量或分类变量之间的关系。

何时使用棒棒糖图表

如果我们要处理大量的值,并且这些值都很高,例如在 80–90%的范围内(100%之外),棒棒糖图通常被认为比普通的条形图有用。那么一大套高大的柱子就可以在视觉上咄咄逼人。

何时避免棒棒糖图表

如果我们的数据中有长度非常相似的未分类棒棒糖——比较两个非常相似的棒棒糖的长度比比较标准棒棒糖的长度更困难。

Python 实现

(markerline, stemlines, baseline) = plt.stem(data['Country'],
                                             data['GDP'])
plt.setp(markerline, marker='o', markersize=15,
         markeredgewidth=2, color='lightblue')
plt.setp(stemlines, color='lightblue')
plt.setp(baseline, visible=False)plt.tick_params(labelsize=12)
plt.ylabel('GDP', size=12)
plt.ylim(bottom=0)plt.show()

棒棒糖图表

柱状图

直方图是描述一组数据分布的垂直条形图。直方图用于显示变量的分布,而条形图用于比较变量。直方图绘制定量数据,将数据范围分组为箱或区间,而条形图绘制分类数据。

N 注意:条形图在列之间有间隔,而直方图没有。

当我们想要显示我们正在处理的数据的分布时,直方图非常有用。这允许我们将连续数据分组到箱中,从而提供观察集中的有用表示。

Python 实现

# Histogram
fig = plt.figure(figsize=(8,6))
plt.hist(df_19['Corruption'], bins=6, density=True)
plt.grid(alpha=0.2)
plt.show()

箱形图(须状图)

箱形图或须状图是一种总结一组区间尺度上测量的数据的方法。这种类型的图形用于显示分布的形状、中心值及其可变性。

箱线图(图片由作者提供)

何时使用箱线图

我们在解释性数据分析中使用箱线图,表明分布是否偏斜,以及数据集中是否存在潜在的异常观察值(异常值)。

当涉及到大量的观察数据和比较两个或多个数据集时,箱线图也非常有用。

何时避免盒状图

箱线图不像茎和叶图或直方图那样详细地显示分布。

Python 实现

假设我们有一个包含 2020 年前六个月媒体成员阅读文章数量的数据集。

# Create dataset
user_1 = [10, 3, 15, 21, 17, 14]
user_2 = [5, 13, 10, 7, 9, 12]
data = [user_1, user_2]
fig = plt.figure(figsize =(8, 6)) 

# Create axes instance 
ax = fig.add_axes([0, 0, 1, 1]) 

# Create plot 
bp = ax.boxplot(data) 

# Show plot 
plt.xticks([1,2],['user_1','user_2'])
plt.show()

箱形图

饼图

饼图是显示群体构成的经典方式。饼图是一个分成若干部分的圆形图。一块越大,它所代表的总量就越大。

然而,现在一般不建议使用,因为饼图部分的面积有时会产生误导。因此,在使用饼图时,强烈建议明确写下饼图每个部分的百分比或数字。

何时使用饼图

饼图最适合描绘整体的各个部分。

何时避免饼图

当我们想要显示一个或多个变量如何随时间发展时,我们不能使用饼图。

Python 实现

假设我们有一个包含中等成员信息的数据集。我们希望看到 2020 年前六个月的文章阅读率。

# Pie Chart
fig = plt.figure(figsize=(8,8))
labels = 'Jan', 'Feb', 'March', 'April', 'May', 'June'
user_1 = [10, 3, 15, 21, 17, 14]
p = plt.pie(user_1, labels=labels, explode=(0.07, 0, 0, 0, 0, 0),
            autopct='%1.1f%%', startangle=130, shadow=True)
plt.axis('equal')for i, (Jan, Feb, March, April, May, June) in enumerate(p):
    if i > 0:
        Jan.set_fontsize(12)
        Feb.set_fontsize(12)
        March.set_fontsize(12)
        April.set_fontsize(12)
        May.set_fontsize(12)
        June.set_fontsize(12)
plt.show()

树形图

树状图类似于饼状图,它在不误导每个小组的贡献的情况下工作得更好。树形图允许我们将整体的总和分成层次,然后显示每个层次的内部分解。

何时使用树形图

树形图通常用于销售数据,因为它们捕获数据类别的相对大小,允许对一个类别内以及多个类别之间的相似性和异常性进行快速、高层次的总结。

何时避免树形图

当我们的数据不能分成类别和子类别时,树形图就不适合了。

此外,当我们用颜色的面积和强度对数据进行编码时,我们的眼睛并不能很好地察觉这些维度中相对较小的差异。如果我们的数据是这样的,我们的受众需要在类别之间进行精确的比较,当类别没有与公共基线对齐时,就更加麻烦了。我们不应该让我们的观众做不必要的工作来理解一个图表!

Python 实现

例如,我们使用一个树形图来显示本月的新用户和文章浏览量。

import squarify
fig = plt.figure(figsize=(10,10))
articles = [17, 22, 35, 41, 5, 12, 47]
labels = ['User_1:\n 17 articles',
          'User_2:\n 22 articles',
          'User_3:\n 35 articles',
          'User_4:\n 41 articles',
          'User_5:\n 5 articles',
          'User_6:\n 12 articles',
          'User_7:\n 47 articles']color_list = ['#0f7216', '#b2790c', '#ffe9a3',
              '#f9d4d4', '#d35158', '#ea3033']
plt.rc('font', size=14)        
squarify.plot(sizes=articles, label=labels,
              color=color_list, alpha=0.7)plt.axis('off')plt.show()

时间序列图

时序图可用于直观显示计数或数值随时间变化的趋势。因为日期和时间信息是连续的分类数据(表示为值的范围),所以点沿着 x 轴绘制,并由连续的线连接。

时间序列分析的目标是发现数据中的模式,并使用数据进行预测。时序图可以回答关于我们的数据的问题,例如:趋势如何随时间变化?

Python 实现

# Time Series Plot
plt.figure(figsize=(8,6))
ts = pd.Series(np.random.randn(100), index = pd.date_range( 
                                '1/1/2020', periods = 100)) 
# Return the cumulative sum of the elements.
ts = ts.cumsum() 
ts.plot() 
plt.show()

时间序列

本笔记中的代码可在 Github 上获得。

就是这样!

在本笔记中,我们学习了如何使用 Matplotlib 构建数据可视化绘图。我们现在可以很容易地构建图表,通过可视化直观地理解我们的数据。

学习愉快!

来源: xkcd

资源:

我的笔记涵盖了所有我认为是 Matplotlib 的基本必需品。掌握一项技能需要几个月,有时几年,所以,不要停止学习!如果你渴望了解更多关于 Matplotlib 的知识,从下面的链接开始吧。

  1. 定制勾 s
  2. Matplotlib 教程
  3. Matplotlib 图库
  4. Matplotlib 用户指南

Matplotlib 多列、多行布局

原文:https://towardsdatascience.com/matplotlib-multi-column-row-spanning-layouts-f026eb7c3c27?source=collection_archive---------42-----------------------

..超越支线剧情中的标准网格布局

图片由 Gerd Altmann 提供,来自 Pixabay

对于 Python 中的可视化来说,Matplotlib 库是相当长一段时间以来的主力。即使在更灵活、代码接口更简单、功能更强大的竞争对手(如 seaborn、plotly、bokeh 等)之后,它也保持了自己的优势。已经到达现场。尽管 Matplotlib 可能缺乏新用户的交互能力,但它在探索性数据分析(EDA)中将我们的数据探索任务可视化方面做得绰绰有余。

在 EDA 过程中,我们可能会遇到这样的情况,我们希望显示一组相关的图,作为一个更大的图片的一部分,以推动我们的洞察力。matplotlib 的subplot函数为我们完成了这项工作。然而,在某些情况下,我们可能想要组合几个支线剧情,并希望每个支线剧情有不同的长宽比。我们怎样才能实现这种布局,其中,本质上一些支线剧情跨越了整个图形的几行/几列?

进入 Matplotlib 的gridspec子模块。

我们首先需要创建一个GridSpec的实例,它允许我们在整个图中指定行数和列数作为参数,以及一个figure对象。

我们将GridSpec实例存储在一个名为gs的变量中,并指定我们希望在整个图形中有 4 行 4 列。

现在,我们需要指定每个子情节如何跨越整个图中的行和列的细节。在纸上画一个草图是很有用的,这样你就可以知道如何安排支线剧情,这样它们就不会重叠。一旦完成,我们就通过我们创建的GridSpec对象传递这个信息。行/列跨度信息以相同的索引符号传递,我们使用该符号对数组/数据帧进行子集化,行和列的索引号从零开始,并使用:指定范围。带有索引的GridSpec对象被传递给figure对象的add_subplot函数。

我们为该图添加了一个总标题,并删除了勾号,以便更好地可视化布局,因为这里的目标是演示我们如何实现跨越多行/多列的支线剧情。当你实现这个的时候,很明显你会想要添加你的轴刻度,标签等等。并调整间距和图形大小以适应这些绘图元素。

嘣!这在多变量时间序列图中可能会很方便,在这种情况下,我们可能希望在顶行显示跨列的时间序列图,并在下面的其他子图中显示其他单变量、多变量可视化。你可以自定义拼图的外观,方法是在整体图形中指定你的行/列,以及各个支线剧情的跨度。

在 R 中,用一行代码中的patchwork包实现上述目标非常简单,除了+/操作符和( ),如果你想发疯的话,甚至可以嵌套支线剧情。点击下面的链接,看看如何在 r。

[## 拼凑——下一代 ggplots

进一步扩展 ggplot2 的多功能性..

towardsdatascience.com](/patchwork-the-next-generation-of-ggplots-1fcad5d2ba8a)

感谢阅读。如果你喜欢这篇文章,你可能也会喜欢下面这篇关于如何用最少的代码行实现最大输出的文章。

[## 使用 SmartEDA 开发的 EDA

探索性数据分析——更智能、更快速的方式..

towardsdatascience.com](/eda-in-r-with-smarteda-eae12f2c6094)

希望听到您的反馈和意见。谢谢!

用于科学绘图的 Matplotlib 样式

原文:https://towardsdatascience.com/matplotlib-styles-for-scientific-plotting-d023f74515b4?source=collection_archive---------6-----------------------

莱斯利·克罗斯Unsplash 拍摄的照片

MATPLOTLIB 简介

为您的科学数据可视化定制 Matplotlib

写这个故事至少有两个灵感。第一个灵感来自我参加的星系和宇宙学暑期学校(SSGC 2020)。它有三个部分:公开讲座,讲座和研讨会。其中一个研讨会使用 Oguri 等人(2012 年)作为主要参考,分析了弱引力透镜现象。Oguri-san 给了参与者他的代码来分析透镜,包括 Maptlotlib 参数设置。我就不说引力透镜了,而是说如何用 Matplotlib 生成一个专业的图,就像小谷三论文里说的那样。

另一个来自于我在阅读总说明时向皇家天文学会月报 MNRAS 提交的一篇文章,这是世界领先的天文学和天体物理学的主要研究期刊之一。说明书中有一部分是如何在 MNRAS 中嵌入数字。建议作者确保他们的图片中使用的颜色是色盲友好的。在这里,我引用说明。

在可能的情况下,请确保您的数字是色盲友好的。在同一张图中使用红色和绿色对一些读者来说尤其成问题(来自 MNRAS 的一般说明)

我对这个指令感到惊讶。我没有意识到我们需要在我的图/图中提供色盲友好,因为我对颜色没有问题。在理解它之后,我建议你(所有的读者)在你的图形/情节中执行色盲友好。我将在下一部分解释更多关于色盲的内容。

主要目标

这个故事将指导你如何:

  1. 使用绘图样式和 rcParams 自定义 Matplotlib 参数
  2. 选择色盲友好

这个故事对于提高数据可视化技能的你来说意义重大,因为我将分享如何基于前面提到的主要目标生成专业的绘图。那么,我们开始吧。

1 .自定义 Matplotlib 绘图风格

Matplotlib 为用户提供了自定义绘图样式的样式包。如果您不改变样式,您将得到一个默认的样式,如图 1 所示。

图一。Matplotlib 中默认的绘图风格(图片由作者/ Rizky MN 提供)。

默认情况下,背景颜色是白色,绘图的第一种颜色是蓝色。您可以使用 样式 语法来更改它,如下面的代码所示。

import matplotlib as plt
plt.style.use('fivethirtyeight') # fivethirtyeight is name of style

应用它之后,您将得到如图 2 所示的结果。

图二。Matplotlib 中的绘图风格 fivethirtyeight (图片作者/ Rizky MN)。

我觉得这很酷。其他款式怎么样?Matplotlib 提供了多少样式?你可以用这个代码来检查。

print(plt.style.available)

您将获得 Matplotlib 提供的所有可用样式,如图 3 所示。

图三。Matplotlib 中的绘图风格(图片由作者/ Rizky MN 提供)。

你会数数吗?:d .在 Matplotlib 中有 26 种不同的样式可以使用。我已经使用所有的绘图样式生成了绘图,但是我将只向您展示其中的四种,如图 4 所示。

图 4。Matplotlib 中的两种出图风格( seaborngg plot)(图片作者/ Rizky MN)。

建议你检查一下 Matplotlib 中所有的绘图样式,选择你喜欢的样式,并将其设为你的默认样式。如果您想要重置绘图样式,可以使用此代码。

plt.style.use('default')

1.b 使用 rcParams 自定义 Matplotlib 参数

回到这个故事的灵感,我将展示 Oguri-san 在他的论文中使用的图形示例,如图 5 所示。

图 5。两个数字的例子见小谷等人(2012)

使用 rcParams 自定义 Matplotlib 参数我将在 Matplotlib 中使用 rcParams 与您分享七个设置。它们是使用 LaTeX 字体、自定义字体大小、调整图例文本长度、自定义轴线宽度、更改 x 轴和 y 轴刻度方向,最后是调整 x 轴和 y 轴刻度的主要和次要大小。我们一个一个来讨论吧。

  • 使用乳胶字体

如图 5 所示,Oguri-san 使用 LaTeX 进行绘图。对于许多人来说,他们需要一些被 Matplotlib 隐藏的特殊符号。在 Matplotlib 中,LaTeX 字体在默认情况下是禁用的。要激活它,您可以使用此代码。

plt.rcParams['text.usetex'] = True

你可以点击这个链接访问我的另一个故事,它解释了更多关于在 Matplotlib 中使用 LaTeX 字体的细节。

[## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05)

如果我在图 4 中应用 LaTeX 字体,我将得到不同的结果,如图 6 所示。您可以比较图 4 和图 6 中的标题、轴、刻度和文本中使用的字体。

图 6。seaborngg plot绘图风格中应用 LaTeX 字体(图片由作者/ Rizky MN 提供)。

  • 调整字体大小

您可以使用此代码调整字体大小。

plt.rcParams[‘font.size’] = 15

Matplotlib 给你 10,以磅为单位,作为默认字体大小。在上面的代码中,我将它从 10 点改为 18 点。参数 font.size 控制所有文本大小,包括标题、x 轴和 y 轴标签、x 轴和 y 轴刻度、图例、文本和注释。您可以使用另一个代码来更改每个元素(例如,标题)的字体大小。例如,您想将所有文本大小调整为 18,但图例将为 20。你可以用这个代码来调整。

plt.rcParams[‘font.size’] = 15
plt.rcParams['legend.fontsize'] = 18

即使您有相同的字体大小,如果您声明了不同的图形大小,您也会得到不同的字体大小表示。这种情况如图 7 所示。

图 7。相似字体大小在不同图形大小中的不同表现(图片由作者/ Rizky MN 提供)。

图 7 中两个图之间的差异来自于以 pts 为单位的字体大小的校准。

  • 改变 x 轴和 y 轴的刻度方向

如果您更详细地查看 Oguri-san 图(图 5 ),您会看到 x 轴和 y 轴上的刻度方向是在轴内,而不是在轴外。可以对比一下图 5 和图 7,特别是在 tick 方向。

默认情况下,记号的方向(x 轴和 y 轴)在轴上。您可以通过键入以下代码来更改它。

plt.rcParams['xtick.direction'] = 'out'
plt.rcParams['ytick.direction'] = 'out'

有三个选项可供使用:in、out 和 inout。您可以在图 8 中看到它们的不同结果。

图 8。Matplotlib 中的 Tick 方向设置(图片作者/ Rizky MN)。

  • 调整主要和次要刻度大小

在图 8 中,我认为你看不出三个图之间的区别,因为分笔成交点的尺寸太小了。怎么把它做大?您可以使用此代码对 x 轴和 y 轴进行更改。

plt.rcParams['xtick.major.size'] = 5.0
plt.rcParams['xtick.minor.size'] = 3.0plt.rcParams['ytick.major.size'] = 5.0
plt.rcParams['ytick.minor.size'] = 3.0

Matplotlib 给出的 xtick 和 ytick 主要大小为 3.5,次要大小为 2.0。要显示次要刻度,可以使用以下代码。

from matplotlib.ticker import MultipleLocatorax.xaxis.set_minor_locator(MultipleLocator(.5))
ax.yaxis.set_minor_locator(MultipleLocator(.005))

当然,你需要定义的使用

*fig, ax = plt.subplots(figsize=(xsize, ysize))*

或者

*ax = plt.gca()*

下面是配置次要刻度的代码

配置主要和次要刻度的代码。

如果您运行代码,您将得到一个图,如图 9 所示。

图九。调整 Matplotlib 中的大小刻度(图片作者/ Rizky MN)。

  • 调整线宽

在这一部分,我将与你分享如何调整轴的线宽。你可以用这个代码来调整。

*plt.rcParams['axes.linewidth'] = 3.0*

默认情况下,线宽设置为 0.8,以磅为单位。我在 3.0 设置的,感受一下默认设置和更新版本的区别。如果您添加上面图 9 中的代码,它将给出如图 10 所示的结果。

图 10。在 Matplotlib 中调整线宽(图片作者/ Rizky MN)。

如图 10 所示,现在次刻度不可见,因为次刻度的大小小于线宽。

  • 调节手柄长度

在最后一部分中,我将演示如何调整句柄长度以及文本图例与其符号之间的距离。我想如果您运行下面的代码并分析结果,您会知道更多,如图 11 所示。

*plt.rcParams['legend.handlelength'] = 5.0*

图 11。在 Matplotlib 中调整图例句柄长度(图片由作者/ Rizky MN 提供)。

您可以在图例框中看到不同之处。我把它设置为 5.0,这样你就可以清楚地看到不同之处。

这是为数据可视化创建科学图的完整样式

*fsize = 15
tsize = 18tdir = 'in'major = 5.0
minor = 3.0lwidth = 0.8
lhandle = 2.0plt.style.use('default')
plt.rcParams['text.usetex'] = True
plt.rcParams['font.size'] = fsize
plt.rcParams['legend.fontsize'] = tsize
plt.rcParams['xtick.direction'] = tdir
plt.rcParams['ytick.direction'] = tdir
plt.rcParams['xtick.major.size'] = major
plt.rcParams['xtick.minor.size'] = minor
plt.rcParams['ytick.major.size'] = 5.0
plt.rcParams['ytick.minor.size'] = 3.0
plt.rcParams['axes.linewidth'] = lwidth
plt.rcParams['legend.handlelength'] = lhandle*

2.创建一个色盲友好的调色板

色盲(或色盲——或更具体的色觉缺乏症(CVD))是众所周知的,但如果你没有遭受痛苦,很难想象。在我知道来自 https://www.color-blindness.com/的数据之前,我没有意识到色盲的人数并不小,大约每 12 名男性中就有 1 人(8%),每 200 名女性中就有 1 人(0.5%)。所以,如果你想生成图形/图,请确保它是色盲友好的。

有四种类型的色盲,它们是色盲、色盲、色盲和色盲。每种类型的详细信息可在这里访问。

对付色盲最安全的方法之一是避免同时使用红色和绿色。简单来说,你可以使用 https://gka.github.io/palettes 的 Gregor Aisch 提供的服务。您可以生成许多调色板,这是色盲友好的。要使用它,首先,您需要选择想要创建的调色板类型。有两个选项,顺序和发散,如图 12 所示。

图 12。生成色盲友好调色板(https://gka.github.io/palettes)。

之后,在同一个部分(第 1 部分),您需要声明想要生成多少种颜色。在这个故事中,我将选择发散的颜色,颜色的数量是 5。

在第二部分,你可以用你想要的十六进制颜色代码填充它。如果你只知道你想要的 RGB 颜色,你可以用这个链接来转换它。我为左侧面板选择这些颜色。

*#0051a2, #10542c, #ffd44f*

这些颜色用于右边的面板。

*lightyellow, #ff005e, #93003a*

在第 3 部分,检查正确的亮度和贝塞尔插值。如果您选择的颜色是色盲友好的,您将在第 3 部分的右侧面板中获得信息“调色板是色盲安全的”,如图 13 所示。

图十三。来自 https://gka.github.io/palettes的色盲友好调色板

然后,向下滚动到第 4 部分“以各种格式导出颜色代码”您可以从第 3 部分的颜色中选择要生成的颜色代码。这是我得到的颜色代码。

*['#0051a2', '#97964a', '#ffd44f', '#f4777f', '#93003a']*

如何应用?只要在你的情节中声明它是你的颜色。这是我的图的例子,如图 14 所示。

图 14。在 Matplotlib 中应用色盲友好(图片由作者/ Rizky MN 提供)。

它仍然很漂亮,当然,对色盲也很友好。您可以改变想要生成的颜色。请确保您收到通知,告知第 2 部分中的调色板是色盲安全的

你可以看到我选择的颜色不是色盲友好的例子。

图 15。不友好的色盲调色板(https://gka.github.io/palettes)。

如果你收到这样的通知,请改变颜色来帮助色盲的人。

如果您想将色盲安全调色板应用到您的色彩映射表,您需要构建自己的色彩映射表。你可以在下面的链接中学习如何使用我的另一个故事来创建你自己的色彩映射表。

* [## 在 Matplotlib 中创建色彩映射表

从颜色列表中创建和定制自己的色彩映射表的指南

towardsdatascience.com](/creating-colormaps-in-matplotlib-4d4de78a04b8)

结论

为了提高使用 Matplotlib 进行数据可视化的技能,您需要制作一个绘图模板。它可以通过选择正确的绘图风格,使用 rcParams 调整一些基本参数,并选择色盲友好调色板来构建。希望这个故事能帮助你考虑到我之前提到的一些信息,创作出科学专业的剧情。

如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:

[## 使用 Matplotlib 实现 Python 数据可视化—第 1 部分

完成了从基础到高级的 Python 绘图的 Matplotlib 教程,包含 90 多个示例

towardsdatascience.com](/visualizations-with-matplotlib-part-1-c9651008b6b8) [## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05) [## 在 Matplotlib 中自定义多个子情节

使用 subplot、add_subplot 和 GridSpec 在 Matplotlib 中创建复杂 subplot 的指南

towardsdatascience.com](/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc) [## Vaex 大数据简介—读取 12.5 亿行的简单代码

用 Python 高效读取和可视化 12.5 亿行星系模拟数据

towardsdatascience.com](/introduction-to-big-data-a-simple-code-to-read-1-25-billion-rows-c02f3f166ec9) [## 如何将 Jupyter 笔记本定制为黑暗模式

一个关于自定义 Jupyter 笔记本主题和轻松调整 Maptlotlib 参数的故事

medium.com](https://medium.com/datadriveninvestor/how-can-i-customize-jupyter-notebook-into-dark-mode-7985ce780f38)

仅此而已。感谢您阅读这个故事。喜欢就评论分享。我还建议您关注我的帐户,以便在我发布新故事时收到通知。

参考

[1] Oguri,M 等人,(2012 年)MNRAS 第 420 卷,第 4 期,2012 年 3 月,第 3213-3239 页,https://doi.org/10.1111/j.1365-2966.2011.20248.x

[2] MNRAS,MNRAS 中提交的一般说明【https://academic.oup.com/mnras/pages/General_Instructions

【3】色盲【https://www.color-blindness.com/的

[4]色盲友好调色板https://gka.github.io/palettes

[5]色码转换https://html-color-codes.info/convert-color-format/*

Matplotlib 提示:如何在绘图上添加文本

原文:https://towardsdatascience.com/matplotlib-tips-how-to-add-text-on-plots-33a87bdd7605?source=collection_archive---------11-----------------------

使用智能文本创建更多信息性的情节。

Unsplash 上由 Neven Krcmarek 拍摄的照片

Matplotlib 是一个广泛使用的 python 数据可视化库。它的语法可能比 seaborn 或 plotly 稍微复杂一点,但这种语法带来了灵活性的优势。我们可以在 matplotlib 图上做任何事情。

图由两个主要部分组成:

  • 身材:身材是维系一切的东西。它就像一个容器,我们把构成情节的其他组件放进去。
  • :我们绘制数据的区域。绘图的其他元素,如标签、图例、刻度都放在轴上。

注意:一个图形可能有多个轴,但是一个轴只能在一个图形上。

关于 matplotlib 有很多内容需要介绍。它提供了我们能想到的几乎任何一种情节。在本帖中,我们将关注一个更具体的主题,即在地块上添加文本。我们将首先创建一个基本的时间序列数据,然后在图上添加一些信息性的文本对象。

让我们从导入我们需要的库开始。

#For generating time series data
import numpy as np#matplotlib
import matplotlib.pyplot as plt
%matplotlib inline

需要%matplotlib 内联魔术命令来渲染 jupyter 笔记本中的绘图。

我们现在可以生成一个基本的绘图。

ser = np.random.randn(100) #time series datafig = plt.figure(figsize=(12,8)) 
ax = fig.add_subplot(111)
plt.grid()
ax.plot(ser)

变量“ser”是保存我们将要绘制的随机时间序列数据的 numpy 数组。在下一行中,我们创建一个大小为(12,8)的图形。然后,我们在图上添加一个。Plt.grid 向绘图添加网格线。最后一行是在轴上实际绘制数据的命令。我们制作的情节是:

看起来是那么的平淡简单。在情节上添加文字之前,让我们使它更有吸引力。我们可以添加一个标题,还可以指定 x 轴和 y 轴的名称。我认为最好调整 y 轴上的范围,这样我们可以有一些空间来添加文本。

ser = np.random.randn(100) #time series datafig = plt.figure(figsize=(12,8)) 
ax = fig.add_subplot(111)
plt.grid()
ax.plot(ser)#title
ax.set_title('Time Series Plot', fontsize=18, fontweight='bold')#axis title
ax.set_xlabel('Day', fontsize=15)
ax.set_ylabel('Value', fontsize=15)#axis limits
ax.axis([0,100, -5, 5])

Set_title 用于添加标题。第一个论点是标题。其余的参数是可选的,用于格式化文本。同样, set_xlabel 和 set_ylabel 用于给 x 轴和 y 轴添加标题。Ax.axis 允许指定数值范围(前两个用于 x 轴,另外两个用于 y 轴)。我们更新的图看起来像:

比之前的版本好看。现在是给我们的情节添加文本的时候了。我们需要指定文本的位置,当然还有文本是什么。例如,下面的代码将添加“随机噪声”文本。它将根据指定坐标的点定位(本例中为[3,4])。参数 bbox 用于捕捉带框的文本。作为 bbox 参数的参数,我们传递一个包含格式样式的字典。

ax.text(3, 4, 'Random Noise', style='italic', fontsize=12, 
        bbox={'facecolor': 'grey', 'alpha': 0.5, 'pad': 10})

我们不必将文本装箱。下面的代码添加不带框的指定文本。

ax.text(60, 4.1, 'No continuous trend observed', fontsize=15,      color='red')

我们还可以添加带注释的文本。例如,我们可以用标记和注释来标记时间序列数据的峰值:

ax.plot([33.5], [2.5], 'o')ax.annotate('peak', xy=(33.5, 2.5), xytext=(40, 4), 
             fontsize=12,      
             arrowprops = dict(facecolor='black', shrink=0.05))

我们首先添加一个圆形标记,然后添加带有指向该标记的箭头的文本。 xy 参数包含箭头的坐标, xytext 参数指定文本的位置。 Arrowprops 顾名思义,是用来给箭头做样式的。

让我们把所有这些放在一起,看看我们剧情的最终版本。

ser = np.random.randn(100) #time series datafig = plt.figure(figsize=(12,8)) 
ax = fig.add_subplot(111)
plt.grid()
ax.plot(ser)#title
ax.set_title('Time Series Plot', fontsize=18, fontweight='bold')#axis title
ax.set_xlabel('Day', fontsize=15)
ax.set_ylabel('Value', fontsize=15)#axis limits
ax.axis([0,100, -5, 5])#text
ax.text(3, 4, 'Random Noise', style='italic', fontsize=12,
        bbox={'facecolor': 'grey', 'alpha': 0.5, 'pad': 10})ax.text(60, 4.1, 'No continuous trend observed', fontsize=15,  color='red')#annotation
ax.plot([33.5], [2.5], 'o')ax.annotate('peak', xy=(33.5, 2.5), xytext=(40, 4), fontsize=12,
            arrowprops=dict(facecolor='black', shrink=0.05))

感谢您的阅读。如果您有任何反馈,请告诉我。

Matplotlib 到 Plotly 图表转换

原文:https://towardsdatascience.com/matplotlib-to-plotly-chart-conversion-4bd260e73434?source=collection_archive---------17-----------------------

将使用熊猫创建的 Matplotlib 图转换为 Plotly 图的实验

将 Matplotlib 图转换为 Plotly 图

介绍

你有没有想过从数据帧中直接创建 Plotly 图表?

Pandas 目前使用 Matplotlib 作为默认的绘图后端。从 0.25 版本开始,还支持其他后端散景。但是,目前不支持 Plotly。因此,我决定看看是否有可能将 Matplotlib 图表转换成它的 Plotly 等价物。

如果您想继续阅读本文,这里有完整的代码。

窥视引擎盖下

第一步是检查每个库如何在内部表示图。

两个库的内部工作是如此的抽象,以至于对于大多数常见的绘图目的,我们几乎不需要修补内部。将绘图提升到一个更高的抽象层次。您只需在数据帧上调用plot(),可选地指定绘图种类,进行即时绘图——不需要创建空图形、设置轴标签、图例等等。例如,

data = df.groupby('year').sum()[["major_death", "major_capture"]]
ax = data.plot.bar(rot=0)

Matplotlib 轴属性

我从检查由data.plot返回的AxesSubplot对象ax开始。快速搜索后,我发现AxesSubplot对象有一个[properties()](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.axes.Axes.properties.html#matplotlib.axes.Axes.properties)方法,将它们的属性作为一个字典返回。

以下是来自我的 Kaggle 笔记本的条形图,其中包含关于《权力的游戏》战斗和死亡数据的 EDA。

图表下方是由ax.properties()返回的属性片段。

Matplotlib 剧情:《权力的游戏》中按年份划分的主要死亡/俘获事件

children属性包含呈现为条形的Rectangle对象。自然地,Rectangle封装了大部分绘图信息(x 坐标、高度和宽度)。title是图的标题,xlabelylabel分别是 x 轴和 y 轴标题。

{
  'adjustable': 'box',
  'axes_locator': None,
  '**children**': [
    <matplotlib.patches.Rectangle at 0x1f7aa154608>,
    ...
    <matplotlib.legend.Legend at 0x1f7ab154ac8>
  ],
  'data_ratio': 3.0,
  'facecolor': (1.0, 1.0, 1.0, 1.0),
  'figure': <Figure size 1080x432 with 1 Axes>,
  ...,
  'title': 'Major death/capture events by year',
  'xlabel': 'Year',
  'xticklabels': <a list of 3 Text major ticklabel objects>,
  'ylabel': 'No. of Death/Capture Events',
  'yticks': array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]),
}

Plotly 图形属性

下面是上面条形图的示意图。它的属性在它下面。

《权力的游戏》中按年份划分的主要死亡/俘获事件

data是包含上述绘图所需的几乎所有信息的属性。在layout属性下,titlexaxis.titleyaxis.title包含图标题和轴标题。

{
  "**data**": [
    {
      "marker": {
        "color": [
          "rgb(31.0,119.0,180.0,255.0)",
          ...
          "rgb(255.0,127.0,14.0,255.0)"
        ]
      },
      "type": "bar",
      "width": [0.25, ..., 0.25],
      "x": [-0.25, 0.75, 1.75, 0, 1, 2],
      "y": [4, 8, 1, 3, 6, 2]
    }
  ],
  "layout": {
    "barmode": "group",
    "template": {
      "data": {
        "bar": [
          {
            "error_x": {"color": "#2a3f5f"},
            "error_y": {"color": "#2a3f5f"},
            "marker": {...}
          }
        ], ...
        "table": [...]
      }, ...
    },
    "title": {"text": "Major death/capture events by year"},
    "xaxis": {"title": {"text": "Year"}, ... },
    "yaxis": {
      "range": [0, 9],
      "title": {"text": "No. of Death/Capture Events"}
    }
  }
}

Matplotlib 图与 Plotly 图

请注意,虽然 Plotly 图形是 Matplotlib 图形的顶级对应物,但 Plotly 图形Matplotlib 图形是不同的概念。

然而,我们直接反映了AxesSubplot的属性,即使它是包含在图形中的。这是因为AxesSubplot包含了我们所有感兴趣的对象。

然而,如果图中包含如下所示的支线剧情,我们必须反映每个支线剧情的属性。注意图fig中包含的四个AxesSubplot对象。

fig, axes = plt.subplots(2, 2)
print(fig.properties())**# Output**
{
    "agg_filter": null,
    ...,
    "axes": [
        <matplotlib.axes._subplots.AxesSubplot at 0x1f...>,
        <matplotlib.axes._subplots.AxesSubplot at 0x1f...>,
        <matplotlib.axes._subplots.AxesSubplot at 0x1f...>,
        <matplotlib.axes._subplots.AxesSubplot at 0x1f...>
    ],
    ...
}

构建 Matplotlib 到 Plotly 的转换器

从这里开始,我们将把plotly.graph_objects简称为go

条形图转换器

根据上一节的理解,我编写了下面的函数,将一个给定的 Matplotlib 条形图转换成一个Plotly条形图。它采用类型为AxesSubplot的单个参数。

将 Matplotlib 条形图转换为 Plotly 条形图的函数

它执行以下步骤。

  1. 从轴中提取所有矩形对象。
  2. 构建矩形的 x 坐标、宽度、高度和颜色的列表。请注意,它将颜色转换为 Plotly 可以理解的格式。
  3. 构建刻度位置和标签的列表。
  4. 创建一个包含单个go.Bargo.Figure对象。
  5. 添加标题和记号。

散点图转换器

以下函数获取包含散点图的 Matplotlib AxesSubplot,并返回包含相应散点图的 Plotly go.Figure

将 Matplotlib 散点图转换为 Plotly 散点图的函数

考虑下面的 Matpotlib 散点图。

Matplotlib 散点图

如果你把它传递给上面的函数,你会得到下面的散点图。

Plotly 散点图

限制

虽然这种方法适用于小范围的绘图用例,但它很粗糙,不适合更大范围的用例。通过转换函数运行各种图并观察输出,很容易看出这一点。其他限制如下。

  1. 图例未映射。如果使用goplotly.express在 Plotly 中创建一个分组条形图,分组信息将被保留。然而,与 Plotly 不同的是,条形分组信息并没有显式地存储在 Matplotlib 中。因此,要在 Plotly 中实现“真正的”分组条形图,我们必须以某种方式从 Matplotlib 图中推断分组信息。此外,我找不到一个直接的方法给一个复杂的图形添加图例,除了添加带有名字的轨迹show_legend=True
  2. 悬停标签显示最少的信息。如果使用plotly.express创建图表,悬停标签会自动填充有用的信息,这是 Plotly 最酷的特性之一。无论如何,你仍然可以定制悬停标签,以显示更多信息。
  3. 内部属性可能会发生变化。如果在其中一个库中引入了向后不兼容的更改,转换代码可能会中断,并且需要更新。

可供选择的事物

Checkout 袖扣,一个第三方库,为 dataframes 添加了一个iplot()方法。df.iplot()之于 Plotly,正如df.plot()之于 Matplotlib。

Bokeh 是一个很酷的交互式绘图库。你可以通过运行pd.set_option('plotting.backend', 'pandas_bokeh')将它设置为你的熊猫绘制后端

同时,Nicolas Kruchten(Plotly 产品副总裁)最近评论Plotly 可能会在下一个版本中作为绘图后端选项添加到 pandas!

我希望你觉得我的周末实验很有趣!此外,请查看我关于 Streamlit 的教程。

matplotlib:Python 强大的数据可视化工具教程

原文:https://towardsdatascience.com/matplotlib-tutorial-with-code-for-pythons-powerful-data-visualization-tool-8ec458423c5e?source=collection_archive---------22-----------------------

通过代码示例解释 Matplotlib 库的基础知识和基本功能

数据可视化是通过图形或图表等可视化工具,以可访问的方式呈现数据。这些可视化有助于交流数据中的见解和关系,是数据分析的重要组成部分。在本文中,我们将讨论 Matplotlib,这是 Python 编程语言中最流行的数据可视化库。

内容

  1. 准备工作
  2. 散点图
  3. 条形图
  4. 直方图
  5. 箱线图

1。准备工作

Matplotlib 是一个文档非常丰富的包。为了使绘图更容易,我们使用了 pyplot 模块,这使得 Matplotlib 像 MATLAB 一样工作。本质上,它的所有功能都可以在这里找到。本文的重点是陈述它的主要和最重要的功能,并举例说明如何使用 pyplot,因为文档有时很难浏览。

为了调用包模块,我们以import matplotlib.pyplot as plt开始我们的代码。下面,我们陈述一些使用 pyplot 时最重要的函数:

  • plt.title:设置标题,出现在剧情上方。
  • plt.grid:配置图中的网格线。使用plt.grid(True)启用绘图中的网格线。
  • plt.legend:在图中放置一个图例。
  • plt.xlabelplt.ylabel:设置轴的标签。例如,plt.xlabel(“Age”)将“年龄”设置为 x 轴的标签。
  • plt.xlimplt.ylim:设定各轴的极限范围。因此,例如,plt.xlim([-50, 50])将绘图限制为仅显示-50 和 50 之间的 x 值。
  • plt.show:用在最后,显示图中的一切。

为了演示这些函数的用法,让我们考虑一个简单的例子,我们想画两条简单的线。这可以通过使用plt.plot功能来实现。通过使用下面的代码

import matplotlib.pyplot as pltx = [1, 2, 3]
x2 = [1, 3, 3.5]
y = [-4, 0, 8]
y2 = [-2, 3, -1]

plt.plot(x, y, label='Line 1')
plt.plot(x2, y2, label='Line 2')

plt.title("Plotting two simple lines")
plt.grid(True)
plt.xlabel("X-label")
plt.ylabel("Y-label")
plt.xlim([0, 4])
plt.ylim([-5, 10])
plt.legend()
plt.show()

我们得到了下图:

2.散点图

现在我们已经看到了基本的 pyplot 函数,我们将从第一种类型的绘图开始。散点图通常显示一组数据的两个变量的值。当弄清楚变量对之间的关系时,这种图可以提供很多信息。

考虑下面的工资数据集(来自 Kaggle),它包含 30 个由多年工作经验和年薪(美元)组成的观察值。为了创建散点图,我们使用了plt.scatter函数。然后,我们可以将这些数据点绘制如下:

import matplotlib.pyplot as plt
import pandas as pddata = pd.read_csv("Salary_data.csv")  # load dataset
X = data["YearsExperience"]
Y = data["Salary"]plt.scatter(X, Y)
plt.title("Scatter Plot")
plt.xlabel("Working Experience (years)")
plt.ylabel("Annual Wage (dollars)")
plt.show()

例如,我们还能够通过使用不同的颜色来区分具有超过 5 年工作经验的观察和具有不到 5 年工作经验的观察。为此,我们通过使用相关数据分割创建两个散点图,并在一个图中显示它们。以下代码会产生所需的绘图:

X_1 = X[X > 5]
X_2 = X[X <= 5]
Y_1 = Y[X > 5]
Y_2 = Y[X <= 5]plt.scatter(X_1, Y_1, label='Years of experience > 5')
plt.scatter(X_2, Y_2, label='Years of experience <= 5')
plt.title("Scatter Plot (split)")
plt.legend()
plt.xlabel("Working Experience (years)")
plt.ylabel("Annual Wage (dollars)")
plt.show()

在这里,我们利用图例函数来很好地区分这两个组。

我们还能够在分类应用中使用散点图。当我们处理属于不同类别的数据时,我们可以绘制一个数据点,并根据其所属的类别对其进行相应的着色。举个例子,我们使用 Iris 数据集,它可以通过 Python 中的 sklearn 包获得。在这个数据集中,观测值可能属于三个不同的 flower (iris)类。在这个例子中,我们只考虑两个特征,因此图像是 2D 的。这两个感兴趣的特征是萼片长度和萼片宽度(以厘米为单位)。然后,通过使用下面的代码,我们可以为属于不同 iris 类的不同观察值绘制一个漂亮的图:

from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as npiris = datasets.load_iris()  # load dataset
X_iris = iris.data[:, :2]  # only take the first two features
Y_iris = iris.target
n_classes = 3for i in range(n_classes):
    index = np.where(Y_iris == i)
    plt.scatter(X_iris[index, 0], X_iris[index, 1],  
    label=iris.target_names[i])
plt.legend()
plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])
plt.show

请注意,为了获得该图,我们必须制作三个不同的散点图(通过循环的)以使用不同的颜色区分不同的类别。

3.条形图

一个条形图用不同高度的矩形条以图形方式显示分类数据,其中矩形条的高度或长度代表相应度量的值。

让我们再次考虑 iris 数据集,其中观察值属于三个 Iris 花类中的任何一个。假设我们想要可视化 Setosa iris 类的每个特性的平均值。我们可以通过使用条形图来实现这一点,需要使用plt.bar函数。以下代码会生成所需的条形图:

from sklearn import datasets
import matplotlib.pyplot as pltiris = datasets.load_iris()
X_iris = iris.data
Y_iris = iris.targetaverage = X_iris[Y_iris == 0].mean(axis=0)

plt.bar(iris.feature_names, average)
plt.title("Bar Chart Setosa Averages")
plt.ylabel("Average (in cm)")
plt.show()

此外,我们还能够很好地显示所有三种鸢尾花的特征平均值,方法是将条形相邻放置。这比标准的条形图需要更多的努力。通过使用以下代码,我们获得了所需的绘图:

from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as npiris = datasets.load_iris()
X_iris = iris.data
Y_iris = iris.target
n_classes = 3averages = [X_iris[Y_iris == i].mean(axis=0) for i in range(n_classes)]
x = np.arange(len(iris.feature_names))

fig = plt.figure()
ax = fig.add_subplot()
bar1 = ax.bar(x - 0.25, averages[0], 0.25, label=iris.target_names[0])
bar2 = ax.bar(x, averages[1], 0.25, label=iris.target_names[1])
bar3 = ax.bar(x + 0.25, averages[2], 0.25, label=iris.target_names[2])
ax.set_xticks(x)
ax.set_xticklabels(iris.feature_names)

plt.legend()
plt.title("Bar Chart Iris Averages")
plt.ylabel("Average")
plt.show

4.直方图

根据手头的样本数据,使用直方图给出数据分布的近似表示。直方图是通过使用大小相等的“箱”(区间),并计算属于每个箱的数据点的数量来构建的。在新项目开始时创建直方图对于熟悉数据和粗略了解底层分布的密度非常有用。为了创建直方图,我们使用了plt.hist函数。

为了使用 20 个等长的箱创建所有鸢尾花的萼片长度的基本直方图,我们使用以下代码:

from sklearn import datasets
import matplotlib.pyplot as pltbins = 20
iris = datasets.load_iris()
X_iris = iris.data
X_sepal = X_iris[:, 0]

plt.hist(X_sepal, bins)
plt.title("Histogram Sepal Length")
plt.xlabel(iris.feature_names[0])
plt.ylabel("Frequency")
plt.show

我们可以绘制所有特征的直方图,而不是绘制单个特征的直方图。这可以通过创建单独的图来完成,但在这里,我们将利用子图,以便所有直方图都显示在一个单独的图中。为此,我们使用了plt.subplots函数。通过使用以下代码,我们获得了包含四个直方图的图:

from sklearn import datasets
import matplotlib.pyplot as pltbins = 20
iris = datasets.load_iris()
X_iris = iris.datafig, axs = plt.subplots(2, 2)
axs[0, 0].hist(X_iris[:, 0])
axs[0, 1].hist(X_iris[:, 1], color='orange')
axs[1, 0].hist(X_iris[:, 2], color='green')
axs[1, 1].hist(X_iris[:, 3], color='red')

i = 0
for ax in axs.flat:
    ax.set(xlabel=iris.feature_names[i], ylabel='Frequency')
    i += 1

fig.suptitle("Iris Histograms")

5.箱线图

一个箱线图是一种通过不同的统计以图形方式描绘数字数据组的便捷方式。下图显示了箱线图的解释:

这里的中位数是数据集的中间值(不要和均值混淆);第 25 百分位是数据集下半部分的中值,而第 75 百分位是数据集上半部分的中值。未包含在须状物之间的数据点被绘制为带点的异常值

再次考虑鸢尾花数据集。使用plt.boxplot功能创建一个箱线图。我们将为所有鸢尾花的萼片长度绘制一个箱线图:

from sklearn import datasets
import matplotlib.pyplot as pltiris = datasets.load_iris()
X_iris = iris.data
X_sepal = X_iris[:, 0]

plt.boxplot(X_sepal, labels=[iris.feature_names[0]])
plt.title("Boxplot Sepal Length")
plt.ylabel("cm")
plt.show

由于所有要素的测量值相同(即以厘米为单位),我们可以在一个单独的图中绘制所有要素的相邻箱线图:

from sklearn import datasets
import matplotlib.pyplot as pltiris = datasets.load_iris()
X_iris = iris.dataplt.boxplot(X_iris, labels=[iris.feature_names[0], iris.feature_names[1], iris.feature_names[2], iris.feature_names[3]])
plt.title("Boxplots Iris features")
plt.ylabel("cm")
plt.show

感谢阅读

这篇文章包含了 Matplotlib 库中 pyplot 模块的基本函数。当然,当使用 Matplotlib 和 pyplot 绘图时,存在更多的可能性。我希望这篇文章是有用的!

薪资数据集来源:

https://www . ka ggle . com/rohankayan/years-of-experience-and-salary-dataset

matplotlib vs . gg plot 2:2020 年及以后选择哪个?

原文:https://towardsdatascience.com/matplotlib-vs-ggplot2-which-to-choose-for-2020-and-beyond-ced5e294bfdc?source=collection_archive---------15-----------------------

深入比较两个最流行的可视化库

2020 年即将结束,数据可视化变得前所未有的重要。呈现一个看起来像 5 岁小孩做的东西不再是一个选项,因此数据科学家需要一个有吸引力且易于使用的数据可视化库。我们今天将比较其中的两个——Matplotlib 和 T2。

照片由安德鲁·布坎南Unsplash 上拍摄

那么,为什么是这两个呢?根据编程语言的选择,我会碰碰运气,说这些是你将学习的第一批可视化库。我越来越喜欢 ggplot2,但今天我们将在两个库中重新创建五个相同的情节,看看事情会如何发展,从代码角度和美学角度都是如此。

数据呢?我们将使用两个众所周知的数据集:地铁车辆和飞机乘客。您可以通过导出 CSV 功能获得第一个到 RStudio ,第二个可在这里获得。

以下是针对 RPython 的库导入:

**R:** 
library(ggplot2) **Python:** 
import pandas as pd 
import matplotlib.pyplot as plt 
import matplotlib.dates as mdates 
mtcars = pd.read_csv('mtcars.csv')

直方图

我们使用直方图来可视化给定变量的分布。这就是我们要对 mtcars 数据集做的事情-可视化 MPG 属性的分布。

下面是 R 的代码和结果:

ggplot(mtcars, aes(x=mpg)) + 
  geom_histogram(bins=15, fill='#087E8B', color='#02454d') +
  ggtitle('Histogram of MPG') + xlab('MPG') + ylab('Count')

这里同样适用于 Python :

plt.figure(figsize=(12, 7)) 
plt.hist(mtcars['mpg'], bins=15, color='#087E8B', ec='#02454d')
plt.title('Histogram of MPG') 
plt.xlabel('MPG') 
plt.ylabel('Count');

默认情况下,两者非常相似。甚至我们需要写的代码量也或多或少是一样的,所以在这里很难挑一个喜欢的。我喜欢 Python 的 x 轴如何从 0 开始,但这可以在 R 中很容易地改变。另一方面,我喜欢在 R 中没有边框,但同样,这在 Python 中也很容易实现。

赢家:平局

条形图

条形图由不同高度的矩形组成,其中高度代表给定属性段的值。我们将使用它们来比较不同数量的气缸(属性 cyl)的计数。

以下是 R 的代码和结果:

ggplot(mtcars, aes(x=cyl)) + 
  geom_bar(fill='#087E8B', color='#02454d') + 
  scale_x_continuous(breaks=seq(min(mtcars$cyl), max(mtcars$cyl), by=2)) + 
  ggtitle('Bar chart of CYL') + 
  xlab('Number of cylinders') + ylab('Count')

这里同样适用于 Python :

bar_x = mtcars['cyl'].value_counts().index 
bar_height = mtcars['cyl'].value_counts().values plt.figure(figsize=(12, 7)) 
plt.bar(x=bar_x, height=bar_height, color='#087E8B', ec='#02454d') 
plt.xticks([4, 6, 8]) 
plt.title('Bar chart of CYL') 
plt.xlabel('Number of cylinders') 
plt.ylabel('Count');

毫无疑问, R 的代码更加整洁简单,因为 Python 需要手动计算高度。从审美角度来说,他们非常相似,但是我更喜欢 T42 的版本。

获胜者:ggplot2

散点图

散点图用于可视化两个变量之间的关系。我们的想法是,当第一个变量发生变化(上升或下降)时,观察第二个变量会发生什么变化。我们还可以通过对其他属性值的点进行着色,为二维绘图添加另一个“维度”。

我们将使用散点图来形象化 HP 和 MPG 属性之间的关系。

下面是 R 的代码和结果:

ggplot(mtcars, aes(x=hp, y=mpg)) + 
  geom_point(aes(size=cyl, color=cyl)) + 
  ggtitle('Scatter plot of HP vs MPG') + 
  xlab('Horse power') + ylab('Miles per gallon')

这里同样适用于 Python:

colors = [] 
for val in mtcars['cyl']: 
    if val == 4: colors.append('#17314c') 
    elif val == 6: colors.append('#326b99') 
    else: colors.append('#54aef3') plt.figure(figsize=(12, 7)) 
plt.scatter(x=mtcars['hp'], y=mtcars['mpg'], s=mtcars['cyl'] * 20, c=colors) 
plt.title('Scatter plot of HP vs MPG') 
plt.xlabel('Horse power') 
plt.ylabel('Miles per gallon');

在代码方面,R 和 ggplot2 显然会胜出。Matplotlib 没有提供一个简单的方法来通过第三个属性给数据点着色,所以我们必须手动完成这个步骤。尺寸也有点奇怪。

获胜者:ggplot2

箱线图

箱线图用于通过四分位数可视化数据。它们通常有从盒子延伸出来的线(胡须),这些线在上下四分位数之外显示出可变性。中间的线是中间值。显示在顶部或底部(胡须之后)的点被认为是异常值。

我们将使用箱线图来显示不同 CYL 值的 MPG。

以下是 R 的代码和结果:

ggplot(mtcars, aes(x=as.factor(cyl), y=mpg)) + 
  geom_boxplot(fill='#087E8B', alpha=0.6) + 
  ggtitle('Boxplot of CYL vs MPG') + 
  xlab('Number of cylinders') + ylab('Miles per gallon')

这里同样适用于 Python :

boxplot_data = [ 
    mtcars[mtcars['cyl'] == 4]['mpg'].tolist(), 
    mtcars[mtcars['cyl'] == 6]['mpg'].tolist(), 
    mtcars[mtcars['cyl'] == 8]['mpg'].tolist() 
] fig = plt.figure(1, figsize=(12, 7)) 
ax = fig.add_subplot(111) 
bp = ax.boxplot(boxplot_data, patch_artist=True) for box in bp['boxes']: 
    box.set(facecolor='#087E8B', alpha=0.6, linewidth=2) for whisker in bp['whiskers']: 
    whisker.set(linewidth=2) for median in bp['medians']: 
    median.set(color='black', linewidth=3) ax.set_title('Boxplot of CYL vs MPG') 
ax.set_xlabel('Number of cylinders') 
ax.set_ylabel('Miles per galon') 
ax.set_xticklabels([4, 6, 8]);

有一点是显而易见的——Matplotlib 需要如此多的代码来生成一个看起来不错的箱线图。而 ggplot2 就不是这样了。到目前为止,R 显然是这里的赢家。

获胜者:ggplot2

折线图

我们现在将从 mtcars 数据集转移到航空乘客数据集。我们将使用它来创建一个带有日期格式的 x 轴的简单折线图。这并不像听起来那么简单。

以下是 R 的代码和结果:

ap <- read.csv('https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv') 
ap$Month <- as.Date(paste(ap$Month, '-01', sep='')) ggplot(ap, aes(x=Month, y=Passengers)) + 
  geom_line(size=1.5, color='#087E8B') + 
  scale_x_date(date_breaks='1 year', date_labels='%Y') + 
  ggtitle('Line chart of Airline passengers') + 
  xlab('Year') + ylab('Count')

这里同样适用于 Python :

ap = pd.read_csv('https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv') 
ap['Month'] = ap['Month'].apply(lambda x: pd.to_datetime(f'{x}-01')) fig = plt.figure(1, figsize=(12, 7)) 
ax = fig.add_subplot(111) 
line = ax.plot(ap['Month'], ap['Passengers'], lw=2.5, color='#087E8B') formatter = mdates.DateFormatter('%Y')
ax.xaxis.set_major_formatter(formatter) 
locator = mdates.YearLocator() 
ax.xaxis.set_major_locator(locator) 
ax.set_title('Line chart of Airline passengers') ax.set_xlabel('Year') ax.set_ylabel('Count');

从美学角度来看,这两个图几乎完全相同,但是在代码量方面,ggplot2 又一次击败了 Matplotlib。在 R 中格式化 x 轴来显示日期也比在 Python 中容易得多。

获胜者:ggplot2

在你走之前

在我看来,在简单美观的数据可视化方面,ggplot2 是一个明显的赢家。几乎总是归结为非常相似的 3-5 行代码,这与 Python 的情况不同。

我们还没有触及一点点的情节定制,因为这个想法是比较“默认”可视化库的“默认”风格。你可以自由探索。

感谢阅读。

加入我的私人邮件列表,获得更多有用的见解。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

原载于 2020 年 9 月 29 日 https://betterdatascience.com**的

matplotlib——谁说它需要简单?

原文:https://towardsdatascience.com/matplotlib-who-said-it-needs-to-be-simple-7156df7c827b?source=collection_archive---------30-----------------------

当有更多可以探索的时候,为什么要抓住简单的数字不放呢?让我们来学习如何使用支线剧情部分!

安德里亚·皮亚卡迪奥——派克斯拍摄的照片

介绍

虽然是一个相对简单的库,但 Matplotlib 不断给新人带来一些困惑;有些功能似乎不太好学,网上的解释也不太友好。

与数字打交道总是一团糟。我们需要一段时间来学习如何在一个图形中创建多个图形,然后我们意识到我们可以做得更多。

你是新来的吗?

如果您现在开始接触数据可视化,我强烈推荐您阅读我的文章“数据可视化终极指南”。在那里,我教如何创建不同的情节类型,以及如何定制你的数字!

[## 数据可视化的终极指南

没有人喜欢丑陋的东西,对吗?如果他们猜不出我们的期望,那就更糟了。所以让我们来学习如何生成…

towardsdatascience.com](/the-ultimate-guide-for-data-visualization-c98de0d3158d)

今天你将学到什么

我们将涵盖 Matplotlib 数据的一些重要方面,例如:

  • 如何将您的绘图应用于特定的轴;
  • 添加标签、标题,改善填充;
  • 用支线剧情工作;

还有更多!在本教程结束时,你将能够理解你在做什么与你的数字!我们开始吧。

这个数字

图片由雷南·洛里科拍摄——中号

每个人都习惯于一个标准的 Matplotlib 图形,你可以只放一个图;这对任何人来说都不再是个谜了,对吗?

第一,你总是从塑造你的身材开始;然后,选择地块类型,并开始调整信息和样式。有用的技术。

当您需要一起创建几个图表时,问题就出现了;创造独特的人物并希望他们看起来很棒是没有意义的,那么你会怎么做呢?

使用 gridspec

图片由雷南·洛里科拍摄——中号

Matplotlib 有一个很棒的处理多个图的工具,叫做 gridspec 这样,您可以在一个图形中插入多个图形。让我们看一下代码。

首先,我用一行三列开始了 GridSpec。因为有不止一列,所以还需要传递参数 width_ratios ,它需要一个整数列表,该列表将是每一列的宽度。想要更简单的选择吗?所以我会推荐 subplot2grid。

使用子图 2 网格

任何人的正确选择!使用起来并不困难,方便了整个过程。先看看我们能做些什么。

图片由雷南·洛里科拍摄——中号

subplot2grid 在引擎盖下使用 GridSpec 这就是为什么它工作得这么好。两者的区别在于 GridSpec 创建了一个新的子情节,并将位置作为参数传递;Subplot2grid 一起完成所有这些工作,所以您用配置实例化它。哪一个是最好的?两者都有?你需要知道哪一个?GridSpec。

使用支线剧情

如果您正在寻找一种更简单的方法来绘制多个图形,并且不想因为不同的宽度而变得过于复杂,请尝试 subplot。让我们看一个例子。

图片由雷南·洛里科拍摄——中号

通常用于探索性数据分析,因其易于绘制各种图形。我们将绘图代码放在一个循环中,这个循环负责将每个图形附加到它的位置上。

你的数据中的信息

现在您知道了如何改进数据可视化,所以让我们深入了解标签的重要性。

图片由雷南·洛里科拍摄——中号

所有数据都必须有标题、x 轴和 y 轴上的标签,以及解释数据差异的图例。这总是必要的,没有例外。

团队内部的信息量可以减少,因为每个人都已经意识到他们试图解决的问题。然而仍然需要某种方式来指定这些情节。

让我们看看我是如何在上图中添加所有这些标签的。

要记住的事情

有一些你不能忘记的重要信息,让我们检查一下:

  • 每当你想创建一个新的图像时,从一个 plt.figure()开始;
  • 注意不要颠倒 x 轴和 y 轴;
  • 质量胜于数量;

永远把你的图表当成一件艺术品;你需要不断思考谁会看到它,他们会有什么反应。

对我们来说,我们花在解释事情上的时间越少,我们就越需要推销我们的想法。

就这样,伙计们!

我希望你喜欢这个内容,并能熟练运用你的新知识!如果你想每天学习有趣的东西,我很乐意与你分享精彩的内容!

另外,你可以在 Github 上查看我的个人资料。我从事一些数据科学项目已经有一段时间了。所有的关键概念都可以学习和重用!

[## 雷南·洛利科-吉图布

在 GitHub 上注册你自己的个人资料,这是托管代码、管理项目和构建软件的最佳地方…

github.com](https://github.com/renfelo)

NumPy 矩阵计算

原文:https://towardsdatascience.com/matrix-computation-with-numpy-a865ebaf2005?source=collection_archive---------60-----------------------

来自我在 Figma 上的设计

NumPy 如何简化您的代码,同时提高其性能。广播和 SIMD 来救援了!

简介

当我们使用机器学习,尤其是深度学习来解决问题时,性能确实是一个重要的方面。使用神经网络来计算事物可能会成为复杂的计算,因为它涉及矩阵和向量。

假设我们想计算一个乘以 5 的 25 x 25 的矩阵。第一次向您介绍编程时,您将会计算这样的向量或矩阵,

for i in range(25):
    for j in range(25):
        x[i][j] *= 5

如果我们使用这种方法,它将使我们的计算时间更长,我们将不会在我们期望的时间得到结果。谢天谢地,在 Python 中,我们有 NumPy 库来解决这个矩阵和向量计算。

通过使用 NumPy 库,我们可以将 3 行代码变成 1 行代码,如下所示,

import numpy as np**# Make it as NumPy array first** x = np.array(x)x = x * 5

如果我们比较时间,在这种情况下,传统方法大约需要 0.000224,而 NumPy 方法只需要 0.000076。NumPy 比传统的快 3 倍,但同时也简化了你的代码!

想象一下,当你想计算一个比这个例子更大的矩阵时,你会节省多少时间。这种计算被分类为矢量化,其中计算发生在矩阵或矢量表示上。因此,用这种计算方法,同样的结果会节省你的时间。

这是怎么回事?NumPy 有什么魔力让它可以更简单更快速的计算矩阵?本文将向您介绍单指令多数据(SIMD)和广播的概念。没有进一步的,让我们开始吧。

单指令多数据(SIMD)

来自我在 Figma 上的设计

什么是单指令多数据(SIMD)?基本上,SIMD(读作“sim-dee”而不是用字母表拼写它)是一种并行计算方法,使计算机内部的数据可以由硬件同时(并发地)计算。

例如,我们有两个输入向量,我们想用算术方法计算每个元素的向量。硬件会,因此每个数据将被分配到硬件的不同组件(即,GPU 核心)并同时计算两个向量的每个元素。正因为如此,向量可以计算得更快。

广播

在 NumPy 中,当满足这些要求时,计算会起作用,它们是:

  1. 两个对象的尺寸相同,或者
  2. 其中一个维度的值为 1

如果对象不符合上述要求,则不能计算。如果有一些对象满足第二个要求,那么该对象将被广播。

广播基本上是用在形状不同的向量上。回想一下上面矩阵和标量元素(5)之间的计算,标量将被广播,因此标量将具有与矩阵相同的形状。例如,当你有了这些东西,

  • 例 2 中的 5×1 个矢量[1 2 3 4 5]
  • 示例中的 1 x 1 标量为 5

为了实现这一点,标量将具有与向量相同的形状,并且该值将在新向量中传播。所以我们可以得到[5 5 5 5 5]向量。有了这个矩阵,我们就可以利用 SIMD 原理,计算出要转换成矢量的矢量和标量。因此,结果将是如下所示的[5 10 15 20 25],

来自我在 Figma 上的设计

结论

总之,机器学习的计算没有从向量和矩阵中分离出来。如果你想从头开发一些机器学习模型,特别是在矢量化部分,理解线性代数将是有用的。通过这样做,由于 SIMD 和广播的概念,我们可以使我们的计算更加有效和简单。

参考

[1]若昂 M.P 卡多佐,何塞·加布里埃尔·f·库蒂尼奥和佩德罗·c·迪尼茨,面向高性能的嵌入式计算(2017) ,爱思唯尔公司
【2】斯特芬·范德沃特,s·克里斯·科尔伯特和加尔·瓦洛夸。NumPy 数组:高效数值计算的结构 (2011),《科学计算&工程》,第 13 卷,第 2 期,第 22–30 页。

感谢您阅读我的文章,您也可以在下面查看我以前的文章:

[## R 时间序列分析导论

从探索,到预测。使用印度尼西亚 2002 年 12 月至 2020 年 4 月的消费者价格指数(CPI)数据

towardsdatascience.com](/introduction-to-time-series-analysis-with-r-a2f97650baa3) [## 做这个额外的步骤,你就做了一个一般化的机器学习模型

只是一个额外的步骤,它可以增加我们对预测未知数据的模型的信心。

towardsdatascience.com](/do-this-additional-step-you-have-made-a-generalize-machine-learning-model-9d85b7e09313) [## 更高的准确性并不意味着更好的机器学习模型性能

我们可以定量地衡量机器学习模型的性能,但不仅仅是准确性,还有很多…

towardsdatascience.com](/greater-accuracy-does-not-mean-greater-machine-learning-model-performance-771222345e61)

自然语言处理中向量空间模型的矩阵设计

原文:https://towardsdatascience.com/matrix-design-for-vector-space-models-in-natural-language-processing-fbef22c10399?source=collection_archive---------31-----------------------

NLP 知识表示的简要原理和矩阵设计的简明指南&分布式单词表示的维数灾难。

乔恩·泰森在 Unsplash 上的照片

我记得当我第一次学习代数的时候,我有一种奇怪的冲动,想把这些字母用文字表达出来。我有一些随机字母的涂鸦被用作数字,然后只是玩玩。

嗯,事实证明,当我学习信息论和单词向量时,我就像“我就知道!!!"

计算机科学的一个基础是用数字甚至更好的数字来表示你的知识——用 0 和 1 的组合。机器学习模型也不例外,因此,将文本转换为数字表示(或者像我的教授所说的——代理)是任何类型的文本分析任务的构建模块。

自然语言处理的知识表示哲学

理解人类语言的人类知识有两个主要来源:

  1. 字典
  2. 我们从阅读书籍和人工制品中收集的信息

我会把字典称为一种结构化的学习工具,旨在帮助自然的人类学习,而从阅读书籍中收集的知识是一种非结构化的甚至不可预见的过程。这是理解自然语言的两种关键方法,自然语言已经被系统地数字化,以供人工生物学习(我指的是计算机😅).

照片由石页康让Unsplash 上拍摄

字典被实现为 WordNet 丰富的知识就像一个随时可以被 NLP 程序使用的数字字典,就像我们如何通过查阅字典来学习特定单词的意思一样。

另一种获取知识的方式是通过从书籍、小说、物品评论、短信、推文等人工制品中学习。这种知识可以使用向量来有效地表示,以捕获嵌入其中的语义知识。这就是我要在这里简要讨论的所有大惊小怪的事情。

关于向量的一个注记

向量是一维矩阵,用于表示一维空间中的数字集合。在机器学习中,特征向量是用于表示一个特定数据实例的特征的所有数字编码的一维向量。随着实例数量的增加,矩阵也会增长。类似地,在推荐系统中,矩阵用于在用户和购买或观看的项目之间建立联系,其中每个向量代表每个用户的选择。在心理学中,向量用于评估心理测量特征,并且特征向量将包括每个人被评估的每个心理测量特征的点数。

因此,使用向量和矩阵将数据量化成机器可解释的格式是相当普遍的。在自然语言处理中,单词也在向量空间中表示,其中每个向量对应于特定单词的分布。这使得通过概化来计算预测变得非常类似于监督分类问题,概化主要通过计算向量相似度来解密。

单词表示的矩阵设计

“从一个人交的朋友,你就可以知道他说的是什么”
J. R. Firth 1957: 11

正如我们已经建立的,我们将把文本转换成它们的数字表示,我们将把它们表示成实数的密集向量。这些向量共同形成了一个矩阵,可以通过这样的方式设计,让我们保留我们期望从文本中获得的意义。

例如,一个句子——“我喜欢文本分析。”单词‘love’的出现可以被转换成 4×1 的向量,其中 4 是词汇量(由 V 表示)

数学上,代表“爱”的向量可以写成:

“爱”这个词的一键编码词向量

这是一键编码的一种形式。

如果有多个句子,那么最简单的方法是将词汇添加到向量的词汇维度中,并继续扩展这个“出现”向量。

然后,如果有 M 个标记,您可以创建一个 V x M 矩阵,对词汇表中标记的存在和不存在进行编码。

现在,让我们回顾一下这种编码方式,并记下注意事项。语言中最重要的一点是,一个词本身不会发出预测信号,直到它被放到一个语境中进行整体理解。例如,如果我说“好”——是的,好是一个积极的词,但什么是好呢?还是在“好”之前有一个“不”?这就是为什么我把它标为“发生”向量。这是一个简单的是或不是的情况。这与上下文无关。

第二个问题是,如果单词向量表示不受控制,可能会产生大量词汇。这将导致昂贵的计算和耗时的过程。

对于某些捕捉一起出现的一组单词的含义的人来说,我们有两种最广泛使用的矩阵设计,讨论如下:

  1. Word x 文档矩阵

在这种向量表示方法中,每个单词被表示为它在每个文档中出现的频率。因此,向量大小将是|V|x D,其中 D 是文档的数量。这个向量由实数组成,并且随着更多文档的添加而扩大。换句话说,对于第 i 个单词,该单词在第 j 个文档中的词频(tf)被放置在矩阵的第 ij 个元素处。

为了证明这一点,请考虑以下三个文档:

文件 1:“听着,哈里,我能试试吗?我可以吗?”

文件 2:“我认为任何人现在都不应该骑那把扫帚!”赫敏尖声说道。

文件 3:哈利和罗恩看着她。

word-document 向量表示看起来像这样:

2。基于窗口的 Word x Word 矩阵:

这也被称为共现矩阵,其中测量一个单词在另一个单词附近出现的次数。例如,如果评估窗口大小为 3,则测量词汇表中的单词( i) 在词汇表中第 j 个单词的范围 j+3 到 j-3 内出现了多少次,并将其放置在共现矩阵的位置 ij 处。如果词汇表的大小是| V |那么最终的矩阵将是| V | x | V |。

为了证明窗口大小为 3 的这一点,前一示例的共生矩阵将是:

如果我使用更多的例子,哈利、罗恩和赫敏在频率计数方面会比其他人更突出,因为他们的名字会更频繁地出现在一起(在 3 个单词的跨度内,向前和向后),这在这些独立的单词中建立了语义。

单词向量的维数

法尔汉·阿扎姆Unsplash 上拍摄的照片

定义向量的维数与使用 NLP 技术解决的问题有关。如果你只是想知道,在用户评级为“非常好”、“好”、“一般”、“不好”、“更差”的情况下。这方面将是一个独热编码器,其中 1 将对应于用户评级。这也是在特定项目的上下文中捕捉用户情绪的一种形式。这个问题的维数是 5。每个实例将是一个 1×5 的矩阵。

现在,就心理测量分析而言,如果你对每个用户的大五分进行编码,那么每个大五人格特质将有 0 到 50 的实数,即开放性尽责性外向性宜人性神经质。这个矢量的形状也是 1 x 5。根据你正在解决的问题,这些值可以被缩放,因为这些个性测试中的较低值表明该特定特征的相反行为。例如,[15,12,34,44,29]可以缩放为[-1,-1,1,1,0]。

如果您正在进行性别分类任务,那么您的向量表示可能是 1x2,如果您有 10k 个文档,那么您的维度将是相同的数量级,除非您对单词 vector 的长度进行策略化。

单词向量的 维度选择 对模型的性能有很大的影响。向量的较小维度对于捕获所有特征是低效的(欠拟合),而向量的较大维度将导致过拟合。大的维度直接增加了模型复杂性、计算成本以及通过增加延迟的训练时间。此外,从向量计算的特征将是维度的线性或二次函数,这进一步影响训练时间和计算成本。

摘要

嵌入在单词中的含义可以通过使用计数统计来识别,并表示单词与相邻单词或其所在的文档的关联,并以向量的形式表示它们。词汇表和文档越多,矩阵就越大,这就导致了维数灾难。由于这些编码策略会产生稀疏矩阵,因此它们也存在相关的可伸缩性问题,并且计算量很大。一个 MxN 矩阵具有 O(mn ) 的计算成本,这是不期望的。然而,这两种表示是最广泛使用的矩阵设计策略,并且已经被证明在解决诸如文本分类、非上下文情感分析和文档相似性的 NLP 问题时非常有效。

参考资料:

  1. http://web . Stanford . edu/class/cs 224n/readings/cs 224n-2019-notes 01-word vecs 1 . pdf
  2. http://web . Stanford . edu/class/cs 224 u/materials/cs 224 u-2020-VSM-讲义. pdf
  3. 特尼,彼得 d 和帕特里克潘特尔。"从频率到意义:语义学的向量空间模型."人工智能研究杂志37(2010):141–188。
  4. 诺亚·史密斯,《语境化的词语表达:语境化的介绍》 arXiv 预印本 arXiv:1902.06006 (2019)。

第 6 部分:流式时间序列数据的矩阵轮廓

原文:https://towardsdatascience.com/matrix-profiles-for-streaming-time-series-data-f877ff6f9eef?source=collection_archive---------41-----------------------

使用 STUMPY 使用在线数据逐步更新您的矩阵档案

(图片由若昂·布兰科提供)

整体大于部分之和

(图片由作者提供)

STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!

注:这些教程最初出现在 STUMPY 文档 中。

第一部分:矩阵轮廓图
第二部分: STUMPY 基础知识
第三部分:时间序列链
第四部分:语义分割
第五部分:快速近似矩阵轮廓图与 STUMPY
第六部分:用于流式时间序列数据的矩阵轮廓图
第七部分:快速模式搜索与 STUMPY
第八部分:【T2 10: 发现多维时间序列模体
第十一部分:用户引导的模体搜索
第十二部分:机器学习的矩阵轮廓

用于流时间序列数据的增量矩阵轮廓

现在,您已经对如何计算矩阵配置文件有了基本的了解,在这个简短的教程中,我们将演示当您有流(在线)数据时,如何使用stumpy.stumpi()(“STUMP Incremental”)函数增量更新您的矩阵配置文件。您可以通过阅读矩阵档案 I 文件的 G 部分以及本文件的第 4.6 部分和表 5 来了解有关该方法的更多详细信息。

入门指南

让我们导入创建和分析随机生成的时间序列数据集所需的包。

import numpy as np
import stumpy
import numpy.testing as npt
import time

生成一些随机时间序列数据

想象一下,我们有一个物联网传感器,它在过去 14 天里每小时收集一次数据。这意味着到目前为止我们已经积累了14 * 24 = 336个数据点,我们的数据集可能如下所示:

T = np.random.rand(336)

或许,我们从经验中知道,在 12 小时(滑动)的时间窗口内,可以检测到一个有趣的主题或异常:

m = 12

典型批量分析

使用stumpy.stump()通过批处理直接计算矩阵分布图:

mp = stumpy.stump(T, m)

但是随着T的长度随着时间的推移而增长,计算矩阵轮廓将花费越来越多的时间,因为stumpy.stump()将实际上重新计算时间序列内所有子序列之间的所有成对距离。这个超级耗时!相反,对于流数据,我们希望找到一种方法来获取新的传入(单个)数据点,并将它所在的子序列与时间序列的其余部分进行比较(即,计算距离轮廓)并更新现有的矩阵轮廓。幸运的是,这可以通过stumpy.stumpi()或“残肢增量”轻松实现。

用 STUMPI 进行流式(在线)分析

当我们等待下一个数据点t到来时,我们可以用现有的数据初始化我们的流对象:

stream = stumpy.stumpi(T, m)

并且当新的数据点t到达时:

t = np.random.rand()

我们可以将t添加到stream中,并在后台轻松更新矩阵配置文件、P和矩阵配置文件索引、I:

stream.update(t)

在后台,t已被附加到现有的时间序列中,它自动将新的子序列与所有现有的子序列进行比较,并更新历史值。它还确定现有子序列中的哪一个是新子序列的最近邻居,并将该信息附加到矩阵简档。随着额外数据的流入,这可以继续进行,比如说,再进行 1000 次迭代(或无限期地):

for i in range(1000):
    t = np.random.rand()
    stream.update(t)

重要的是要重申,增量stumpy.stumpi()与批量stumpy.stump()不同,它不会浪费任何时间来重新计算任何过去的成对距离。stumpy.stumpi()只花时间计算新的距离,然后在必要时更新适当的数组,因此,它真的很快!

验证矩阵配置文件

现在,这种用流(在线)数据“快速更新”的说法可能感觉奇怪或不可思议,因此,首先,让我们验证增量stumpy.stumpi()的输出与执行批处理stumpy.stump()的输出相同。让我们从具有64数据点的完整时间序列开始,并计算完整的矩阵轮廓:

T_full = np.random.rand(64)
m = 8mp = stumpy.stump(T_full, m)
P_full = mp[:, 0]
I_full = mp[:, 1]

接下来,对于stumpy.stumpi(),我们将只从全长时间序列中的第一个10元素开始,然后一次一个地增加额外的数据点:

# Start with half of the full length time series and initialize inputs
T_stream = T_full[:10].copy()
stream = stumpy.stumpi(T_stream, m)# Incrementally add one new data point at a time and update the matrix profile
for i in range(len(T_stream), len(T_full)):
    t = T_full[i]
    stream.update(t)

现在我们已经完成了,让我们检查并验证一下:

  1. stream.T == T_full
  2. stream.P == P_full
  3. stream.I == I_full
npt.assert_almost_equal(stream.T_, T_full)
npt.assert_almost_equal(stream.P_, P_full)
npt.assert_almost_equal(stream.I_, I_full)

没有错误,它们都匹配!因此,这意味着stump.stumpi()确实产生了我们所期望的正确矩阵分析结果。

验证性能

我们基本上声称,当每个新数据点到达时,用stumpy.stumpi()增量更新我们的矩阵轮廓比用stumpy.stump执行完整的成对距离计算要快得多(在总计算时间上)。让我们实际比较一下时间,取一个完整的时间序列,长度为 1,000 个数据点,我们用时间序列的前 20%(即前 200 个点)初始化这两种方法,并在每次迭代时附加一个新的数据点,然后重新计算矩阵轮廓:

T_full = np.random.rand(1000)
T_stream = T_full[:200].copy()
m = 10# `stumpy.stump` timing
start = time.time()
mp = stumpy.stump(T_stream, m)
for i in range(200, len(T_full)):
    T_stream = np.append(T_stream, T_full[i])
    mp = stumpy.stump(T_stream, m)
stump_time = time.time() - start# `stumpy.stumpi` timing
start = time.time()
stream = stumpy.stumpi(T_stream, m)
for i in range(200, len(T_full)):
    t = T_full[i]
    stream.update(t)
stumpi_time = time.time() - startprint(f"stumpy.stump: {np.round(stump_time,1)}s")
print(f"stumpy.stumpi:, {np.round(stumpi_time, 1)}s")stumpy.stump: 429.9s
stumpy.stumpi:, 3.4s

撇开拥有更多 CPU 将加速这两种方法的事实不谈,我们清楚地看到,对于处理流数据,增量stumpy.stumpi()比批量stumpy.stump()快几个数量级。事实上,对于当前的硬件,平均来说,stumpy.stump()分析每个新矩阵配置文件大约需要半秒钟。因此,如果每半秒钟就有一个新的数据点到达,那么您将无法跟上。相比之下,stumpy.stumpi()应该能够使用相当适中的硬件轻松处理每秒 300 多个新数据点。此外,计算复杂度为O(n^2)的批处理stumpy.stump()将会变得更慢,因为越来越多的数据点被附加到现有的时间序列,而stumpy.stumpi(),本质上是O(1),将继续保持高性能。

直观的例子

现在,我们已经了解了如何使用流数据计算和更新我们的矩阵轮廓,让我们用一个真实的示例数据集来探索这个问题,其中有一个已知的模式,并看看stumpy.stumpi()是否能够正确识别何时遇到全局基序(模式)。

检索和加载数据

首先让我们导入一些额外的 Python 包,然后检索我们的标准“Steamgen 数据集”:

%matplotlib inline

import pandas as pd
import stumpy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib import animation
from IPython.display import HTML
import os

plt.rcParams["figure.figsize"] = [20, 6]  # width, height
plt.rcParams['xtick.direction'] = 'out'

steam_df = pd.read_csv("https://zenodo.org/record/4273921/files/STUMPY_Basics_steamgen.csv?download=1")
steam_df.head()drum pressure  excess oxygen  water level  steam flow
    320.08239       2.506774     0.032701    9.302970
   1321.71099       2.545908     0.284799    9.662621
   2320.91331       2.360562     0.203652   10.990955 
   3325.00252       0.027054     0.326187   12.430107
   4326.65276       0.285649     0.753776   13.681666

该数据是使用模糊模型生成的,该模型用于模拟位于伊利诺伊州香槟市的 Abbott 电厂的蒸汽发生器。我们感兴趣的数据特性是输出蒸汽流量遥测,单位为 kg/s,数据每三秒“采样”一次,共有 9600 个数据点。

下面突出显示了我们正在寻找的主题(模式),但是仍然很难确定橙色和绿色的子序列是否匹配,也就是说,直到我们放大它们并将子序列重叠在彼此之上。

m = 640
fig, axs = plt.subplots(2)
plt.suptitle('Steamgen Dataset', fontsize='30')
axs[0].set_ylabel("Steam Flow", fontsize='20')
axs[0].plot(steam_df['steam flow'], alpha=0.5, linewidth=1)
axs[0].plot(steam_df['steam flow'].iloc[643:643+m])
axs[0].plot(steam_df['steam flow'].iloc[8724:8724+m])
rect = Rectangle((643, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
rect = Rectangle((8724, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[1].set_xlabel("Time", fontsize='20')
axs[1].set_ylabel("Steam Flow", fontsize='20')
axs[1].plot(steam_df['steam flow'].values[643:643+m], color='C1')
axs[1].plot(steam_df['steam flow'].values[8724:8724+m], color='C2')

(图片由作者提供)

现在,我们可以清楚地看到,母题非常相似!

使用 STUMPI

现在,让我们看看当我们用前 2000 个数据点初始化stumpy.stumpi()时,矩阵轮廓会发生什么变化:

T_full = steam_df['steam flow'].values
T_stream = T_full[:2000]
stream = stumpy.stumpi(T_stream, m)

然后递增地添加新的数据点并更新我们的结果:

windows = [(stream.P_, T_stream)]
P_max = -1
for i in range(2000, len(T_full)):
    t = T_full[i]
    stream.update(t) if i % 50 == 0:
        windows.append((stream.P_, T_full[:i+1]))
        if stream.P_.max() > P_max:
            P_max = stream.P_.max()

当我们绘制增长时间序列(上图)、T_stream以及矩阵分布图(下图)、P时,我们可以看到矩阵分布图是如何随着新数据的添加而演变的:

fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})rect = Rectangle((643, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
rect = Rectangle((8724, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[0].set_xlim((0, T_full.shape[0]))
axs[0].set_ylim((-0.1, T_full.max()+5))
axs[1].set_xlim((0, T_full.shape[0]))
axs[1].set_ylim((-0.1, P_max+5))
axs[0].axvline(x=643, linestyle="dashed")
axs[0].axvline(x=8724, linestyle="dashed")
axs[1].axvline(x=643, linestyle="dashed")
axs[1].axvline(x=8724, linestyle="dashed")
axs[0].set_ylabel("Steam Flow", fontsize='20')
axs[1].set_ylabel("Matrix Profile", fontsize='20')
axs[1].set_xlabel("Time", fontsize='20') lines = []
for ax in axs:
    line, = ax.plot([], [], lw=2)
    lines.append(line)
line, = axs[1].plot([], [], lw=2)
lines.append(line)def init():
    for line in lines:
        line.set_data([], [])
    return linesdef animate(window):
    P, T = window
    for line, data in zip(lines, [T, P]):
        line.set_data(np.arange(data.shape[0]), data) return linesanim = animation.FuncAnimation(fig, animate, init_func=init,
                               frames=windows, interval=100,
                               blit=True, repeat=False)anim_out = anim.to_jshtml()
plt.close()  # Prevents duplicate image from displaying
if os.path.exists("None0000000.png"):
    os.remove("None0000000.png")  # Delete rogue temp fileHTML(anim_out)
# anim.save('/tmp/stumpi.mp4')

(图片由作者提供)

这里,垂直虚线标记了预期的全局基序对的位置,灰色方框强调了相应的基序子序列。播放动画时,您可能会注意到矩阵轮廓不断变化,因为过去的子序列可能会找到新的最近邻。但是,请注意,矩阵轮廓的任何变化只能向下移动(向零移动)。在该动画的大部分时间里,左侧高亮显示的子序列(灰色框)具有相对较高的矩阵轮廓值。然而,随着时间序列延伸超过右侧的灰色框,前述矩阵轮廓值显著下降,并且一旦其最近的邻居完全到达流中就迅速稳定。这真的很酷!事实上,最初的 Matrix Profile I 论文的作者指出,在这个数据集上,在耗尽时间或内存之前,可以用stumpy.stumpi()继续监控 Matrix Profile 几十年!

奖金部分—从不更新历史记录

上面,我们已经用典型的定义矩阵配置文件。也就是说,对于任何给定的子序列,T[i : i + m],找出到它最近的邻居,T[j : j + m]的距离,不管j是在i(即j < i)的左边还是在i(即j > i)的右边。这意味着随着新数据的到来,如果一个“新的”最近邻点出现,甚至过去的历史数据点的矩阵轮廓也会更新。本质上,这是“事后诸葛亮”。因此,可能会有这样的情况,当您第一次看到一个独特的子序列时,您可能会将其识别为异常,因为它的矩阵分布值相对较高。然而,随着越来越多的新数据到达,这种最初的异常子序列可能不再是唯一的。考虑只观察正弦波的第一个周期,所有这些子序列将是唯一的。但随着正弦波的下一个周期开始流入,我们意识到第一个周期中的数据点不再异常,因此我们相应地更新了它们的矩阵轮廓值。

现在,这可能有益,也可能无益,取决于你选择如何定义“异常”。事实上,您可以选择不更新过去的矩阵轮廓,并且您可能希望限制对最近邻居j的搜索,使其始终位于i的左侧(即j < i)。幸运的是,在stumpy.stumpi()中,这已经为您完成,您可以分别通过流对象的.left_P.left_I属性访问左矩阵配置文件和左矩阵配置文件索引:

T_full = np.random.rand(64)
m = 8T_stream = T_full[:10].copy()
stream = stumpy.stumpi(T_stream, m)for i in range(len(T_stream), len(T_full)):
    t = T_full[i]
    stream.update(t)print(f"Full Matrix Profile: {np.round(stream.P_, 2)}")
print(f"Left Matrix Profile: {np.round(stream.left_P_, 2)}")
print(f"Full Matrix Profile Indices: {stream.I_}")
print(f"Left Matrix Profile Indices: {stream.left_I_}") Full Matrix Profile: [2.59 2.56 2.4  2.07 1.99 2.22 2.18 1.57 2.29 1.8  1.94 1.93 1.97 2.12
 2.06 2.35 2.54 2.15 1.95 1.78 2.18 1.99 2.43 2.05 1.77 2.07 2.04 2.49
 2.18 2.23 1.57 1.68 1.59 1.93 1.68 1.59 2.12 2.12 1.77 1.78 2.08 2.06
 1.99 2.42 2.1  2.07 1.99 2.22 2.1  1.8  2.29 2.16 2.13 1.95 1.93 1.93
 1.97]
Left Matrix Profile: [ inf  inf  inf 4.42 3.78 2.98 2.74 3.12 2.98 3.8  2.93 2.75 2.45 2.56
 2.4  2.35 2.54 2.34 2.77 2.56 2.48 2.58 2.74 2.48 2.29 2.39 2.16 2.51
 2.18 2.23 1.57 2.05 1.91 2.07 1.68 1.59 2.19 2.12 1.77 1.78 2.08 2.06
 1.99 2.52 2.4  2.07 1.99 2.22 2.1  1.8  2.29 2.16 2.13 1.95 1.93 1.93
 1.97]
Full Matrix Profile Indices: [52 19 39 45 46 47 48 30 26 49 54 55 56 40 41 42  6 56 53 39 28 42 30 31
 38 33 55 38 20  6  7 34 35 54 31 32 54 34 24 19  3 14 21 47 48  3  4  5
 44  9 10 36 37 18 33 11 12]
Left Matrix Profile Indices: [-1 -1 -1  0  1  2  3  4  2  4  0  1  7  3  9  5  6 12 13  1  9  6  7 10
 11 12 13  4 20  6  7 23 24 25 31 32 25 34 24 19  3 14 21 30  3  3  4  5
 44  9 10 36 37 18 33 11 12]

当然,需要指出的是,左侧矩阵轮廓索引中的-1值并不对应于时间序列中的最后一个子序列。相反,这意味着该位置的子序列在其左侧没有有效的最近邻。因此,相应的左矩阵轮廓值将被设置为np.inf

摘要

就是这样!您刚刚学习了如何针对流式(在线)数据逐步更新矩阵配置文件。

资源

Matrix Profile I
时序连接、基序、不一致和 Shapelets:利用 Matrix Profile 的统一视图(见第 4.6 节和表 5)
STUMPY Matrix Profile 文档
STUMPY Matrix Profile Github 代码库

第 5 部分:使用 STUMPY 的快速近似矩阵轮廓 | 第 7 部分:使用 STUMPY 的快速模式搜索

马修斯相关系数:何时使用,何时避免

原文:https://towardsdatascience.com/matthews-correlation-coefficient-when-to-use-it-and-when-to-avoid-it-310b3c923f7e?source=collection_archive---------8-----------------------

这不是解决分类问题的灵丹妙药

马库斯·斯皮斯克在 Unsplash 上的照片

当我在 StackExchange 上遇到这个关于不平衡分类问题度量的问题时,我知道了马修斯相关系数(MCC)。Boaz 在他的名为“Matthews Correlation Coefficient Is The Best class ification Metric You Never Heard”的中型故事中出色地解释了使用 MCC 的优势,我相信许多人在下次遇到棘手的不平衡分类问题时都会受到启发并兴奋地使用它。

但是等等……最好的分类度量?

让我们在二进制分类问题的背景下更仔细地考虑 MCC。与 F1 得分类似,MCC 是一个总结混淆矩阵的单值指标。混淆矩阵,也称为误差矩阵,有四个条目:真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)。使用 MCC 而不是 F1 分数获得的主要好处可以通过查看他们的公式很容易地猜到:

**

当我输入 FP 和 FN 时,它们是红色的,因为它们是不可取的

F1 分数忽略真阴性的计数。相比之下,MCC 友好地将其关注扩展到混淆矩阵的所有四个条目。《计算生物学中机器学习的十个快速提示》的作者 Davide Chicco 评论说,MCC“只有在你的分类器在正负元素上都表现良好的情况下才是高的。”

现在让我们把第一感觉放在一边,看一个具体的例子(MCC 的 wiki 页面中使用的同一个例子):

有条目的混淆矩阵:TP = 90,FP = 4;TN = 1,FN = 5。

F1 得分= 0.9524,误导我们认为分类器极其优秀。相比之下,将这些数字代入 MCC 的公式,我们得到的是可怜的 0.14。MCC 的范围从-1 到 1(嘿,反正是相关系数),0.14 表示分类器非常接近随机猜测分类器。从这个例子中,我们可以看出,MCC 有助于识别分类器在分类特别是负类样本时的无效性。

然而,F1 分数很大程度上受哪个类被标记为积极的影响。F1 分数在数量上与 MCC 相差如此之大,因为少数族裔被贴上了负面标签。让我们通过颠倒正反标签来看另一个例子:

有条目的混淆矩阵:TP = 1,FP = 5;TN = 90,FN = 4。

F1 分 0.18,MCC 0.103。这两个度量向从业者发送分类器表现不好的信号。

F1 的分数通常已经足够好了

重要的是要认识到多数类通常被标记为负面的(如第二个例子)。这是因为更罕见或更“有趣”的样本通常被标记为阳性,例如患有罕见疾病的患者(他们被检测为阳性)。对于这些问题,F1 分数通过更加强调积极的类别来实现其作为良好指标的目的。

F1 分数可能优于 MCC

我们在构建一个好的模型和选择信息性的度量标准上所付出的努力是为了一个主要的目的:解决现实生活中的问题。因此,不要急于下结论说某种方法或方法论是“最好的”,因为一种尺寸很难适合所有人。如果数据分析从业者有幸拥有商业领域的知识,他或她可能知道精确度和召回率是如何贴近客户的核心。在这种情况下,F1 分数以一种比 MCC 更容易解释的方式融合了精确度和召回率。只有在低精度和低召回率的成本确实未知或不可量化的情况下,MCC 才优于 F1 分数,因为它是对分类器更“平衡”的评估,无论哪一类是正面的。

结论

MCC 在数学上构造得非常漂亮,从分类器的输出被视为一个单一实体的意义上来说,它是全面的——一个可以与真实标签进行比较的变量。这可以说是二元分类问题的最佳度量。

这个故事试图比较 F1 得分和 MCC,并说明 F1 得分对于人们通常遇到的分类问题也是非常有用的。此外,在选择度量标准时,应该始终考虑问题的先验知识(如领域知识)。如果你亲爱的客户更关心 F1 的分数呢?

使用 Python 最大化您的生产力

原文:https://towardsdatascience.com/maximize-your-productivity-with-python-6110004b45f7?source=collection_archive---------5-----------------------

你创建了一个待办事项清单来提高效率,但最终却把时间浪费在了不重要的任务上。如果您可以使用 Python 创建一个任务选择系统来最大化您的生产力,会怎么样?

动机

你有没有发现自己在一天之内写了一个长长的待办事项清单,但是在检查了清单上的许多方框之后,却感觉什么都没做?原因是你虽然完成了很多任务,但大部分都很紧急却不重要。我们大多数人花时间完成需要的事情,而没有意识到我们没有做任何事情来投资我们的未来,比如读书。那么解决办法是什么呢?

艾森豪威尔矩阵来自卢克斯特

正如你在上面看到的,解决方法很简单,优先考虑重要的任务而不是琐碎的任务。但是这需要时间来找出如何适应我们一天中的重要任务,同时仍然去上课/工作/开会。好消息是,只要掌握一点 Python 知识和数学思维,您就可以轻松地创建自己的系统来最大化生产率。

方案

假设你在一天中有不同的任务要完成。早上 7 点是一天中完成所有任务的最早时间,晚上 10 点是最晚时间。由于每个时间段是 30 ',所以有(15 小时)*(2 块/小时)= 30 块。每个任务需要不同的时间来完成不同的重要分数。鉴于白天有个预定会议,您无法分配任务。你如何分配任务给最大化生产力

注意:由于每天的时间有限,您不需要分配一天中的每项任务,目标不是适合每项任务,而是最大化总分

下图是我根据自己的日常工作和任务创建的数据。

任务

时间段

availability列中,0 表示该时间段不可用于分配任务(你可能在这些时间吃早餐、去上班、开会、上课),1 表示其他情况。

读取数据:

import pandas as pd
tasks = pd.read_csv('tasks.csv')#We simplify our problem by using time block instead of hours
schedule = pd.read_csv('schedule.csv')['Availability']

纸浆优化

如果您不熟悉 PuLP,它是一个 python 库,使您能够解决优化问题。你可以在这里找到关于这个图书馆的纪录片。我将使用这个方便的包来制定和解决我们的问题。

安装软件包

克隆回购

git clone [https://github.com/khuyentran1401/Task-scheduler-problem](https://github.com/khuyentran1401/Task-scheduler-problem)

安装所有依赖项

pip install -r requirements.txt

导入模块并定义问题

from pulp import *#Define and name the problem. The objective is to maximize the productivityprob = LpProblem("Schedule_Tasks",LpMaximize)

输入参数

s = list(tasks['Important score (1-5)'])d = list(tasks['Num of blocks'])b = list(schedule)B = len(b)n = len(s)#Time blocks available
A = sum(b)

决策变量

是否在特定时间段内分配任务

y = LpVariable.dicts('Block', [(i,t) for i in range(n) for t in range(B)],
                    cat='Binary')

LpVariable允许您定义变量、名称、尺寸和类别。由于 y = 0 或 1,所以它是一个二进制变量。

目标

最大化总重要分数(通过选择一个重要的任务或通过选择许多任务)

prob += lpSum(s[i]*b[t]*y[(i,t)] for i in range(n) for t in range(B))

限制

有 3 个约束条件:

  1. 分配的时间段数量不能超过可用的时间段数量。
  2. 由于每个任务都需要一定的时间来完成,如果任务完成了,就不应该再将该任务分配到新的时间段。也就是说,需要两个时间段才能完成的任务不应该分配到三个不同的时间段。
  3. 我们假设每个块只能完成一个任务

prob += lpSum(y[(i,t)] for i in range(n) for t in range(B)) <= A #1for i in range(n):
    prob += lpSum(y[(i,t)] for t in range(B)) <= d[i] #2for t in range(B):
    prob += lpSum(y[(i,t)] for i in range(n)) <= 1 #3

解决问题,观察答案

prob.solve()print("Assignment accomplished!")
for i in range(n):
    for t in range(B):
        if y[(i,t)].varValue ==1:
            print('Task {} is assigned to block {}'.format(i,t))

结果:

结果的解释

让我们看看选择的任务:

任务 0:完成数学作业。重要分数:4

任务 1:为物理测验学习。重要分数:5

任务三:看书。重要分数:3

任务 4:完成编程项目。重要分数:3

任务 6:完成论文。重要分数:2

有几件事需要注意:

  • 不是每个任务都选(任务 2,5,7,8 都没选)。
  • 重要的任务优先于不太重要的任务(任务 0、1、3、4 比其他任务有更高的重要分数)
  • 并非每项选定的任务都在一天内完成(任务 6 被分配到 2 个区块,而需要 4 个区块才能完成)

这个解决方案实用吗?

解决方案的代价是我们无法在一天内完成所有任务。但是因为我们试图最大化一天中的重要任务,所以明智的做法是将重要任务排在其他任务之前。生产力不在于任务的数量,而在于我们完成任务的质量(T2)。

然而,有一件事我们应该考虑。在现实生活中,我们会像解决方案显示的那样,花 30 分钟完成一项任务,然后在完成前一项任务之前再做另一项任务吗?我们显然不想在短时间内从一项任务跳到另一项任务,但我们也不想因为在一项任务上工作太长时间(写一篇 2 小时的短文)而感到疲惫或厌倦。那么,我们如何对我们的问题建模,以便我们可以得到更接近现实生活的结果呢?我会让读者想出你的答案。我期待收到你的建议,这些建议要么对你的生活有用,要么对你认识的大多数人有用。

这个 Github repo 中,您可以随意使用这篇文章的代码。

我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedInTwitter 上联系我。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

[## 用 Python 选择要投资的股票

您计划在未来 3 年投资几只股票,每只股票的每一美元都有不同的预期回报…

towardsdatascience.com](/choose-stocks-to-invest-with-python-584892e3ad22) [## 为您的数据科学项目提供 Numpy 技巧

创建数组、矩阵、执行矩阵运算、解决线性代数问题和常见数据科学的技巧…

medium.com](https://medium.com/@khuyentran1476/comprehensive-numpy-tutorials-for-beginners-8b88696bd3a2) [## 如何从头开始构建矩阵模块

如果您一直在为矩阵运算导入 Numpy,但不知道该模块是如何构建的,本文将展示…

towardsdatascience.com](/how-to-build-a-matrix-module-from-scratch-a4f35ec28b56)

最大限度地采用数据产品

原文:https://towardsdatascience.com/maximizing-adoption-of-data-products-3951745854cb?source=collection_archive---------53-----------------------

办公时间

确保你的基于 ML 的产品被内部商业客户接受的方法

华特·迪士尼世界当代度假村照片(作者拍摄)。

当科学团队构建数据产品时,他们可能会遵循一个固有的过程。这个过程从收集数据开始,移动到模型构建,然后是模型生产。微软在 2017 年推出的数据科学过程生命周期【1】记录了这一过程。该流程由业务问题和客户对数据产品的接受程度来决定。作为参考,我在下面提供了数据科学流程生命周期的概述。

作者对数据科学流程生命周期的说明

如果你的团队和大多数人一样,你可能会花 90%以上的时间在这个生命周期的“中心流”上。可以说是最有趣的,也是最好玩的。就“业务问题”而言,产品经理专注于将业务问题转化为技术需求。这就剩下一个关键部分:客户接受度。“客户”既包括外部用户,也包括内部业务用户。

不幸的是,客户的接受通常是开发过程中的事后想法。

科学团队可以通过用户接受测试来确认客户的接受程度。更糟糕的是,科学团队可能会通过 RMSE、AUC 或 F1 分数等科学指标来验证客户对数据产品的接受程度。本文从内部业务用户的角度提供了接受客户的方法。我们应该认识到接受不是一次性的事情,而是贯穿数据产品生命周期的事情。我发现,至少有三个选项可以支持机器学习产品获得客户认可,或最大限度地采用。它们是:1)使它可以解释,2)提供一些控制,3)显示价值。让我们通过一组用例来探索这些组件。

让它变得可以解释……

虽然展示机器学习驱动的产品的财务影响是强有力的证据,但有时企业领导人希望了解“引擎盖下发生了什么”。虽然不可扩展,但提供基于客户的例子来说明你的科学为什么有意义,可以在获得内部认可方面大有帮助。当我在迪士尼工作时,我们有时会遇到让内部业务客户接受我们团队数据产品的挑战。下面是我们所做的一个例子。

如果你曾经试图在华特·迪士尼世界度假村或任何地方的酒店预订住宿,你可能有时会发现酒店不可用。这并不奇怪,因为在一年中的某些时候,比如夏天或节假日,酒店房间的需求量可能会超过供应量。为了最大限度地减少这种情况,我们希望全年的需求保持平稳。特别是,我们希望通过提高高需求房间的价格和降低低需求房间的价格来实现这一目标。我们的团队建立了一个基于机器学习的数据产品,该产品根据房间类型、度假胜地和一年中的时间来量化需求的价格弹性。价格弹性计算的结果通常小于零。-0.01 到-0.99 的价格弹性告诉你,客户对价格上涨不太敏感,或者对定价缺乏弹性。这意味着你可以对提高价格充满信心,只需最低限度地减少需求。相反,价格弹性小于 1 意味着顾客对价格敏感。我们创建的模型可以向我们展示在特定日期某个度假胜地的湖景、停车场景或主题公园景房间之间的弹性差异,或客人价格敏感度。使用需求预测和价格弹性模型,我们能够计算出每种房间类型和度假村的最佳价格点。有了这些认识,我们可以向企业领导层建议价格变动。

我们的团队开发的是一个离线定价模型:一个内部工具,可以为迪士尼领导层提供关于来年战术定价变化的建议。当我们计划第一次回顾这些结果时,我们意识到其中一些变化是不寻常的。这是因为我们的许多建议与历史变化不同。对于那些看起来最违背直觉的建议,我们试图为科学的驱动力提供逻辑。我们采取了以客户为中心的方法,而不是“进入黑盒子”来确定最相关的功能。我们查看了在线留言板,过去的客人在那里分享度假小贴士。我们还开车去了度假村,亲自查看房间,并与度假村经理交谈,了解他们的见解。华特·迪士尼世界的一个度假胜地,“动画艺术”,有一种房间类型,我们的模型认为它在一年的大部分时间里是无弹性的。这种房型是“海底总动员”套房。除了主题之外,这个房间类型和动画艺术中的其他房间类型没有明显的区别。因为我们知道我们的数据产品中的 ML 模型可能会受到质疑,所以我们决定参观这个度假村。走了一圈之后,很容易明白为什么这位模特会提出这些建议。海底总动员套房都位于离最大的游泳池最近的地方。它也是最靠近主建筑的地方,这里有度假村的餐厅、零售店和电子游戏中心。在下面的地图中,你可以看到黄色突出显示的海底总动员套房,灰色的主建筑,蓝色的主游泳池。

来自谷歌地图的截屏,带有作者提供的覆盖图。

我们也能够通过查看迪士尼和旅游博客来确认我们的见解。我们注意到过去的客人为我们确定的原因提供了选择海底总动员套房的建议。我们的科学模型能够通过数据推断出这一点。虽然这不是一个可扩展的方法,但我们能够为我们的模型提供基于客户的验证。

提供一些控制…

当创建主要用户是内部客户的数据产品时,您应该内置灵活性。

如果数据产品提供基于科学预测的建议,这一点尤其重要。面向内部客户的数据产品通常会取代现有的流程。在预测的情况下,遗留过程通常是一个没有因果关系的时间序列预测。从时间序列到基于科学的方法的最初商业案例是准确性和可解释性的提高。虽然基于 ML 的预测将包括许多特征,但实际上,该模型无法考虑战略决策、业务变化或其他外部因素。一个相关的例子是 Covid 导致的产品需求变化。没有任何科学模型能够预测到疫情或其持续的影响。

回到迪士尼的另一个例子,我们的团队构建了一个内部数据产品来推荐迪士尼公园和度假村的促销活动。我们促销的目的是在一年中表现不如预期的时期增加需求。因此,我们的促销是对客户对我们在上一节中讨论的定价的最初反应的回应。如果我们定价过高,促销可以让我们“调整方向”。我们开发的科学模型做了两件事。它推荐了 10%的折扣级别和促销的预订窗口.商业用户只需提供旅行窗口,或需求低于预期的一年中的时间。科学模型预测了不同折扣水平下的需求,并考虑了促销稀释。稀释意味着向客人提供折扣,即使他们可能会支付全价。

创建成千上万(或更多)预测并优化生成结果的科学模型的一个挑战是,最终用户可能不相信这些预测。这具有不相信优化结果或建议的后续后果。为了克服这些异议,我们提供了需求预测。这使得我们的内部客户能够理解模型“看到”了什么,并据此进行优化。我们还提供了场景分析功能,让用户可以查看不同折扣级别的预测。即使这样,我们仍然有客户接受的问题。这是因为迪士尼乐园和度假村的其他业务领域也在努力增加需求。在华特·迪士尼世界的某一年,有许多活动和节日。例子包括花卉和花园,食品和葡萄酒,并运行迪士尼周末。增加这些活动或改变其持续时间会对度假需求产生重大影响。这是科学模型无法理解的。

虽然不完美,但最好的方法是混合方法。这种方法从科学模型开始,然后结合内部客户的影响。具体来说,我们允许客户将自己的见解添加到科学预测中,然后根据机器学习模型和分析师输入的组合进行重新优化。为了取得成功,我们的数据产品包括:

接受内部客户输入(包括约束)的用户界面

基于科学的建议的初步产出

场景分析,包括嵌入在用户界面中的原始数据和可视化

UI 中允许内部客户提供需求“影响”的功能

基于内部客户需求影响进行重新优化的能力

存储初始预测供以后参考,以便在根据影响重新优化时减少模型运行时间

显示数值…

帮助客户接受数据产品的第三个选择是展示可量化的好处。这可以通过 AB 测试来完成。不幸的是,并不是所有的数据产品都可以进行 AB 测试。例如,之前讨论过的内部数据产品通常不能以这种方式进行验证。内部客户接受的 AB 测试方法的最佳候选是直接与最终客户交互的基于 ML 的产品。这类产品的例子包括聊天机器人、个性化 UX 或推荐。

在华特·迪士尼世界,如果潜在的客人试图预订的度假村不可用,他们会得到建议。如果迪士尼没有这样做,潜在客户有可能会寻找非迪士尼的替代产品。这些选择可能包括呆在非迪士尼度假区或寻找另一个城市度假。下面的屏幕截图显示了这样一个例子。

https://disneyworld.disney.go.com 度假村推荐截图

在实施基于科学的模型之前,我们创建了基于业务规则的方法。这始于一个静态的度假胜地列表和一个相应的三个维度的“次佳选择”列表。例如,31 个华特·迪士尼世界旅游胜地中的每一个都可以基于相似的定价、主题相似性以及与主题公园之一的接近度而具有相关联的堆栈排名列表。如上面的截图所示,从每个维度选择的度假胜地可以满足三个推荐选项中的一个。这种基于业务规则的方法在 AB 测试中充当基线或“控制”。

一旦我们建立了基于 ML 的推荐产品,潜在的客人被随机分配到两组。半数访问网站的潜在客人看到了基于 ML 模型的推荐。另一半人看到基于业务规则方法的建议。AB 测试的目标是确定客人预订率的差异。一旦我们可以量化与新数据产品相关的增量提升,我们就可以计算每年的收益。通过年化的财务收益,科学工作的价值对领导层是显而易见的,使内部客户更容易接受。不幸的是,有两个警告。如前所述,只有某些类型的数据产品可以进行 AB 测试。第二,你不能假设 AB 测试结果不会改变。即使没有推出新功能,也应该建立重新测试的节奏,以确保价值仍然存在。

所以,概括一下:

仅仅因为一个团队建立了一个机器学习模型,并不意味着内部客户会相信并采用它。

产品和科学团队经理需要明确考虑如何获得内部客户对数据产品的接受,并考虑最终客户将如何受到产品的影响。

数据产品有可能通过以下协调努力获得内部认可:1)使输出可解释,2)提供一定的灵活性和对模型的控制,以及 3)展示财务或业务价值的实验。

参考文献:

[1]https://docs . Microsoft . com/en-us/azure/machine-learning/team-data-science-process/overview

最大化 BERT 模型性能

原文:https://towardsdatascience.com/maximizing-bert-model-performance-539c762132ab?source=collection_archive---------12-----------------------

一种评估预训练 BERT 模型以提高性能的方法

图一。最大化 BERT 模型性能的培训途径。对于实体类型—人、位置、组织等—的应用程序域。是主要的实体类型,训练途径 1a-1d 就足够了。也就是说,我们从一个公开发布的 BERT 模型开始(BERT-base/large-cased/uncased,或 tiny bert 版本),并可选地进一步训练它(1c-连续预训练),然后针对特定任务对它进行微调(1d-带有标记数据的监督任务)。对于个人、位置、组织等的域。不是主要的实体类型,使用原始 BERT 模型对特定领域的语料库进行连续预训练(1c ),然后进行微调,可能不会像途径 2a-2d 那样提高性能,因为 1a-1d 途径中的词汇仍然是原始 BERT 模型词汇,具有对人、位置组织等的实体偏好。途径 2a-2d 使用从领域特定语料库生成的词汇表从头开始训练 BERT 模型。注意:任何形式的模型训练——预训练、连续预训练或微调,都会修改模型权重和词汇向量——在训练阶段从左到右,相同颜色模型的不同阴影(米色阴影)以及词汇(蓝色/绿色阴影)说明了这一事实。标有“?”的方框,是本文的重点—评估预训练或持续预训练的模型以提高模型性能。作者图片

TL;速度三角形定位法(dead reckoning)

已经证明,在特定领域语料库(例如生物医学空间)上用特定于该空间生成的定制词汇从头训练 BERT 模型对于最大化生物医学领域中的模型性能是至关重要的。这在很大程度上是因为生物医学领域特有的语言特征,这些特征在谷歌发布的原始预训练模型中没有得到充分体现(BERT 模型的自我监督训练通常被称为预训练)。这些领域特定的语言特征是

  • 生物医学领域有许多该领域特有的术语或短语,例如药物、疾病、基因等的名称。这些术语,或者广义地说,生物医学领域语料库对疾病、药物、基因等的实体偏向。从模型性能最大化的角度来看,在原始预训练模型中没有足够的代表性。最初的 BERT 模型(BERT-大型案例/无案例,BERT-基本案例/无案例)用带有实体偏差的词汇表进行预训练,该词汇表很大程度上偏向于人、地点、组织等。
  • 生物医学领域特有的句子片段/结构例如(1)“<疾病名称>继发于<药物名称>……”,**“<疾病名称>对接受<治疗名称>治疗的患者的前两个疗程无效

在保留原始词汇的领域特定语料库上进一步训练原始 BERT 模型,通常称为连续预训练,然后在监督任务上进一步微调模型已经显示出提高模型性能 (例如 BioBERT。图 1 中路径 1a→1b→1c→1d)。然而,这样的模型的性能仍然落后于在具有领域特定词汇(例如SciBERT)的领域特定语料库上从头开始预训练的模型。图 1 中路径 2a→2b→2d)

假设 BERT 模型的典型用途是采用现有的预训练模型,并在任务(图 1 中的路径 1a→1b→1d)中对其进行微调,那么在实践中通常会做出一个隐含的假设,即原始的预训练模型经过了“良好”的训练,并且表现良好。只评估微调后的模型—预训练模型的质量是理所当然的。

然而,当我们使用自定义词汇表从头开始预训练 BERT 模型以最大化性能时,我们需要一种方法来评估预训练模型的质量。BERT 的预训练模型在屏蔽语言目标(预测句子中屏蔽或损坏的标记)或下一个句子目标上的损失在实践中可能不足。

下面列出的性能检查对于检查预训练模型可能很有价值

  • 上下文无关矢量性能。检查构成 BERT 词汇的经过训练的上下文无关向量。特别是它们的聚类特征和词汇表中所有向量与其他向量的聚集分布。当执行该测试时,训练不充分/不适当的模型往往具有与训练良好的模型不同的特征。
  • 上下文敏感向量性能。当上下文无关向量通过训练模型时,在它转换成上下文敏感向量之后,检查上述上下文无关向量的质量。这些转换后的向量显示了模型在屏蔽词预测中的表现。虽然这实质上是屏蔽语言模型损失值在训练期间捕获的内容,但是对几大类屏蔽语言任务(如下所述)的模型性能的细粒度检查可以揭示比代表模型损失的单个数字更多的模型性能。假设测试是全面的,即包括针对特定领域实体类型的测试,并且具有特定领域句子结构,则在该测量中表现不佳的模型表示模型训练不足。

下面使用这两个性能度量来检查一些公开发布的 BERT 预训练模型的质量。

下面讨论的这个练习的结果强调了评估预训练模型以最大化模型性能的重要性。它还帮助我们确定是否需要进一步预训练一个公开发布的模型,即使它是在我们感兴趣的领域内预训练的,在我们为一个领域特定的任务微调它之前。

快速回顾用于 NLP 任务的 BERT 模型用例

BERT 中的自我监督学习是通过屏蔽和破坏每个句子中的几个单词来实现的,并通过预测这些单词来让模型学习。尽管这种形式的学习(自动编码器模型)限制了模型生成新句子的能力,与 GPT-2 等自回归模型相反,预训练的 BERT 模型可以原样用于无监督的 NER句子表示等。在不需要任何标记数据的情况下,利用构成 BERT 词汇表的学习向量(上下文无关向量)和模型的 MLM (屏蔽语言模型)能力,即使用上下文敏感向量的 BERT 的“填空”能力(出现屏蔽位置的模型的向量——原始词汇表中这些向量的邻居是填空的候选者)

然而,预训练 BERT 模型的流行和典型用途是针对下游监督任务对其进行微调。在某些情况下,微调之前可能会持续进行预训练,以提高模型性能(图 2)

任何形式的模型训练、预训练、连续预训练或微调,都会修改模型权重和词汇向量——在训练阶段,从左到右不同色调的相同颜色模型(米色色调)以及词汇(蓝色色调)说明了图 1 和图 2 中的事实。

图二。BERT 的 MLM 或“填空”功能对于使用预先训练的模型来执行通常以无监督方式监督的任务可能具有巨大的价值(4)。例子有无监督 NER无监督句子表示、无监督关系提取等。此外,“填空”功能也可用于评估预训练模型的性能,这可能是最大化模型性能的关键步骤。作者图片

检查以下模型的证据表明,无论使用何种训练途径(图 1 中的 1a-1d 或 2a-2d),对预训练模型性能的评估(图 2 中的步骤 3 和 6)可能是在下游任务中最大化模型性能的关键。

图 3。评估性能的模型。 伯特的 11 种典型风格——都在维基百科和图书语料库上训练过, SciBERT 在语义学者的论文上训练过微软 PubmedBERT 在 Pubmed 摘要和全文上训练过。为了这次评估,我在临床试验语料上对微软 PubmedBERT 进行了持续的预训练。作者图片

上下文相关向量的评估(MLM 检验)

三大类“填空”测试(屏蔽语言模型预测)用于评估模型性能。这些测试本质上是具有隐蔽位置的句子。屏蔽位置的模型预测分数(在整个词汇表上)用于评估模型性能。

  • 词汇测试——一个模型在带有领域语料库特有术语的句子中表现如何。这个测试类别包含词汇表中出现的完整术语(未分解成子词的术语)以及由词汇表中的子词组成的术语。
  • 领域特定实体和句子结构测试 —测试模型预测句子中领域特定实体和领域特定结构的能力。
  • 基本语言句子结构测试 —这测试模型预测感兴趣的主要语言的基本句子结构的能力(对于多语言语料库,这需要成比例地表示主要语言)

词汇测试样本

图 4a。词汇测试样本 —空白位置的 5 个模型的前 10 个预测。尽管词汇中不存在术语伊马替尼,但 BERT base 无案例预测抓住了伊马替尼是一种化学物质的概念。相比之下,SciBERT 没有捕捉到它,尽管这个完整的词存在于它的词汇表中。这在一定程度上可能是因为 SciBERT 是在科学语料库而不是具体的生物医学语料库上预先训练的。两个微软预训练模型表现不佳,但其中一个(MS-Abs+Full)在持续进行临床试验预训练时,在所有 5 个模型中表现最佳。作者图片

图 4b。词汇测试样本 —空白位置的 5 个模型的前 10 个预测。伯特的无案例预测未能抓住 braf 是一种基因的事实。SciBERT 也没有捕捉到它,尽管在它的词汇表中有完整的单词 braf。这在一定程度上可能是因为 SciBERT 是在科学语料库而不是具体的生物医学语料库上预先训练的。两个微软预训练模型表现不佳,但其中一个(MS-Abs+Full)在持续进行临床试验预训练时,在所有 5 个模型中表现最佳。作者图片

图 4c。词汇测试样本 —空白位置的 5 个模型的前 10 个预测。尽管术语尼罗替尼没有出现在词汇中,但是 BERT base 无案例预测捕捉到了尼罗替尼是一种化学物质的概念。相比之下,SciBERT 没有捕捉到它,尽管这个完整的词存在于它的词汇表中。两个微软预训练模型表现不佳,但其中一个(MS-Abs+Full)在持续进行临床试验预训练时,在所有 5 个模型中表现最佳——在这种情况下,术语尼罗替尼被微软模型分解为子词。作者图片

领域特定实体和句子结构测试样本

图 4d。领域特定实体和句子结构测试样本 —空白位置的 5 个模型的前 10 个预测。BERT base uncased 预测抓住了伊马替尼治疗疾病药物的概念。赛伯特也捕捉到了它。微软模型在这项测试中表现不佳,即使在临床试验语料库连续预训练后也是如此。作者图片

图 4e。领域特定实体和句子结构测试样本 —空白位置的 5 个模型的前 10 个预测。在这个测试中,空白位置有一个实体歧义—可能是药物或疾病。伯特 base uncased 抓住了疾病的概念,但不是药物。西伯特抓住了疾病和治疗的概念。微软持续的预先训练也抓住了这两种感觉。这两个微软预训练模型在这个测试中表现不佳。作者图片

基础语言句子结构测试样本

图 4f。基础语言句子测试—5 个模型对空白位置的前 10 个预测。考虑到训练它的语料库——维基百科和图书语料库,BERT base 在这个测试中毫不奇怪地优于其他模型。SciBERT 和 ms 连续预训练模型表现也很好,而两个 MS 预训练模型表现很差。作者图片

图 4g。基础语言句子测试—5 个模型对空白位置的前 10 个预测。BERT base 在此测试中也优于其他型号。SciBERT 和 ms 连续预训练模型表现也相当好,而两个 MS 预训练模型表现差。作者图片

上述测试的总结

虽然上面的测试纯粹是三大类别的说明性样本,但从业者可以使用像上面那样的少数定性测试来检测模型在训练模型时或训练模型后表现不佳。微软的两个预训练模型就是这样的例子——它们在所有测试中的表现一直很差。除了不准确的预测之外,表现不佳的模型还表现出不充分/不正确的预训练的其他迹象——它们具有相同的签名噪声,如不同/不同输入句子的术语。

然而,要确定模型是否经过预训练以获得最佳性能,必须在这些类别中创建足够数量的测试案例,然后根据空白位置的最佳模型预测对性能进行评分。

概括地说,在上面的测试中,

  • 微软预训练模型,在临床试验中持续预训练 (持续预训练由我 完成,以评估 ) 在生物医学领域测试中表现最佳,在基本语言测试中表现相当好
  • 尽管没有特定领域的词汇,BERT 在生物医学测试中表现得相当好(除了特定领域的术语预测),表明它经过了良好的预训练。
  • SciBERT 的表现也相当不错,然而,无论是在生物医学领域还是在基本语言测试中,他都无法超越。
  • 两个公开发布的微软预训练模型(PubMedBERT),如上所述,表现最差。鉴于持续的预训练提高了模型的性能,使其成为此次评估中生物医学领域的最佳模型,这间接证明了微软模型(即使上面的样本太小,无法得出模型性能的结论)在训练时间更长(最先进的模型尚未由微软发布— 三个模型中的两个 已发布-表 8。【论文中)】T27。这也强调了在将模型发布/用于其他任务之前对其进行评估的重要性,尽管事实上随后对在该测试中表现不佳的模型进行微调,仍然可以产生最先进的结果(两个 ms 模型就是这方面的证据)。**

上下文无关向量的评估(词汇检查)

除了由表现出不充分/差训练的可测量迹象的训练模型输出的上下文敏感向量之外,构成 BERT 词汇的向量也可以揭示关于训练质量的可测量信息。举个例子,

  • 根据伯特学习向量词汇表中的每一项与词汇表中所有其他向量的余弦分布构建的直方图。这些直方图可用于识别可能训练不充分/不正确的模型。
  • 对术语的顶部邻居进行采样也有助于揭示训练质量——顶部邻居往往是通常具有相同实体类型的那些。
  • 词汇向量的聚类。在训练期间或者在预训练和连续预训练运行之间比较训练模型的集群,提供了对连续训练的效果的洞察。

各种模型的余弦分布直方图

图五。****5 个评测模型的词汇中随机抽取约 1000 个词的余弦分布直方图。微软模型即使在持续的预训练之后,也有一个看起来更像 BERT 大模型的分布(如下)。然而,总的来说,这些并没有显示出任何异常,表明词汇向量得到了充分的训练。在连续预训练后,分布仅轻微向右移动,进一步支持了该结论。向量组(下面将会讨论)也为词汇向量被充分训练的说法提供了证据。这导致了一个合乎逻辑的结论,即 MS 模型权重可能没有被充分训练。持续的预培训解决了这一问题,带来了一流的表现。这一结论得到了以下事实的进一步证实:MS 已经训练了一个模型更长的时间,并且在所有三个模型中产生了最好的分数(三个模型中最好的模型尚未由微软公开发布)。与所有被检查的分布相比,SciBERT 有第二个凸起,使其具有独特的形状——其原因尚不清楚。一般来说,这些直方图对于检测可能指示一些潜在现象的异常分布是有用的。以上图片作者

图六。 随机抽取词汇中约 1000 个词的余弦分布直方图。 BERT 大模型(有壳和无壳,全字屏蔽)往往有一个较长的尾巴。无案例模型的分布均值更倾向于向右偏移,基础模型比大型模型更是如此。有趣的是,MS 模型与 BERT 基本模型(768 dim12 层)具有更像 BERT 大模型的分布。以上图片作者

图 7。 随机抽取约 1000 个词汇样本的余弦分布直方图。2、4、6、8、10 层伯特微小模型分布。随着层数的增加,平均值向左移动,类似于从 BERT 基本模型(12 层)到 BERT 大模型(24 层)的平均值移动上图作者

上面的数字没有显示所有 5 个评估模型的任何异常,表明在构成 BERT 词汇的向量的训练中没有明显的异常。下面对几个样本单词的余弦距离邻居测试进一步证实了这一点。

然而,包括连续预训练模型(图 6) 在内的 MS 预训练模型的一个奇怪的特性是,768 维的词汇向量(类似于基于 bert 的模型)具有类似于具有全词屏蔽的 1024 BERT 模型的分布轮廓(图 7)。很可能是全字掩蔽导致了这种分布概况()MS 模型被预训练 (具有全字掩蔽)。如果是这样的话,还不清楚为什么全词屏蔽会导致如此大量的向量几乎与其他向量正交(下面的实现注释详细说明了这一点,但还没有回答这个问题)即使在训练 之后,MS 预训练模型和 BERT 全词(有壳和无壳)的 y 截距超过 1000,与没有全词屏蔽的 BERT 基本模型和大型模型形成鲜明对比,后者低于 500

之前使用的少数词汇测试术语的前 10 个邻居

对以下术语的邻居测试显示,它们的邻居都很好,即使对于两个 ms 预训练模型和 SciBERT 也是如此,这两个术语都出现在除 BERT 之外的所有评估模型的词汇表中。然而,这三个模型在包含这些术语的句子测试中表现不佳,这表明模型层的训练与词汇向量本身相反是不充分的。MS 模型的分布尾部的平均长度相对较高,表明高质量的邻居,为训练有素的词汇向量提供了进一步的证据(下面的实施说明中有示例)

图 8。 词汇测试中使用的两个词的前十名邻居。对这两个词的测试表明,它们的邻居都很好,即使对于两个 ms 预训练模型和 SciBERT,这两个词也存在于除 BERT 之外的所有评估模型的词汇中。然而,这三个模型在包含这些术语的句子测试中表现不佳,这表明模型层的训练与词汇向量本身相反是不充分的。以上图片作者

词汇向量的聚类

此外,当检查由微软预训练模型(摘要+全文)及其持续预训练版本的向量形成的聚类时,其中聚类是用固定阈值(60 度-0.5 余弦)完成的,80%的聚类是相同的。这进一步证实了这样的事实,即使在原始的预训练模型中,词汇向量也得到很好的训练。需要进一步培训的是模型层。词汇向量的聚类没有固定阈值,但具有基于单个术语确定的截止值(主要基于特定余弦距离的邻居的个位数计数),显示了 MS 模型的长尾(实施说明中的示例)。这进一步证明了训练有素的词汇向量。

[连续]预培训的顺序流程

下图显示了在训练和连续预训练期间最大化模型性能的顺序流程。下面的顺序甚至适用于模型输出一组检查点(相对于一个最终检查点)的情况,我们评估每个检查点,如流程所示。但是,在这种情况下,如果一个检查点未通过 MLM 检查,我们可以丢弃它,前提是选择了一个更新的检查点作为候选检查点。

图 9 显示了在训练和连续预训练期间最大化模型性能的顺序流程。作者图片

最后的想法

对具有定制词汇的领域特定语料库进行预训练或持续预训练已被证明是从业者的关键,尤其是当将该模型用于各种下游任务时,无论是受监督的还是不受监督的。任何不利用特定领域定制词汇表的方法都被证明产生相对次优的结果,至少在生物医学领域是这样。当进行预训练或持续训练时,不像通常的方法那样只对一定数量的步骤或时期进行预训练,而是对下游任务进行微调,按照本文中讨论的思路评估模型可能会在这些下游任务中产生更好的性能。

从从业者的角度来看,BERT 的“填空”(MLM)学习方法的效用不能被夸大,尽管这种学习方法限制了该模型成为像 GPT-2 那样的生成性模型。除了如本文所示用于评估训练的 BERT 模型的质量之外,“填空”能力在与学习的词汇向量结合使用时,有助于将传统的监督任务转换为非监督任务(例如非监督 NER )。

实施说明

  • 术语“微调”的澄清。在本文中,微调仅用于接受预先训练或持续预先训练的模型,然后在监督任务中对其进行训练的任务。
  • 当 BERT 模型被持续训练/微调时,可以添加额外的特定于域的令牌。这是一个有限的改进,在上面的文章中没有提到,因为它没有解决原始词汇表中的实体偏差问题。
  • 预处理语料库遵循 BERT 的 Github 页面中的建议是最大化模型性能的关键。使用 HuggingFace 的预训练目前有一个限制——它在训练之前将整个语料库读入内存(这个代码正在快速更改,所以这个问题可能会很快得到解决)。这使得在没有大量内存的情况下,对大型语料库进行预训练是不切实际的。
  • 当使用原始 BERT 发布代码进行【连续】预训练时,全词屏蔽已被证明可提高模型性能。当创建训练前记录时,而不是在训练前期间,需要指定该选项(我犯了这个愚蠢的错误,并想知道为什么在生成训练记录期间没有发生全词屏蔽。但是请注意,如果我们检查训练记录输出,我们可能会发现单词的前缀被屏蔽,而后缀没有——这只是因为随机标记替换(BERT 既屏蔽又替换)发生在标记化的句子上
  • 当使用原始 BERT 发布代码进行【连续】预训练时,用于创建预训练记录的序列长度需要与预训练期间使用的序列长度相同。
  • 当使用原始 BERT 发布代码进行【连续】预训练时,可能需要选择与我们选取的序列长度相对应的批量大小,批量大小也由可用的 GPU 内存决定
  • 当使用原始 BERT 发布代码进行预训练时,即使是针对特定领域进行预训练,也可能有助于添加来自通用语料库(如图书语料库)的句子。然而,该语料库不必是 vocab 生成的一部分。
  • 当使用原始 BERT 发布代码进行预训练时,定制词汇文件生成最好在领域语料库的子集上完成,该子集从术语的角度来看是有代表性的和干净的。检查词汇向量的群集可以揭示看起来有噪声的群集。这可能表明词汇生成过程可以改进。对于词汇生成子集语料库,最好有选择地删除与我们感兴趣的领域不相关的非 ascii 字符。数字术语也是一样(对于数字术语,我们需要确保添加 0-9 的次数与词汇生成中的最小频率计数一样多,以确保它们被包含在内)。这为固定大小的词汇留下了更好地表示语料库的空间。然而,这些字符/术语最好保持原样用于训练。在标记化期间,它们将被未知标记(或者在数字的情况下——由数字构成)替换,同时仍然保留句子结构(移除它们将影响句子结构)
  • 下图显示了从头开始预训练模型时矢量分布的直方图。正如人们所料,所有向量几乎都是相互正交的——这是高维向量随机初始化的好处。

图 10从零开始预训练模型时,词汇中大约 1000 个词的随机样本的余弦分布直方图。正如人们所料,所有向量几乎相互正交——这是高维向量随机初始化的简单好处。值得注意的是,所有 BERT 发布的预训练模型都有数百个正交向量,只有一千多个的全词屏蔽模型除外。MS 预训练模型具有类似的高数量的正交向量,并且即使在连续预训练之后也保持如此。需要回答的问题是,这些向量是在训练期间移动,然后变得接近正交,还是在训练期间根本不移动。如果结果是它们根本没有移动,那么这可能表明词汇生成没有真正代表特定领域语料库——这个问题可以通过在真正代表整个语料库的语料库子集上重新生成词汇来解决。然而,检查具有大量正交向量的项揭示了具有长尾的高质量邻域。这类似于我们在全词屏蔽 BERT 模型中看到的情况。这表明,全词屏蔽似乎在创建实体类型、保持具有语义上接近的术语的高质量邻域以及通过使它们接近正交来分离语义上不接近的术语方面起作用。以上图片作者

  • 全词掩蔽在确定词汇向量的质量中起着重要作用,这可以通过两个测量来量化:( 1)与术语正交的向量的数量平均增加。这些正交向量是语义上远离术语的术语。( 2)术语与词汇表中其他术语的余弦距离分布中的尾部长度也增加。这对于像无监督 NER 这样的任务具有巨大的价值,在这些任务中,实体标注依赖于词汇向量簇。下图说明了使用全字屏蔽时正交向量的数量呈线性下降,而不使用全字屏蔽时呈指数下降

图 11。全词掩蔽对词汇向量的影响。与某项正交的向量数量显著增加(y 截距更高)。所有全词屏蔽模型(MS 模型和两个 BERT 模型)都表现出这种行为。此外,与非整词屏蔽的指数下降相比,对于整词屏蔽模型,正交向量的下降是线性的。高正交向量计数间接表示高质量的向量邻域。上图作者

  • 下图显示了没有和有全词屏蔽的示例术语的邻域

图 12。对于全词屏蔽模型,实体类型以长尾形式保留,这与没有全词屏蔽的模型相反(左侧为 bert-large-uncased)。上图作者

  • 用于本次评估的 Github 库 MLM 检查vocab 检查
  • 上述评估中使用的 MS 预训练模型的时间戳。这些模型可能会在将来被训练得更好的模型更新,使得本文的一些结果不可复制。

本次评估中使用的 MS 摘要+全文模型的时间戳作者图片

本次评估中使用的仅 MS 抽象模型的时间戳作者图片

  • 更新了文章,将[CLS]矢量性能纳入模型评估。下一句预测可用于学习对各种任务有用的高质量句子表达。以下可视为评估预训练模型质量的测试列表。(1)对上下文敏感向量的 MLM 检查(如上所述) (2)对上下文无关向量的评估——聚类(不是固定阈值,而是每个词的 z 分数驱动阈值)、累积分布形状的直方图——是均值远且接近 1 还是理想地接近 0、零向量计数/分布(与向量正交的向量的数量);(3)【CLS】性能

本文原帖 Quora

使用 Python 中的线性规划实现利润最大化

原文:https://towardsdatascience.com/maximizing-profit-using-linear-programming-in-python-642520c43f6?source=collection_archive---------8-----------------------

明丹迪FreePik 上的照片

学习如何解决最大化线性规划问题

线性规划(LP)和单纯形算法已经存在了几十年。早在 40 年代,它就被美国空军首次引入,用于帮助制定战略计划。从那时起,许多行业都在利用它来最大化利润和最小化成本,等等。

单纯形法是为了帮助解决 lp 问题而设计的,它基本上就是我们将在这里看到的。随着技术领域的进步,这种方法开始被使用,不仅在军事上,而且在无数的行业。今天,我将向大家展示一个我们如何利用这种算法的例子。我将介绍以下内容:

1-线性规划的基本概念

2-如何制定一个线性规划问题

3-如何使用 Python 求解线性规划

4-用图解的方式看 LP 问题

基本概念

线性规划和线性不等式齐头并进。也就是说,许多现实生活中的问题都受到一些限制,例如生产一把椅子的原材料数量。换句话说,有些限制阻止我们在不影响其他产品生产的情况下生产一种产品。

例如,假设你需要木材来制作椅子和桌子,那么你可用的木材数量就限制了你能生产的椅子和桌子的数量。

本质上,这正是 LP 试图解决的问题:如何系统地分配资源,以便从我们所拥有的限制(约束)中获得最大收益,同时考虑,例如,你从他们的销售中获得的利润的潜在最大化。关于这一点,我们可以使用 LP 来最大化利润,或者最小化成本。有趣的是,我们可以将最大化问题转化为最小化问题,反之亦然。但这不会是这里的重点。

在 LP 中,当我说“解决”时,并不意味着我们会一直找到解决方案(比如 2 + 2 = 4)。我们可以公式化一个 LP 问题,做一些数学计算,并得出结论,特定的 LP 问题没有最优解,这是解决 LP 的主要目标:试图获得唯一的最优解。这可能是因为一些问题可能有太多不同的最优解或者甚至根本没有最优解

我们可能遇到没有最优解的 LP 的一些原因可能超出了我们的控制。在许多情况下,问题太复杂而无法解决(找到唯一的最优解)。在解决 LP 问题时,我们可能想问自己一个问题:问题可行还是不可行?有些问题甚至可以有很多可行解,最后被无界。总结一下,我们可以把一个 LP 问题分为三类:最优解不可行无界

在这里,你将看到一个 LP 问题的例子,它给了我们一个最优解。但是在我们开始解决问题之前,我想给你看一个传统 LP 问题的例子:

摘自《线性规划》一书(Chvatal 1983)

第一行写着“最大化,这就是我们的 目标函数 所在的位置。这也可以说“最小化”,这将表明我们的问题是一个最小化问题。

第二行和第三行是我们的 约束。 这是基本上是什么阻止我们,让我们说,最大化我们的利润到无限。就像我已经提到的,这是我们可以发现线性不等式 (≤、=、≥)的部分。我还必须透露,有不同的方法来解决一个线性规划问题,例如,BigM,对偶,两阶段的方法等。

不幸的是,试图在这里涵盖 LP 的所有细节是适得其反的,我希望您已经掌握了一些基础知识,可以继续学习我们的示例。如果没有,我会在这篇文章的末尾删除一些参考资料,这样你就可以参考了。

false 优化是现代研究对决策过程的革命性贡献——乔治·丹齐格

问题

假设我们在一家制造公司的数据科学团队工作。我们在这里要解决的问题被命名为“活动分析问题”(Gass 1970)。数据科学团队的目标是通过定义生产多少种不同的产品,并考虑到可用资源的有限性,来最大化制造公司的利润。通过改善公司的运营和资源配置,我们有可能最大化利润,这是我们这里讨论的焦点。

公司生产四种家具:椅子桌子书桌书柜。主要成分是红木,但他们也使用胶水,皮革,玻璃和工时。例如,当我们看到一把椅子时,制作一把椅子真正需要的是 5 板英尺的红木,10 个工时的劳动,3 盎司的胶水和 4 平方英尺的皮革。生产一张桌子,我们需要 20 英尺木板,15 个工时,8 盎司胶水。一张桌子由 15 板英尺、25 工时、15 盎司胶水和 20 平方英尺皮革制成。最后,书柜是用 22 英尺木板、20 个工时、10 盎司胶水和 20 平方英尺玻璃制成的。

以下是制作一把单人椅子所需材料的示例:

作者图片

瓶颈是所有这些材料每周的可用总量如下:

- 两万板英尺的红木

-4000 工时

-2000 盎司胶水

-3000 平方英尺的皮革

- 500 平方英尺的玻璃

正如你所看到的,有限数量的材料使我们无法同时生产无限数量的产品。也就是说,我们的工作是决定如何更好地分配这些资源,以获得最大利润。这是一个如何开发数据驱动的决策流程的练习。

但是为了建立这个问题,我们需要知道每个产品给公司带来的利润。提示:这就是我们想要的最大化

他们在这里:

- :每把椅子 45 美元

- :每桌 80 美元

- :每张桌子 110 美元

每个书架 55 美元

等等!人们可能决定只生产桌子,因为仅这一项就有最高的利润(110 美元)。但是,为什么我们不应该接受这种方法呢?我会留给你答案。

由于我们想生产所有这四种产品,并向我们的客户提供良好的产品组合,同时分担风险,我们真正想知道的是,为了获得最大利润,每种产品我们必须生产多少单位。这就是 LP 建模可以帮助我们解决这个问题的地方。

公式化线性规划问题

对于这个 M 最大化 LP 问题,我们将用项目名称的第一个字母来表示项目。同样, c 为椅子, t 为桌子, d 为书桌, b 为书柜。

就像我们在前面的例子中生产一把椅子需要什么一样,我们将对所有其他项目遵循类似的模式。下面我们可以看到制作每一个产品所需的资源量。请注意,制造这些产品的总量必须是可用资源总量的等于

作者图片

请慢慢阅读这个模式。我只是把制造我们四种产品中每一种产品的数据放在一起,加上约束,这是可用的资源(最后一栏)。

现在,为了以一种更传统的方式来制定我们的 LP,我们所要做的就是带来项目的利润(目标函数)。下面是这个 LP 问题的最终表述:

作者图片

我们做到了。恭喜你!拍拍你自己的背,因为通常,公式化一个 LP 问题是这个过程中最难的部分。记住“垃圾进,垃圾出”,所以一个 LP 如果制定不当,是不会带来多大价值的。

既然我们已经将问题公式化了,我们将使用 Python,更具体地说,使用名为 PuLP 的库来解决这个 LP。没有进一步的原因,让我们做那件事。

线性规划是线性代数的推广。它能够处理各种问题,从为航空公司或影院中的电影寻找时间表到从加油站向市场配送石油。如此多才多艺的原因是约束可以很容易地被结合到模型中——史蒂文·j·米勒

使用 Python(纸浆库)求解线性规划

关于如何在 Anaconda 上安装纸浆的说明可以在这里找到。

因为这是一个简单的例子,而且我们没有处理很多变量、约束等,我们不会使用任何文件(比如 csv 文件)并将其导入 Python,我们只是输入这几个变量。我们也可以创建一个 Python 程序来请求用户以一种更高层次和更有组织的方式来做这件事,但是我会把这留给你。

我将把这个部分分成两部分:第一部分我们将使用 PuLP 在 Python 中解决这个问题,第二部分我们将解决它。

第一部分:

安装完纸浆后,我们需要导入纸浆库,如下所示:

*# import the library PuLP as p 
import pulp as p*

接下来,我们将设置最大化问题并初始化变量:

*# Set Up a LP Maximization Problem:
Lp_prob = p.LpProblem('Activity-Analysis_1', p.LpMaximize) # Here we named the Problem "Acitity-Analysis_1".

# Set Up Problem Variables: 
c = p.LpVariable("c", lowBound = 0) # "c" for chair
t = p.LpVariable("t", lowBound = 0) # "t" for table
d = p.LpVariable("d", lowBound = 0) # "d" for desk
b = p.LpVariable("b", lowBound = 0) # "b" for bookcase*

现在,这就是我们将创建目标函数(我们试图最大化)和约束的部分。

*# Create Objective Function:
Lp_prob += 45 * c + 80 * t + 110 * d + 55 * b    

# Create Constraints: 
Lp_prob += 5 * c + 20 * t + 15 * d + 22 * b <= 20000
Lp_prob += 10 * c + 15 * t + 25 * d + 20 * b <= 4000
Lp_prob += 3 * c + 8 * t + 15 * d + 10 * b <= 2000
Lp_prob += 4 * c + 20 * d <= 3000
Lp_prob += 20 * b <= 500*

最后,我们将显示这个问题,以确保事情看起来不错。

*# Show the problem:
print(Lp_prob) # note that it's shown in alphabetical order*

运行上述代码后,您的 LP 问题应该是这样的:

作者图片

正如你所看到的,显示的问题看起来像我以前写的那个,除了纸浆按字母顺序组织变量,这对解决方案没有任何影响。到目前为止,我们所做的只是输入我们之前讨论过的变量,并用 Python 对 LP 问题建模。为了简单和更容易理解,我们现在不解决它,而是在第二阶段。

第二阶段:

在这里,我们将创建一个新的简化问题,该问题源自我们刚刚看到的问题。这样做的原因只是为了更容易传达解决方案,这也有助于获得解决这类问题的额外直觉。

好的,在这个新问题中,我们仍然使用相同的变量,但是现在我们把它减少到只有两个变量(椅子和桌子),并且我们改变了一些数字。这是我们新的最大化问题的样子:

作者图片

事实上,我们保留了大部分的数字不变,但是现在,红木的总数是 400,工时总数是 450。第二个约束条件也由“15t”改为“20t”。现在我们将用 Python 解决这个问题,如下所示:

*### Simplifying the Problem and Solving it #### Generate a New LP Maximization Problem:
Lp_prob2 = p.LpProblem('Activity-Analysis_2', p.LpMaximize)

# Generate Problem Variables (>= 0): 
c = p.LpVariable("c", lowBound = 0)
t = p.LpVariable("t", lowBound = 0)# Create Objective Function:
Lp_prob2 += 45 * c + 80 * t #+ 110 * d + 55 * b    

# Set Up the Constraints: 
Lp_prob2 += 5 * c + 20 * t <= 400
Lp_prob2 += 10 * c + 15 * t <= 450# Show the problem:
print(Lp_prob2) # note that it's shown in alphabetical order*

同样,让我们看看这个新问题是如何在 Python 中显示的:

作者图片

它看起来很好,所以现在我们可以着手解决它。下面是这样做所需的代码。请注意,我们将打印解决方案的“状态”,它只是告诉我们解决方案是否是最优(或者不是)。在这个例子中,我们得到了一个最优* 。*

*# Solve the Problem:
status = Lp_prob2.solve()
print(p.LpStatus[status])   # Display Solution Status*

请记住,并非所有 LP 问题都有一个最优解决方案。现在,为了真正看到实际的数字,我们需要如下所示的打印结果。

*# Printing the final solution 
print(p.value(c), p.value(t), p.value(Lp_prob2.objective))# Result: 24.0 14.0 2200.0*

于是我们得到了“24”、“14”、“2200”。有人可能想知道这些数字是什么,对吗?结果是,24 和 14 分别是我们需要生产的椅子和桌子的最佳数量,以便获得 2200 美元的最佳利润。提示:线性编程完全是关于优化

如果您愿意,可以创建一个循环来显示这个结果。这里有一个例子:

*# Printing Number of Chairs and Tables:
for var in (c,t):
    print('Optimal number of {} to produce is: {:1.0f}'
          .format(var.name, var.value()))# Output:
# Optimal number of c to produce is: 24
# Optimal number of t to produce is: 14*

换句话说,考虑到我们对可用的红木数量和工时的限制,生产这两种物品并获得最大利润的最佳组合是: c =24 把椅子, t =14 张桌子,为了找到最佳利润,我们必须将目标函数带入该方程。这将看起来像: $45 x 24 + $80 x 14 = $2,200

我们刚刚用单纯形算法解决了这个问题。现在,我们可以根据数据做出决定,并得到结果的支持。不是基于直觉,对吗?!

还有一件事我需要指出的是,单纯形可能是相当具有挑战性和棘手的解决方案。虽然在这里看起来像是小菜一碟,但是如果你试图用手来解决它,如果你不知道实际上是什么和如何做,你会有一段艰难的时间。感谢上帝,现在我们有能力使用像 Python/PuLP 这样的解决方案来做到这一点。

在结束我的案例之前,我想向你展示如何将这个问题绘制成图表。解决线性规划问题有许多方法,图解法是其中之一。

使用单纯形图

所以,我走到白板前,画出了单纯形图,让我们的讨论更进一步。下面是绘图(可以在 Python 上使用 Matplotlib 完成):

作者图片

看起来不错吧?!让我向你解释我们是如何到达那里的。

首先,我们开始查看 LP 问题的第一个不等式(5c + 20t ≤ 400),在这种情况下,用橙色表示。我们需要的是找到两个点,一个为 c 轴,另一个在 t 轴(记住 c 为椅子, t 为桌子)。想出那个最简单的方法是假设如果 c = 0,我们必须得到 t = 20,并在 t 轴上标记那个“点”;如果 t = 0,那么我们得到 c = 80,我们把它画在 c 轴上。

其次,我们绘制最后一个约束(10c + 15t ≤ 450),用绿线表示。按照与前面相同的方法,我们得到轴上的点如下:45,0 和 0,30。

在这个图中,我们看到的是这两个不等式的叠加。通过重叠它们,我们可以计算出所需的解空间,也就是黄色突出显示的区域。这个区域中的任何点都将满足这个问题的约束,这个组合代表了考虑到我们可用的资源(桃花心木和工时),我们可以生产的不同的桌椅组合。当两条线相交时,我们得到的最优值为 24,14(红色)。这意味着 c =24,而 t =14 正好满足这两个约束。我们在使用纸浆时也发现了同样的结果,但是如果你想证实这一点,你可以使用一些代数方法。

最后我们看目标函数* (45c + 80t = 0)。这由灰色线表示。现在,让我们想一想。如果公司不生产任何桌椅,它的利润会是多少?零,对吗?!这将意味着 c =0,而 t =0。这是我们使用单纯形法的起点,我们可以将那条灰线从零向上移动到与 ct (24,14)相交的点,但不能移出黄色区域的边界。通过这样做,我们最终得到了最优的公式,我们以前见过这个公式: $45 x 24 + $80 x 14 = $2,200。*

到现在为止,你可能已经有了可以用不同的值进行实验的直觉,并且最终基于目标函数的变化测试了多个最佳解决方案。我希望这对你有用。

这个例子摘自 Saul I. Gass 的《线性编程图解指南》一书。你可以在我的 GitHub 这里找到代码。

开始吧,但不要试图一餐吃掉大象。从试点项目开始,构建您的第一个仪表板。从那里你可以学习、提高并扩展到其他领域——鲁珀特·邦汉姆·卡特

结论

在本文中,您了解了 LP 的一些基本概念,您了解了如何制定 LP 问题,以及如何解决它。资源的优化将永远是世界上许多公司议事日程的一部分。根据项目的范围,最大化和/或最小化总是有问题。

数据科学家至少需要有一个关于 LP 如何有用的非常基本的概念,以及我们今天可以用来帮助我们的资源。我希望这篇文章能激励你去做自己的实验。祝你好运。

谢谢大家!

参考资料:

[1] Lial,格伦威尔和 Ritchey,2012:有限数学。马萨诸塞州波士顿:皮尔逊。

[2] Chvatal,Vasek,1983:线性规划。美国:弗里曼。

[3] Gass,Saul I .,1970:线性规划图解指南。加拿大:多佛。

通过可用材料实现利润最大化

原文:https://towardsdatascience.com/maximizing-profits-by-materials-available-3be9f1a64d6d?source=collection_archive---------57-----------------------

线性规划在供应链运作中的应用初探

Guillaume Bolduc 在 Unsplash 上拍摄的照片

如果你正在寻找一款更深入一点的 jupyter 笔记本,看看这款笔记本

虽然有些公司可能没有实物商品,但在今天的世界上,许多公司仍然有,对于这些公司来说,重要的是不要浪费任何材料,因为这意味着浪费金钱。

我们将研究一个线性问题,假设我们有实物产品,而我们只有有限数量的材料来制造这些产品,我们如何最大化我们得到的回报。我们将通过创建一个线性约束优化问题来做到这一点,并举例说明。

现在,让我们设置一个示例问题。

  1. 我们卖什么,卖多少钱?在当今时代,加入家具游戏可能不是最明智的举动,但这正是我们今天要模仿的。假设我们是一家小型家具公司,我们销售两种产品,桌子和椅子,价格分别为 $30$45(这些椅子很别致,但桌子很一般)
  2. 每件产品需要多少材料?
    所以做一张桌子,需要 22 根木头15 根钢
    T22;做一把椅子,需要 45 根木头10 根钢。换句话说,这就是我们在制造每一张桌子和椅子时从可用材料中去除的量。
  3. 总共有多少可用材料?
    在这个问题中,我们将可利用的材料设定为 5500 木材2500 钢来配合工作。

注意:我没有使用任何特定的单位,所以如果你打算使用这种方法,就标准化单位

双注:我们将使用图形方法来解决我们的问题,但你可以使用像 CVXPY 这样的库来构建你的问题,并使用求解器来获得解决方案。如果你想了解更多关于解决线性或凸性问题的方法,请查阅单纯形内点方法

现在我们对这个问题有了一个大致的概念,我们想要以一种具体的形式来定义这个问题,我们将通过把它分成两部分来做到这一点目标函数(即我们想要最大化的部分)和不等式约束(即我们必须保持的阈值)。

目标函数

这个问题的目标是利润最大化。这是通过销售每件商品的正确数量来实现的,这样我们可以获得最多的钱。我们可以用下面的函数来表示

最大 f(t,c) = t30 + c45

其中 t 和 c 分别是我们售出的桌椅数量

我们可以把它推广到向量和矩阵,但是为了这个玩具问题,我们将保持这种方式

我们可以看到,如果我们可以得到 t 和 c 值的完美组合,那么我们就可以最大化我们的利润,同时仍然有效地利用手头的材料。

不等式约束

不等式约束告诉我们什么时候使用了太多的材料,否则会迫使问题超出可行性区域(即我们没有那么多可用的材料,所以不可能)。

现在我们知道我们有 5500 块木头和 2500 块钢材可以使用。因此,我们可以从为木材创建不等式约束开始。每张桌子需要 22 块木头,每把椅子需要 45 块木头。所以我们可以把它翻译成这样一句话

h1(t,c) = t22 + c45 ≤ 5500

我们可以对我们的钢约束做类似的事情

h2(t,c) = t15 + c10 ≤ 2500

为了完整起见,我们需要包括我们想要零个或多个或每个项目,因为负面的桌子和椅子没有意义。

h3(t,c) = t ≥ 0
h4(t,c) = c ≥ 0

我们现在可以在我们的问题中使用这些不等式约束。

构造最终问题并以图形方式求解

既然我们已经得到了这些碎片,现在我们终于可以把它们组合在一起了。这是看起来的样子。

最大化 f(t,c) = t30 + c45
服从
h1(t,c) = t22 + c45 ≤ 5500
h2(t,c) = t15 + c10 ≤ 2500
h3(t,c) = t ≥ 0
h4(t,c) = c ≥ 0

现在,通常你会用某种迭代方法来解决这个问题,比如单纯形法或者内点法。但是因为只有两个变量(桌子和椅子)我们可以用图解法解决这个问题。

由德斯莫斯制造

当画这个图的时候,我简单地采用了约束条件,并把变量 c(椅子)单独安排在左边。y 轴表示购买的桌子数量,x 轴表示椅子数量

这给我们留下了空白空间中的可行区域,该区域也是多项式。

现在,当用图解法求解时,我们将采用类似于单纯形法的(不精确)方法,通过查看角点解。

注意:单纯形法不是查看所有的点,然后进行比较,而是使用松弛变量来判断是否达到了最佳点,但除此之外,它会访问拐角点

我们有 4 个点要看(0,0),(166.667,0),(126.374,60.44),(0,122.222)。如果我们把这些坐标代入我们的目标函数,我们可以看到哪一个产生最好的结果

f(0,0) = 0
f(166.667,0) = 5000.01
f(126.374,60.44)= 6511.02
f(0,122.222) = 5499.99

我们可以看到(126.374,60.44)的角点给出了最好的结果。请注意,我们没有得到整数值,因为这可能是通过整数编程可以实现的一个改进点,但这是另一篇文章的内容。

结论

我们看到,给定一个由物理材料组成的变量的问题,我们可以通过使用线性规划来最大化我们可以得到的钱数。希望这篇文章激起你对数学优化的兴趣,因为它是一个有趣的领域,对许多现实生活场景都很有用。

如果你喜欢这篇文章,并且想看更多我的作品,请查看www.kevinpallikunnel.com,并随时给我发电子邮件,我很乐意与你聊天。

最大似然分类

原文:https://towardsdatascience.com/maximum-likelihood-classification-4b129971ea92?source=collection_archive---------12-----------------------

实现最大似然分类器并使用它来预测心脏病

这是关于什么的?

最大似然分类的主要思想是预测使我们观察到的数据 x 的似然性最大化的类别标签 y 。我们将把 x 视为随机向量,把 y 视为 x 的分布所依赖的参数(非随机的)。首先我们需要对 x 的分布做一个假设(通常是高斯分布)。

然后,我们的数据学习包括以下内容:

  • 我们将数据集分成对应于每个标签 y 的子集。
  • 对于每个子集,我们仅使用该子集内的数据来估计 x 的假设分布的参数。

当对新的数据向量 x 进行预测时:

  • 我们使用每个标签 y 的估计参数来评估假设分布的 PDF。
  • 返回评估的 PDF 具有最大值的标签 y

让我们从一个简单的例子开始,考虑一个一维输入 x ,和 2 个类: y = 0y = 1

假设我们估计了在 y = 0y = 1 两种情况下的参数后,我们得到了上面绘制的这两个 pdf。蓝色的( y = 0 )有均值𝜇=1 和标准差𝜎=1;橙色地块( y = 1 )有𝜇=−2 和𝜎=1.5.现在,如果我们有一个新的数据点 x = -1,我们想预测标签 y ,我们评估两个 pdf:𝑓₀(−1)≈0.05;𝑓₁(−1)≈0.21.最大值是 0.21,这是我们考虑 y = 1 时得到的,所以我们预测标签 y = 1

这只是一个简单的例子,但在现实世界的情况下,我们将有更多的输入变量,我们希望使用,以作出预测。因此,我们需要一个多元高斯分布,其 PDF 如下:

要让这个方法起作用,协方差矩阵σ应该是正定;即它应该是对称的,并且所有特征值应该是正的。协方差矩阵σ是包含 x:σ𝑖𝑗=𝑐𝑜𝑣(𝑥𝑖,𝑥𝑗).所有分量对之间的协方差的矩阵所以,它是一个像𝑐𝑜𝑣(𝑥𝑖,𝑥𝑗)=𝑐𝑜𝑣(𝑥𝑗,𝑥𝑖一样的对称矩阵),因此我们要检查的是所有的特征值都是正的;否则,我们将显示警告。如果观测值比变量多,且变量之间没有很高的相关性,这个条件应该满足,σ应该是正定的。

现在,让我们来实现它

利用多分类器预测心脏病

图片由米利安·齐尔斯 @ 皮克斯贝提供

对于这个任务,我们将使用这里提供的数据集。该数据集由一个 csv 文件组成,该文件有 303 行,每行有 13 列可用于预测和 1 个标签列。下表显示了每个字段的简短描述:

我们得到了 80.33% 的测试准确率。虽然这种方法的精确度不如其他方法,但我仍然认为这是一种有趣的思考问题的方式,因为它简单而给出合理的结果。

Jupyter 笔记本可以在这里找到。

我希望这些信息对您有用,感谢您的阅读!

这篇文章也贴在我自己的网站这里。随便看看吧!

R 中的最大似然估计

原文:https://towardsdatascience.com/maximum-likelihood-estimation-in-r-b21f68f1eba4?source=collection_archive---------2-----------------------

通过这份快速简单的指南,最大限度地提高您在统计方面取得成功的可能性

🇨🇭·克劳迪奥·施瓦茨| @purzlbaum 在 Unsplash 上拍摄的照片

通常,你会有某种程度的直觉——或者具体的证据——来表明一组观察结果是由特定的统计分布产生的。与你正在模拟的现象相似的现象可能已经被证明可以用某种分布很好地解释。您正在研究的情况或问题的设置可能会自然地建议您尝试一系列的发行版。或者,你可能只是想通过将你的数据拟合到某个模糊的模型来获得一点乐趣,看看会发生什么(如果你在这方面受到挑战,告诉人们你正在做探索性的数据分析,并且当你在你的区域时,你不喜欢被打扰

现在,有许多方法可以根据你所拥有的数据来估计你所选择的模型的参数。其中最简单的是矩量法——一个有效的工具,但是也有它的缺点(值得注意的是,这些估计值经常有偏差)。

你可能想考虑的另一种方法是最大似然估计(MLE),它倾向于对模型参数产生更好的(即更无偏的)估计。技术含量高一点,但没什么我们不能处理的。让我们看看它是如何工作的。

什么是可能性?

似然——更准确地说是似然函数——是一个表示从给定模型中获得某一组观察值的可能性有多大的函数。我们认为这组观察值是固定的——它们已经发生了,它们发生在过去——现在我们考虑在哪组模型参数下我们最有可能观察到它们。

一个简单的抛硬币的例子

考虑一个例子。假设我们将一枚硬币抛 100 次,观察到 52 个正面和 48 个反面。我们想出一个模型来预测如果我们继续翻转另外 100 次,我们会得到多少个头。

把这个问题正式化一点,让我们想想 100 次抛硬币得到的人头数。鉴于:

  • 只有两种可能的结果(正面和反面),
  • 有固定数量的“试验”(100 次抛硬币),而且
  • “成功”的可能性是固定的。

我们可以合理地建议使用二项式分布来模拟这种情况。

我们可以使用 R 来如下设置问题(查看用于本文的 Jupyter 笔记本以了解更多细节):

# I don’t know about you but I’m feeling
set.seed(22)# Generate an outcome, ie number of heads obtained, assuming a fair coin was used for the 100 flips
heads <- rbinom(1,100,0.5)heads# 52

(为了生成数据,我们使用了 50%的机会得到正面/反面,尽管我们打算暂时假装不知道。对于几乎所有现实世界中的问题,我们都无法获得生成我们正在查看的数据的过程的这种信息——这就是为什么我们有动力去估计这些参数!)

在我们将正面/反面过程公式化为二项式过程的情况下,我们假设每次掷硬币都有获得正面的概率 p 。由此延伸,在 100 次翻转后获得 52 个头的概率由下式给出:

这个概率就是我们的似然函数——它允许我们计算概率,即在给定正面概率的情况下,我们的数据集被观察到的可能性有多大。给定这种技术的名称,你也许能猜到下一步——我们必须找到使这个似然函数最大化的 p 的值。

我们可以很容易地在 R 中用两种不同的方法计算这个概率:

# To illustrate, let's find the likelihood of obtaining these results if p was 0.6—that is, if our coin was biased in such a way to show heads 60% of the time.
biased_prob <- 0.6# Explicit calculation
choose(100,52)*(biased_prob**52)*(1-biased_prob)**48# 0.0214877567069514# Using R's dbinom function (density function for a given binomial distribution)
dbinom(heads,100,biased_prob)# 0.0214877567069514

回到我们的问题——我们想知道我们的数据暗示的 p 的值。对于像正在考虑的这种简单情况,可以对关于被估计参数的似然函数进行微分,并使结果表达式等于零,以求解 p 的最大似然估计。然而,对于更复杂(和现实)的过程,您可能不得不求助于数值方法。

幸运是,这也是一件轻松的事情!我们的方法如下:

  1. 定义一个函数,该函数将计算给定值 p 的似然函数;然后
  2. 搜索产生最高可能性的 p 的值。

从第一步开始:

likelihood <- function(p){
  dbinom(heads, 100, p)
}# Test that our function gives the same result as in our earlier example
likelihood(biased_prob)# 0.0214877567069513

现在考虑第二步。在 R 中有许多不同的优化(即最大化或最小化)函数的方法——我们在这里考虑的一种方法利用了代表非线性最小化的 nlm 函数。如果你给 nlm 一个函数,并指出你希望它改变哪个参数,它将遵循一个算法并迭代工作,直到它找到使函数值最小的那个参数值。

你可能会担心我引入了一个工具来最小化一个函数值,而我们实际上是在寻找最大化——这毕竟是最大似然估计!幸运的是,最大化一个函数相当于最小化这个函数乘以-1。如果我们创建一个新函数,简单地将可能性乘以-1,那么使这个新函数的值最小化的参数将与使我们的原始可能性最大化的参数完全相同。

因此,对我们的职能进行一点小小的调整是合适的:

negative_likelihood <- function(p){
  dbinom(heads, 100, p)*-1
}# Test that our function is behaving as expected
negative_likelihood(biased_prob)# -0.0214877567069513

很好——我们现在准备好找到我们的 p 的 MLE 值。

nlm(negative_likelihood,0.5,stepmax=0.5)# $minimum
# -0.07965256# $estimate
# 0.5199995# $gradient
# -2.775558e-11# $code
# 1# $iterations
# 4

nlm 函数返回了一些关于寻找 p 的最大似然估计的信息。

  • $minimum 表示找到的负可能性的最小值,因此最大可能性就是这个值乘以负一,即 0.07965…;
  • $estimate 是我们对 p 的极大似然估计;
  • $gradient 是我们对 p 的估计值附近的似然函数的梯度——对于成功的估计,我们希望它非常接近于零;
  • $code 解释使用最小化算法终止的原因——值 1 表示最小化可能已经成功;和
  • $iterations 告诉我们 nlm 为获得参数的最佳值而必须经历的迭代次数。

知道这些信息很好——但我们真正关心的是,它告诉我们,我们对 p 的极大似然估计是 0.52。我们可以凭直觉判断这是正确的——在 100 次投掷中,哪个硬币更有可能让我们 52 次正面朝上,而不是 52%的时候正面朝上?

结论

在我们今天看到的这个相当琐碎的例子中,我们似乎已经经历了很多争论才得出一个相当明显的结论。但是,请考虑一个问题,其中您有一个更复杂的分布和多个参数要优化,最大似然估计的问题变得更加困难,幸运的是,我们今天探索的过程可以很好地扩展到这些更复杂的问题。

最终,如果你想建立稳健的模型,你最好很好地掌握最大似然估计——在我看来,你只是朝着最大化你的成功机会又迈进了一步——或者你更愿意认为这是最小化你的失败概率?

学分和更多信息

Andrew Hetherington 是英国伦敦的一名见习精算师和数据爱好者。

  • 查看我的网站
  • LinkedIn 上与我联系。
  • 看看我在 GitHub 上摆弄什么。
  • 用于制作本文作品的笔记本可以在这里找到。

硬币照片由🇨🇭·克劳迪奥·施瓦茨| @purzlbaumUnsplash 上拍摄。

最大似然(ML)与 REML

原文:https://towardsdatascience.com/maximum-likelihood-ml-vs-reml-78cf79bef2cf?source=collection_archive---------3-----------------------

生命科学的数理统计和机器学习

基于限制最大似然的线性混合模型

作者图片

这是来自专栏 生命科学的数理统计和机器学习 的第十九篇文章,我试图以简单的方式解释生物信息学和计算生物学中使用的一些神秘的分析技术。这是致力于线性混合模型(LMM)系列的最后一篇文章。之前我们讲过 线性混合模型如何工作 ,如何从 R 中的最大似然(ML) 原理出发,从零开始推导并编程 线性混合模型 。今天我们将讨论限制最大似然(REML) 的概念,它为什么有用,以及如何将其应用于线性混合模型。

最大似然有偏方差估计量

受限最大似然( REML )的思想来源于认识到最大似然(ML)给出的方差估计量是有偏的。什么是估计量,它以何种方式存在偏差?估计量只是模型参数的近似值/估计值。假设统计观测值服从正态分布,如果要对观测值进行汇总,需要估计两个参数: μ (均值)和 σ (方差)。原来最大似然(ML)给出的方差估计量有偏的,即我们从 ML 模型得到的值高估或者低估了 真实方差,见下图。

有偏与无偏估计量的图解。作者图片

在实践中,当我们例如使用 ML 求解一个线性回归模型时,我们很少考虑方差估计量中的偏差,因为我们通常对线性模型的系数感兴趣,即 平均值,并且经常没有意识到我们并行地估计另一个拟合参数,即方差。在这种情况下,方差被认为是所谓的 干扰参数 ,这不是我们主要关心的。

为了证明 ML 确实给出了有偏方差估计量,考虑一个简单的一维情况,其中变量 y = ( y 1, y 2,…, yN )遵循正态分布。

最大似然,等式。(1),导致均值和方差的估计量,方程。(2)、推导请到我的 github 查看笔记本。为了证明等式中的方差估计量。(2)有偏,我们将推导方差估计量的期望值,并证明它不等于方差的真值,σ 。为此,我们首先重新安排方差估计量,方程。(2)通过将未知的真实均值 μ 显式地包括到等式中:

最后,让我们计算方差估计量的期望值:

这里我们可以看到,ML 方差估计值的期望值不等于真实方差 σ ,尽管它在大样本量时接近真实方差。因此,ML 给出的方差估计量向下偏移,即低估了真实方差。当 N > > 1 时,偏差似乎可以忽略不计,直到我们认识到等式。(8)是针对一维数据获得的。使用高维数据,这是现实世界中的典型问题,我们可以得到方差的严重有偏估计,因为它可以被导出,例如查看精彩的教程这里的,对于 k 维数据,方差估计的期望值采用以下形式:

因此,当维数 k 接近样本数/统计观测值,N 时,ML 低估真实方差的问题变得尤其尖锐。我们得出结论,在高维空间中,最大似然(ML)原理只在极限 k < < N 中起作用,而有偏 结果可以在kN**中得到。这种偏见需要被考虑进去,这正是 REML 发挥作用的地方。

基于 REML 的线性混合模型

ML 的有偏方差估计量的问题似乎是由于我们使用了一个未知的均值估计量来计算方差估计量。相反,如果我们确保对数似然函数不包含任何关于均值的信息,我们可以针对方差分量对其进行优化,并获得一个无偏方差估计量。这就是受限最大似然法(REML)的本质。在这种情况下,平均值(不像 ML 的方差)被认为是一个干扰参数,应该以某种方式从等式中移除。从对数似然函数中去除关于平均值的信息的一种方法是计算一个边际概率,即对平均值上的对数似然进行积分。在之前的帖子 LMM 从零开始 中,我们看到了对于处理高维数据的多元分析,Eq 的扩展。(1)由给出的多元高斯分布:

其中σy是方差-协方差矩阵,它是等式中简单残差方差的推广。(1).这里,我们将对多元高斯分布(对数似然)取对数,并对平均值、β 的对数似然进行积分,得到方差分量的无偏估计值。因此,我们需要计算以下积分:

为此我们将使用鞍点方法( 拉普拉斯近似 )。在这种方法中,由于指数函数在方程的第三项积分下。(9)下降非常快,这足以计算指数、指数 ( f ( β ))中函数 f ( β )的最大值中的积分,这将对指数做出最大贡献,并因此对等式(1)中的积分做出最大贡献。(9),并因此的可能性。通过 f ( β 表示指数中的函数,我们可以在均值估计点附近通过泰勒级数展开来近似它:****

这里线性项为零是因为 极值条件 。这里,我们假设在现实中,真实均值的似然性是最大的,但是估计量离真实均值不远,因此可以执行泰勒级数展开。回到等式的第三项。(9),并且将指数中的函数表示为 f ( β ),围绕均值估计量的泰勒级数展开给出:

其中 |…| 是行列式的符号。等式中的前两项。(12)是我们在 LMM 从无到有 (Eq。(10)在那篇文章中)。相比之下,第三项来自 REML 方法。人们可以把这个额外的项看作是一个惩罚模型** ( 脊/套索/弹性网)中的一个惩罚(或偏差),我们在线性回归(或 LMM)模型中的系数上加了一个约束。让我们来看看这个来自 REML 的附加项如何影响玩具数据集**的线性混合模型(LMM)的解决方案,该模型是在 LMM 从零开始帖子中介绍的。****

LMM 通过 REML 的玩具数据集

为了简单起见,我们只考虑了 4 个数据点: 2 个来自个人#1,另外 2 个来自个人#2。此外,这 4 个点分布在两种情况之间:未治疗和治疗,请参见下图。在处理栏中,0 表示未处理,1 表示已处理。

****

我们使用 LMM 拟合数据,使用 lme4 R 包中的 lmer 函数对斜率和截距进行固定效应,对截距进行随机效应。包括考虑分组因子 Ind (个体 ID)的随机效应截距,我们还需要为 lmer 函数使用特殊的语法 (1 | Ind) 。现在,我们可以使用限制最大似然(REML)** 方法来拟合 LMM 模型,为此,我们指定 REML = TRUE 😗*

请注意共有的剩余标准差8.1556.0 ,我们在上一篇文章中分别表示为 σsσ 。我们将在稍后为 LMM 实施 REML 解决方案时重现这些值。正如我们在之前的LMM _ 从头开始教程中看到的,知道数据点 y11,y12,y21,y22 的坐标,方程中的前两项。(12)可以计算为:

等式中的第三项。(12)也可以从解析导出,因为我们既知道 X设计矩阵,也知道逆方差协方差矩阵σy。下面我们呈现一个来自 Maple 软件的截图,其中显示等式(1)中的第三项。(12)采取的形式:

因此,等式中的第三项。(12)有以下简单的表达式:

因此,我们现在可以在限制最大似然(REML)近似中最小化对数似然函数,即当对数似然等式。(12)函数不包含任何关于平均值 β,的信息,即这不再是优化的参数,而是具有固定/估计值 β 1=6, β 2=15.5,这是之前找到的。现在,一切都准备好执行对数似然函数 Eq 的数值最小化。(12)关于 REML 近似中的 σsσ :

通过对数似然函数的最小化,我们获得了= 6.00【σs】= 8.155,这正是我们通过 lmer 函数以及 REML = TRUE 获得的标准偏差。我们复制了随机效应残差方差 σ ,并在本帖中分享了最大似然(REML =假)受限最大似然(REML =真)的数据点方差 σs* 。而且,我们已经用 R 从头开始推导并编码了它,干得好!***

摘要

在本文中,我们了解到最大似然(ML) 方差估计量是有偏的,特别是对于高维数据,由于使用了未知的均值估计量。限制最大似然(REML)通过在最小化对数似然函数之前首先移除关于均值估计器的所有信息来解决这个问题。我们成功地复制了 lmer 报告的 REML = TRUE 的方差分量,并使用 r 从头推导和编码了 REML。

在下面的评论中,让我知道哪些来自生命科学的分析技术对你来说似乎是 T42 特别神秘的,我会在以后的文章中尽量涉及它们。检查我的 Github 上的帖子中的代码。请在媒体 Nikolay Oskolkov 关注我,在 Twitter @NikolayOskolkov 上关注我,并在 Linkedin 上关注我。在下一篇文章中,我们将讨论如何在 UMAP 空间聚集,敬请关注。**

64 核服务器会比我的笔记本电脑慢 100 倍吗?

原文:https://towardsdatascience.com/may-a-server-with-64-cores-be-100x-slower-than-my-laptop-e648f6e69c0e?source=collection_archive---------41-----------------------

这里没有剧透;-)

很久以前,我在 Twitter 上问是否有人能帮我解决一个令人困惑的问题。我使用的一个工具利用了 scipy 线性代数软件包来执行计算。大部分时间都花在了运行 pinv 函数上,这使得计算逆矩阵。 scipy.linalg 模块中有四个函数可以计算逆矩阵: pinvpinv2pinvh、inv 。前三种使用不同的方法计算伪逆矩阵,最后一种是显式计算逆矩阵,它们产生或多或少相同的结果(一般在舍入误差范围内)。在本地笔记本电脑上的测试表明, pinv 是最慢的实现, pinv2 次之,然后是 pinvh,inv 最快。事实上,它比 pinv 快了 15 倍。这意味着,如果我们在工具的源代码中用 inv 替换 pinv ,我们的代码运行速度也会提高 15 倍!

旁注:如果事先不知道 逆是否存在 ,不建议使用 inv。但是在我们的例子中,它几乎总是存在的,所以 inv 可以用作默认选项,我们仍然可以使用 pinv2 作为后备。

Sidenote 2:如果你正在使用 numpy,那么请注意 numpy 和 scipy 在命名上有不同的约定。numpy pinv 或多或少相当于 scipy pinv2,所以不要与下面 tweet 中的命名混淆。

我们的代码花了 8 个小时在真实世界的数据集上完成。让它在 30 分钟内运行的机会太好了,不能不尝试!但是,意想不到的事情发生了。在本地, inv 是最快的方法,但是在服务器上却非常慢!

其余 3 个伪逆实现的时序符合我们的预期。但是 inv 就是不符合预期:

Twitter 的智慧给了我三个同样好的主意:

对目标进行优化编译很重要,所以 Niko 的建议可能非常真实。阵列的内存布局也非常重要。如果你曾经使用过 numba 来优化你的代码(我曾经使用过),你可能已经体验过,当 numpy 数组在内存中正确定位时,你的代码变得有多快,所以 Moritz 的建议看起来也不错。然而,Petar 的建议很奇怪。我的意思是,它不可能可能是,一个备受尊敬的基于 C 的 BLAS 包会以这样一种方式编写,它会在服务器上失败,可能吗?

我想你已经可以猜到,接下来发生了什么。

重新编译毫无用处。记忆布局也与本案无关。结果是, inv 存在一些并发问题。可以指定,BLAS 可以使用多少个线程。下面是应用于测试数据的 inv 的执行时间,作为线程数量的函数(注意,y 轴是对数):

你可以看到,执行时间是如何下降的,然后突然在大约五个内核之后开始增长。更有趣的是,随着越来越多的内核被使用,执行时间呈指数增长。

因此,我们的解决方案是限制内核数量,让代码运行得更快

奇怪的是,并非所有的数学函数都是如此!虽然 inv 已经减速,但 np.dot 的表现与预期一致。当提供更多内核时, np.dot 的执行时间变得更短,直到在 10-15 个内核左右达到饱和:

最后,作为折衷,我们将代码中使用的内核数量限制为 6 个。在我们的代码中,第二耗时的函数 np.dot 在使用六个内核时已经足够快了。对于 scipy inv,这是最佳解决方案。

我们实现了 15 倍的速度提升吗?不幸的是,没有。 pinv 实际上并没有占用所有的代码执行时间,而且还有其他部分没有受到这个变化的影响。但是我们仍然通过替换代码中的两个字符来节省几个小时的执行时间。要是一直这么简单就好了。

结论

  • 使用 profiler 测量您的代码和您正在使用的包的代码的执行时间。
  • 试着找到一行或一个函数,它至少需要 10-20%的运行时间。
  • 如果你能加快速度。
  • 为不可预见的后果做准备拥抱它们,并把它们作为学习新东西的机会
  • 总是在生产环境中测试你的代码。

— —

Twitter(siberianpython)上连接以获取更多技术主题和帖子,或者在 LinkedIn 上连接。

五月版:用数据改变世界

原文:https://towardsdatascience.com/may-edition-changing-the-world-with-data-ddb6fda47fc2?source=collection_archive---------51-----------------------

社区的力量

照片由像素皮克斯拜拍摄

无论你是谁,无论你在世界的哪个角落,这个月你的生活可能会和你想象的有所不同。

我们社区的一些人失业了。你们中的一些人已经削减了工作时间和工资。你们中的许多人已经开始在一些非常具有挑战性的环境中远程工作。我们正经历着经济和情感上的困难以及巨大的损失。我们工作、购物、社交、为人父母和生活的方式几乎在一夜之间发生了变化。我们的想法和希望与你们所有人同在。

但没变的是我们的社区。

我们团结起来让世界变得更美好的愿望没有改变。从这次疫情的第一时间起,全球的数据专业人员就开始合作寻找应对这种不可预测情况的解决方案。当事情看起来最黑暗的时候,人们开始积累、分享和分析我们仅有的一点信息。这个社区不知疲倦地收集更多的数据,并为分析、理解和预测做准备。我们采用了新的方法,创造了新的合作方式。

我们从未见过如此多的数据科学家、分析师、工程师和程序员如此无私地聚集在一起,分享知识、汇集资源,并致力于发现我们作为一个全球社区所需要的解决方案。我们在提问,我们在寻找答案,我们在不知疲倦地保护我们的隐私,同时维护我们的道德规范。

在这个社会距离的时代,我们在一起真的更好。

我们在数据科学公司从未如此自豪地与你们站在一起。

谢谢你。

保持健康!

《走向数据科学》的编辑安妮·邦纳。

“在人类(以及动物)漫长的历史中,那些学会最有效地合作和随机应变的人一直占据上风。”

~查尔斯·达尔文

危机时刻的合作

由凯伦·霍奇森 — 6 分钟读完

分享你在新冠肺炎分析工作的简单方法。

数据是如何与新冠肺炎交织在一起的!

作者卡兰·巴诺特 — 6 分钟阅读

数据、仪表板和下一步行动

各个国家的医疗保健能力是什么样的?

JP Hwang — 8 分钟读取

鉴于冠状病毒(新冠肺炎),按国家可视化和比较医疗保健数据和指标。

更聪明的新冠肺炎决策

凯西·科济尔科夫 — 10 分钟阅读

如何将决策科学的合理原则应用到自己的生活中

冠状病毒:疾病背后的数据🎧

由杰瑞米·哈里斯 — 3 分钟阅读

TDS 播客上的杰瑞米·霍华德

如何用 Python 追踪贵国的冠状病毒

耶戈·古格莱塔 — 6 分钟读完

随着大规模爆发和消息传播速度超过冠状病毒(新冠肺炎)本身,我们必须了解影响我们生活地区的实际统计数据。

群体免疫的数据科学观点,我们要付出什么才能阻止病毒?

凯瑟琳王 — 11 分钟读完

从数据科学家的角度看新冠肺炎疫情,没有废话,没有指责,没有政治化。

避免解读新冠肺炎统计数据常见陷阱的简短指南

通过 Imad Riachi — 8 分钟阅读

在与朋友分享下一个统计数据之前,你可能需要考虑的 8 个要点

新视频

新播客

我们也感谢最近加入我们的所有伟大的新作家基里安·法特拉斯西达尔特·夏尔马史蒂夫·科斯滕米基安·穆塞尔泰勒·彼得森米里阿姆·巴恩斯巴斯卡尔·阿加瓦尔安吉莉卡·洛·杜卡弗洛伦特·普克斯博士 阿尔文万多洛塔米尔泽瓦克里斯托夫施密德尔古伊列梅科斯塔亚历山大西多罗夫等等很多人。 我们邀请你看看他们的简介,看看他们的工作。

请大家注意一下。

原文:https://towardsdatascience.com/may-i-have-your-attention-please-9c03de3c1933?source=collection_archive---------50-----------------------

什么、为什么以及如何在营销中使用人工智能

我怎样才能引起你的注意?你信息超载了,对吧?速度和噪音是定义我们当今世界的两个特征,这使得我越来越难引起你的注意。

社交网络,饱和的新闻,一些虚假的,其他的没那么多,电子邮件,信息……所有这些不断地消耗着我们。尽管如此,公司能够与我们交流并抓住我们的一小部分注意力,你不觉得这很神奇吗?

让我们来谈谈营销中的 人工智能 作为一种使能器来识别潜在的线索、超个性化的报价和沟通,以及根据客户的年龄、个人情况或偏好等属性来调整公司活动中包含的每条消息中使用的文本和语言。

约书亚·厄尔Unsplash 上拍摄的照片

如果你想了解更多,请访问oscargarciaramos.com

你听说过聚类客户细分吗?如何主动识别常见的消费模式?典型的,对吗?

右频道右时间投放的右广告,带右信息和报价,聚焦右观众

然而,公司在广告上花了多少钱?

他们能通过 AI 优化广告支出吗?

我们想知道什么? 广告商应该在他们的每一次广告活动上花多少钱。

换句话说,我们要确定最佳成本时机手段来开展广告活动。

如今,人工智能系统可以帮助我们识别渠道、信息,甚至调整我们每个广告活动的广告投资计划,分析它们的表现,并持续监控不同的传播渠道。不仅如此……多亏了人工智能,我们不仅可以跟踪广告客户活动的表现,还可以跟踪他们的竞争。

就是我们所说的 【情境感知】 。随着市场的发展和不断改变其模式,基于人工智能的系统可以通过改变广告内容和传播渠道来调整广告支出。

有一种叫做 MMM(营销组合建模) 的技术可以让我们量化不同营销投入对销售或市场份额的影响。由于 MMM,我们能够知道这些变量或营销投入在销售中的贡献,以及我们必须投入其中的每一项的估计投资是多少。

这种技术尤其基于 ML & AI 算法,如多元线性回归。我们的因变量可能是销售额或市场份额,而我们的自变量可能是分销、定价、纸质广告支出、电视支出、网站访客或促销支出等。

这些变量中有一部分并不一定与销售额成线性关系,比如 TVspending,也就是说,它们并不与销售额的增长成正比(它们是非线性的)。为什么?一则广告会在受众中产生一定程度的认知度,从这一点开始,更多的曝光不会产生更大的认知度,因为受众已经对品牌有了足够的了解。

我们还必须考虑销售额。在 MMM,销售必须分为两部分:基础销售,或者说我们在不做任何广告的情况下将获得的东西;以及增量盐,由营销活动产生。

现在,我们把广告放在哪里?

这对于一个人来说可能很难知道。然而,由于人工智能,我们可以扫描成千上万个页面的内容,根据哪个频道和哪个受众消费了那个页面来确定哪个广告是最合适的。

让我们深入到…的世界吧

商业广告的创作。

广告的完美内容是什么?人工智能可以指导我们创作内容以提高响应率吗?

基于从结构化数据创建文本,有各种不同的技术,如【NLG(自然语言生成)】 等公司使用的技术。这种类型的技术将允许我们创建标准化格式的分析报告、博客和产品描述。

我们可以用 PR 20/20 找到一个明显的例子,这是营销人工智能研究所背后的营销机构,由于 NLG,它将报告的时间和制作减少了 80%。

Textio 这样的公司正在帮助 Twitter、P & G、Slack 或 Nestle 这样的公司创建“增强写作”,避免在创建工作岗位等内容时可能不合适的性别偏见或行话。

不仅如此,人工智能还帮助我们显著减少了欺诈性广告的数量。2018 年,它们比上一年翻了一番。

为明年 11 月的美国大选做准备!

那么,接下来呢?

虽然我们可能不欣赏或者没有意识到,但是 AI 正在改变广告的世界 。让我们把它看作一个巨大的竞争优势:

让我们用更相关、更有效的广告来减少挫败感。

如果我们这样做,我们将改善媒体支出策略和决策能力,这将意味着我们客户销售额的增加。

欢迎发表评论或分享这篇文章。跟随 me 进行未来岗位。

如果你想了解更多,你可以在oscargarciaramos.com找到我

也许是时候升级你的终端体验了

原文:https://towardsdatascience.com/maybe-its-time-to-upgrade-your-terminal-experience-a9e12b2af77?source=collection_archive---------30-----------------------

学习机

默认的 MacOS 终端不适合你,也不适合任何人

安东尼·加兰德在 Unsplash上的照片

你买过床垫吗?

让我告诉你我与臭名昭著的床垫推销员打交道的经历。

推销员会说服你买一些你并不真正需要的东西,或者你确实需要的更贵的东西。

就我个人而言,我喜欢安静地购物。这意味着我不希望在我浏览的时候有售货员跟着我。然而,几乎不可能找到一家没有销售人员的床垫商店。

一旦你听到一个推销词,你就会意识到所有的都是完全一样的。几乎就像你反复看的电影剧本。

“我们的床对你的脊椎有好处。”

想想如果你睡在劣质床垫上,你以后会有多少医疗账单

“如果你不能享受金钱,那么拥有金钱又有什么意义呢?”

不过,在某一点上,其中一个投球很突出。

“你每天花多少时间坐在车里?两个小时?你的车多少钱?同样,你每天在床上花多少时间?”

然后他展示了一个价值 5000 美元的床垫。

不过,我不是来告诉你买一个 5000 美元的床垫的。

我从那个推销中学到的是,你应该更加关注你在日常生活中实际使用的东西。

如果你是软件工程师、机器学习工程师或数据科学家,很有可能:

  1. 你用苹果电脑
  2. 你大部分时间都在使用终端

我相信,改善您日常使用的整个终端体验是一项很好的投资,从长远来看是值得的。

话虽如此,你还在用默认的 MacOS 终端吗?

终点站

有很多流行的终端替代品。我尝试过其中的一些,下面是我会推荐给朋友们的。

iTerm2

迄今为止 MacOS 终端最强大的替代品。

iTerm2(图片由作者提供)

乍一看,它与默认终端非常相似。但是,它具有许多终端和其他终端替代品所不具备的功能。

在我看来,最突出的一个特征是侧面。

作为一名开发人员,大部分时间你将访问远程服务器来使用它们。每台服务器都有唯一的 IP 地址,你不想记住每台服务器的 IP 地址。

您可以在 ssh 配置文件~/.ssh/config中创建一个条目,如下所示:

Host work_server
    HostName <IP address>
    User <username>

然后,你可以简单地输入ssh work_server,而不是一遍又一遍地手工输入 IP 地址。

在 iTerm2 中,您可以为每台机器创建一个概要文件。下面是 ssh 到服务器的简单配置文件的设置。

iTerm2 配置文件设置(图片由作者提供)

之后,您只需从下拉菜单中选择配置文件,打开一个新的终端选项卡,您已经通过 ssh 连接到该机器。

这只是我如何使用配置文件的一个用例,这个特性还有很多其他的用例。

你为每个项目使用不同的 conda 环境吗?创建一个概要文件来直接打开项目的工作目录并运行命令conda activate environment来节省您的时间。

有一点需要注意,如果您没有使用 ssh 的概要文件,您需要将命令改为 Login Shell,然后在Send text at start字段添加命令。您也可以通过用;分隔来运行多个命令

对于默认的启动目录,你可以把cd /path/to/workdir放在Send text at start里面或者在Directory部分指定。

想让你的流量更快吗?使用热键指定快捷键来打开配置文件,如⌘^A.

超级

您喜欢开箱即用的漂亮终端吗?这可能是适合你的。

超级(作者图片)

Hyper 是 MacOS 最好看的终端替代品,使用 HTML、CSS 和 JS 构建。

Hyper 区别于其他终端的一个显著特征是它的插件。它有大量专为 Hyper 定制的插件。这里有一个名为 awesome-hyper

你可以很容易地安装插件,甚至通过编辑~/.hyper.js配置文件来改变主题或配色方案。

有很多有趣的插件,比如hypergoogle可以让你直接通过 Hyper 搜索谷歌。它会打开一个新的浏览器窗口,所以你不用担心在终端里浏览网页。hyper-spotify将在终端顶部或底部显示 Spotify 上当前播放的歌曲,并让您控制它,这对于不想一直呆在终端中的开发人员来说是完美的。

不幸的是,Hyper 没有 iTerm2 那样的 Profiles 特性。这是一个非常好且功能强大的终端,但是配置文件的便利性不断将我拉回 iTerm2。

优秀奖:

Alacritty 为自己是“现存最快的终端模拟器”而自豪。秘密?他们使用 GPU 来启动终端,与其他终端相比,这使得渲染速度非常快。

坏处呢?它消耗很多能量。

如果你总是在办公桌前工作,并且你的机器总是与充电线相连,那么它可能看起来没有那么糟糕。另一方面,如果你有时在舒适的沙发上工作,一旦你的笔记本电脑底部变热,电池需要更频繁地充电,你就会很快变得不舒服。

最重要的是,Alacritty 也不支持像 iTerm2 这样的概要文件,所以它不适合我。

不过这取决于你的主要关注点。如果你是所有关于速度和电池消耗不是一个问题,那么无论如何,这是一个给你的。

定制您的终端

既然您已经选择了终端,是时候开始定制它们了。

无论你选择哪种终端,定制都应该适用于任何一种终端,即使你决定使用与上面列出的完全不同的终端。

这里有一个我用来安装家酿、zsh、oh-my-zsh 和 powerlevel10k 的快速脚本。

安装 homebrew、zsh、oh-my-zsh 和 powerlevel10k 的自动脚本

复制命令并逐行执行是可以的,因为只有几行。

您还可以将内容复制并保存到一个名为terminal_upgrade.sh的文件中,然后在目录中打开终端cd,并使用该命令授予执行权限。

*chmod +x terminal_upgrade.sh*

之后,执行这个命令来运行脚本。

*./terminal_upgrade.sh*

请注意,它不能自动安装 powerlevel10k 主题,请阅读 Powerlevel10k 部分以获得进一步的说明。

我将在下面的章节中详细介绍每一项。

公司自产自用

*/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"*

自制软件对于任何使用 MacOS 的开发者来说都是必不可少的。它是一个软件包管理器,允许你直接从终端安装很多东西。

几乎所有的主流软件包都可以通过自制软件安装,而且你可以通过安装自制的木桶来安装更多的东西。

*brew install cask*

甚至你可以通过家酿啤酒桶安装 iTerm2。

*brew cask install iterm2*

简而言之,这是一个必须拥有的包管理器,就像 Linux 中的apt

zsh

*brew install zsh zsh-completions*

如果 iTerm2 是 Terminal 的替代品,那么 zsh 就是 bash 的替代品。

Z shell 的简称,它构建在 sh (Bourne Shell)之上,就像它的对应物 bash (Bourne Again Shell)一样。

它有一些小的改进,比如不需要输入cd来浏览文档。

我很少使用这个特性,因为不是所有的终端都使用 zsh,所以使用cd是一个很好的实践,即使你知道 zsh 不需要它。

然而,您应该使用 zsh 的主要原因是因为 oh-my-zsh。

哦我的 zsh

*sh -c “$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"*

Oh-my-zsh 是 zsh 的一个框架,它使得为 zsh 安装和管理插件变得更加容易。

就像 Hyper 的插件一样,oh-my-zsh 的插件是在一个文件中定义的。在本例中,它是~/.zshrc文件。

需要注意的一点是,这是一个与 Hyper 完全不同的插件管理器。Hyper 和 oh-my-zsh 都可以使用,只要记住 Hyper 的插件在~/.Hyper.js中定义,oh-my-zsh 的插件在~/.zshrc

这是 oh-my-zsh 的著名插件列表,以及 oh-my-zsh 的主题列表

要安装你想要的插件,只需把它放在 oh-my-zsh 配置文件的plugins=()行中。

对于主题,您可以在指定行ZSH_THEME=...中指定您想要使用的主题,这将我们带到最后一点。

功率级 10k

*cd $ZSH_CUSTOM/themesgit clone [https://github.com/romkatv/powerlevel10k.git](https://github.com/romkatv/powerlevel10k.git) --depth 1*

Powerlevel10k 是其前身(Powerlevel9k)的更快版本,并包含更多功能。

简而言之,这是我的终端主题。

在运行脚本在$ZSH_CUSTOM/themes目录中克隆 Powerlevel10k 之后,您需要编辑~/.zshrc中定义ZSH_THEME的代码行,如下所示。

*ZSH_THEME=powerlevel10k/powerlevel10k*

通过执行以下命令,重新加载 zsh 以使更改生效

*source ~/.zshrc*

它应该会启动 Powerlevel10k 配置向导。如果没有运行p10k configure来手动启动向导,并按照屏幕上的指示选择您想要的终端外观。

如果你的 oh-my-zsh 中有很多插件,当你第一次打开终端时,可能需要一段时间来加载插件。Powerlevel10k 有即时提示功能,让你在后台加载插件的同时开始使用终端。

恭喜

你现在正式成为增强型 MacOS 终端俱乐部的成员。你盯着平庸的期末会议的日子已经一去不复返了。

如果你安装了上面列出的所有东西,你的终端应该是这样的。

最终结果(图片由作者提供)

如果您在 Powerlevel10k 中选择不同的定制选项,看起来可能会有所不同,但总体而言是相似的。就我个人而言,我喜欢它显示活跃的 Conda 环境和存储库的活跃分支的方式。

仅仅拥有一个漂亮的终端不会让你成为一个更好的程序员,但它肯定会帮助你成为一名程序员。这是我的另一篇文章,可以帮助你掌握终端。

* [## 每个机器学习工程师都应该掌握的工具

你每天都在使用它,没有注意。

medium.com](https://medium.com/swlh/the-one-tool-that-every-machine-learning-engineer-should-master-68aecd920b0)

它展示了如何轻松地在终端内部链接程序,创建自己的自定义命令,以及一些您可能使用过也可能没有使用过的有用命令。

最后要注意的是,定制你的终端没有错。这是你的终端,不是别人的。

我上面列出的一切都是我从开始数据科学家的职业生涯以来,一直对自己的终端做的事情。你的需求可能和我的不同,这完全没问题。

你如何定制你的终端并不重要,但我希望它能让你意识到默认的 MacOS 终端有多糟糕。

你知道罗宾·夏尔马说过,“拥有你的终端。提升你的生活"还是别的什么?*

《学习机》是一系列关于我所学到的东西的故事,我认为这些故事很有趣,值得分享。有时也是关于机器学习的基础。 获得定期更新 上新故事和 成为中等会员 阅读无限故事。

* [## 成为媒体成员—里奥纳尔迪·钱德拉塞塔

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事

chandraseta.medium.com](https://chandraseta.medium.com/membership)*

使用朴素强化学习的迷宫求解器

原文:https://towardsdatascience.com/maze-rl-d035f9ccdc63?source=collection_archive---------15-----------------------

这是一个简短的迷宫求解游戏,我使用 numpy 和 opencv 用 python 从头开始写的(不到 260 行)。代码链接包含在最后。

箭头显示学习到的策略随着训练而改进。假设一个代理从任何地方开始,它应该能够跟随从它的位置的箭头,这应该引导它到最近的目的地街区。

我写这篇文章是为了理解 Q-Learning 的基本原理,并从头开始在代码中直接应用理论概念。如果你想用强化学习弄脏你的手,就跟着来吧!

游戏目标-

找到最佳移动策略,该策略将代理从任何起点(显示在左边的黑灰色阴影中)移动到最近的目的地 (蓝色左右)箱子,同时避开危险区域(红色)墙壁(绿色)箱子。

一个“策略”可以被认为是一组“智能运动”规则,代理学习如何在它的环境中导航。在这种情况下,它们被可视化为箭头(如左侧所示)。这是通过 Q-Learning 完成的。

意义-

你可能会问,制作这样的游戏人工智能在实际应用中是否有意义,这是公平的。实际上,这些都是玩具问题,它们的解决方案被设计成具有广泛的适用性。

例如,当前的迷宫求解示例可以进一步扩展为占用网格中的自主导航,以到达最近的电动汽车充电站。

Q 学习算法和 Q 表方法-

Q-Learning 以贝尔曼方程为中心,寻找当前状态下每个动作的 q 值。寻找最优策略需要多次递归求解这个方程。

贝尔曼方程。这可以递归求解,以获得给定代理当前状态的不同动作的“Q 值”或“质量值”。

本文中将只解释与该实现相关的贝尔曼方程的主要部分。关于贝尔曼方程的更深入的基础知识,请查阅参考文献[1]。

什么是 Q 值?

想象你是一个不幸的人,被困在一个简单的 2D 世界里,就像下面这样-

对,就是你。你很难过。橙色箭头指示您可以在这个 2D 世界中进行的置换。

你看起来很悲伤。你应该害怕。谁愿意生活在 2D 的世界里呢?

嗯……让我们笑一笑,好吗?🎃

考虑到你唯一能做的移动就是左边图片中的橙色箭头(和一个无操作操作),你必须找到去最近出口的路。

考虑到这些条件,在任何给定的阶段,你都必须对这些行动中的一个做出决定。为了做到这一点,你的大脑会考虑很多因素,对行动进行内部“排序”。这可能包括像-

  • 最近的出口在哪里?
  • 有危险区域吗?
  • 博伊的 dem 墙在哪里?
  • 这里为什么变热了?(我们将通过讨论每次代理什么都不做时增加小额奖励来达到这个目的)

现在你是一个高级人,隐式地处理这些,并为你在该点可以采取的每个动作(上、下、左、右、无操作)分配一个质量值或一个 Q 值

但是你怎么能让计算机做到呢?

简单来说,你以某种方式给你可能遇到的每种情况下的每个动作分配一个数字 q 值。然而,这是幼稚的方法;如标题所述,我们将坚持这一点。对于更高级的东西,有大量的其他文章,你应该看看。

就像我们人类如何基于现实生活经验形成对“好”和“坏”行为的感知一样,代理人必须以类似的方式接受训练。

现在,这给我们带来了下面的问题-

什么是 Q 表?

简单地说,这是对经验的记忆——比方说,每次你必须在环境中做出决定和采取行动时,你都要更新和查询。

你与 Q-table 关系的准确可视化表示显示在左侧。

现在,为了建立 Q 表,你需要收集关于这个世界的信息。它需要知道危险区域,它可能会撞到的墙壁,以及几乎所有能帮助你不至于很快死去的东西(就像生命本身一样)。

为了做到这一点,让我们假设你可以死一千次。是的,牺牲对于科学是必要的。

有了这个,你将从随机地点开始,开始随机漫游,直到你开始形成对周围世界的感知。这种看法是由你四处漫游时所遇到的事情形成的。

你想避免痛苦。从这个意义上来说,在某些情况下的行为会带来-ve 回报。因此,无论何时你遇到他们,你都要在 Q 表中“记下他们”。

例如,你可能会撞上一堵墙——这很糟糕,因为你在流血。现在你要记住,在那种情况下,无论你做了什么让你流血的事,都不应该重复。

有时,你甚至会遇到大火肆虐的危险地带🔥🧨,只要你一踩上去,它就会结束你的生命。这比流血更糟糕,这将通过为这种经历分配一个更有价值的奖励值来量化。

现在为了生活中更好的事情。

同样,你也将记录下在迷宫中发生的所有好的事情(当你收到+ve 奖励时)。嗯,在这种情况下,只有一件好事会发生-E S C A P E

这听起来像是另一种死法,但是让我们假装它更有趣,因为它听起来和死亡不一样。

为了做到这一切,您将基本上构建一个表,存储在环境中的每个可能场景中执行每个动作的 q 值(请记住,这是有原因的天真的)。

在给定状态下,给定操作的 q 值越高,意味着您(代理)采取该操作的可能性越大。

下面显示了两种不同的状态,以及您(代理)在这些状态下可以执行的每个操作的示例 q 值

在每种状态下,代理都位于棋盘世界中的方框区域。对于每个状态,右边显示的是代理可以采取的不同动作(从上到下分别为向上、向左、向右、向下、无操作)以及从 Q 表中导出的 Q 值。

然后,q 值作为采取下一步行动的指南,以最大化整体回报(这意味着逃避)。在此天真场景中,每一步都将依次执行以下操作-

  1. 查询 Q-table,获取与您在当前状态下可以执行的不同操作相关的值。
  2. 采取与最高 q 值相关的措施。
  3. 记录新的状态和收到的奖励,并使用贝尔曼公式更新 Q 表。我们很快就会到这里。
  4. 转到步骤 1。

学习可视化

最终学习到的在迷宫世界中可视化呈现的 Q 表。它是使用 numpy 在代码库中从头开始实现的。

给定定义的所有状态转换规则(在这种情况下,给定迷宫世界的基本性质,这是非常简单的),在足够次数的重复这些迭代之后,代理根据应该在迷宫的每个位置执行的不同动作构建“矢量场图”,以便在最短时间内到达最近的目的地。

左边显示的是 Q 表的最终学习表示。

通过获得每个位置的不同 q 值的矢量和来可视化箭头。例如,如果我们有以下上、左、右、下的 q 值— qu,ql,qr,qd

然后,箭头在 2D 平面(水平为 X 轴,垂直为 Y 轴)上将使其 x 分量qr-qly 分量qd-qu

箭头的长度是这个向量的范数,用下面的公式得到

因此,如果你从迷宫中的任何一个地方开始,你都可以沿着箭头方向,避开墙壁和危险区域,到达最近的目的地。

探索迷宫时更新 Q 表-

这是问题中更具挑战性的部分之一,它极大地影响了你多快能得到甜蜜的释放(这不是死亡,让我们记住这一点,哈哈)。

基本上,这是一个问题—

你在给定的状态下采取最高 q 值的行动,随后,你在一个新的状态中结束(让我们希望简单,你现在不会死)。

接下来,您需要在 Q 表中记录您的行动是否让您更接近最近的目的地。你怎么能这样做?

你在这里要做的就是-

  1. 为每个动作定义的新旧状态下的现有 q 值。它们可能已经被随机初始化或者从先前的迭代中获得。
  2. 从旧状态进入新状态所获得的奖励。
  3. 您为从旧状态进入新状态而执行的操作。

H 如果将来遇到旧状态,您会如何更改您获得的现有 Q 表值以做出更好的决策?

这是非常基本的问题,在这种情况下由贝尔曼方程回答-

贝尔曼方程。这可以递归求解,以获得给定代理当前状态的不同动作的“Q 值”或“质量值”。

以下是变量定义-

  • 一个就是动作。
  • ss’分别是旧状态和新状态。
  • 𝛾贴现因子,一个介于 0 和 1 之间的常数。你需要这个来优先考虑当前的回报,而不是预期的未来回报。
  • Q(s) 是你刚刚采取的从旧状态 s 到达新状态的动作 a 的 Q 值。
  • Q(s’)是新状态s’下的最大 Q 值。
  • R(s,a) 是你执行 as 过渡到s’立即获得的奖励。

最大术语是这里的秘方。这使得方程迭代通过每一个 a ,直到获得 max 项中表达式的最大值。它最终返回那个值 q 和相应的动作 a

从状态 s 执行的每个动作 a 都可能导致每次迭代的新状态s’。因此,每次都选择在s’处定义的 q 值的最大值来计算 max 内的表达式。

一旦获得了值 Q 和 a ,则在状态 s 下为动作 a 定义的 Q 表值将被 q 覆盖。

在我们的例子中,这个表示是值函数(如果您没有得到这个,请不要担心;好吧,我刚刚在你身上拉了个吴恩达😈)

在迷宫中运行代理-

你终于成功了,恭喜你!下面是我的 meme page @ml.exe 给你的独家 RL meme,你值得拥有 bud。

别担心,健康的自恋不会要你的命。

经过足够次数的贝尔曼方程迭代后,你会收敛到每个状态下每个动作的最佳 q 值。

当您想要运行代理时,只需从任意一个种子点开始,盲目地执行具有最高 q 值的动作。你会到达最近的目的地。

然而,要做到这一点,有一些注意事项

奖励政策应该精心设计。这意味着应该为每个状态下的每个行为分配正确的奖励值。由于这种情况非常简单,所以像下面这样的简单方案效果很好-

  • discount_factor = 0.5
  • default_reward = -0.5
  • wall_penalty = -0.6
  • win_reward = 5.0
  • lose_reward = -10.0

默认 _ 奖励是什么都不做而获得的奖励。还记得我们在本文开头问自己的一个基本问题吗?”;嗯,在这里。分配一个小的负面奖励鼓励代理人寻求行动来结束它的痛苦,而不是像一块肥胖的猪油一样无所事事。

wall_penalty 是从你现在的状态做动作时撞到墙得到的奖励。每当你撞上一堵墙,你就停留在原来的位置,同时获得这个“奖励”🤣。

赢 _ 奖励输 _ 奖励不言自明。

如果你进入了任何一个危险区域,你就输了一局。在死亡时,你在格子上随机选择的位置重生。

在代码库中,您可以尝试奖励,看看它如何影响解决方案的收敛。

结论

如果您正确理解了本文中引用的步骤,您将能够完全理解我为实现所有这些而从头编写的代码库。你可以在这里找到它-

[## ironhide23586/naive-dqn-maze

迷宫求解器使用朴素强化学习和 Q 表构造这是 Q 学习的一个实现…

github.com](https://github.com/ironhide23586/naive-dqn-maze)

代码写出了代理培训和学习的视频,如下面的 YouTube 视频所示。你可以创造复杂多变的随机世界。

如果您觉得这很有帮助,请随时关注我,获取更多即将发布的文章:)

我是以下出版物的编辑,该出版物发表了与 AI & ML 在地球数字地图绘制中的使用相关的技术文章。请随时关注以保持更新:)

[## 数字制图中的机器学习和人工智能

策划尖端人工智能和人工智能研究文章,来自从事设备、边缘、云和混合领域工作的行业科学家…

medium.com](https://medium.com/ai-ml-cv-in-enriching-digital-maps-navigation)

参考文献-

  1. https://medium . com/analytics-vid hya/bellman-equation-and-dynamic-programming-773 ce 67 fc 6a 7
  2. https://www.instagram.com/ml.exe
  3. https://github.com/ironhide23586
  4. https://www.youtube.com/user/mick23586

临时演员-

谢谢:)

MC 控制和时间差分方法

原文:https://towardsdatascience.com/mc-control-methods-50c018271553?source=collection_archive---------22-----------------------

深度强化学习讲解— 14

常数- α MC 控制,Sarsa,Q 学习

在这个深度强化学习解释系列的新帖子中,我们将改进蒙特卡罗控制方法来估计上一个帖子中提出的最优策略。在之前的蒙特卡罗控制算法中,我们收集了大量片段来构建 Q 表。然后,在 Q 表中的值收敛之后,我们使用该表来提出改进的策略。**

然而,蒙特卡罗预测方法可以一集接一集地逐步实现,这就是我们在本文中要做的。即使在 Q 表中的值准确地逼近动作值函数之前更新了策略,这种较低质量的估计仍然具有足够的信息来帮助提出连续更好的策略。

此外,可以在每个时间步更新 Q 表** ,而不是使用时间差方法等到剧集结束。我们也将在本帖中回顾它们。**

本出版物的西班牙语版本

** [## 6.优化政策委员会

访问第 6 页的自由介绍

medium.com](https://medium.com/aprendizaje-por-refuerzo/6-obtención-de-políticas-óptimas-87267b32df00)

蒙特卡洛控制的改进

之前的帖子中,我们已经介绍了蒙特卡罗控制算法如何收集大量剧集来构建 Q 表(策略评估步骤)。然后,一旦 q-表非常接近动作-值函数 ,算法就使用该表来提出改进的策略t27】ππϵ-相对于 q-表(表示为【ϵ-greedy(q】)而言是贪婪的,这将产生比原始策略 π 更好的策略

也许在每集之后更新 Q 表会更有效率?是的,我们可以修改政策评估步骤,在每次互动后更新 Q 表。然后,更新的 Q 表可以用于改进策略。然后,新策略可用于生成下一集,以此类推:

恒定αMC 控制算法

在每一集之后更新策略(而不是等到 Q 表的值从许多集完全收敛之后才更新策略)的 MC 控制算法的最流行变体是常数αMC 控制。

恒αMC 控制

在 MC 控制的这个变体中,在策略评估步骤期间,代理收集一集

使用最近的策略 π 。当情节在时间步 T 中结束后,对于每个时间步 t ,相应的状态-动作对 (St,At) 使用以下更新等式进行修改:

其中 Gt 是在时间步 t 的返回,而 Q(St,At) 是对应于状态 St 和动作的 Q 表中的条目。

一般来说,这个更新等式背后的基本思想是,Q-table 的 Q ( St ,处的)元素包含如果环境处于状态 St 并且代理在处选择动作时代理对预期回报的估计。然后,如果回报 Gt 不等于包含在 Q(St,At ) 中的预期回报,我们“推送”Q(St,At ) 的值,使其与回报 Gt 稍微一致一些。我们对 Q(St,At ) 的改变幅度由超参数 α 控制,该超参数充当更新步骤的步长

我们应该始终将 α 的值设置为大于零且小于(或等于)一的数字。在最外层的情况下:

  • 如果 α =0,则动作值函数估计永远不会被代理更新。
  • 如果 α =1,那么每个状态-动作对的最终估计值总是等于代理经历的最后一次返回。

ε贪婪策略

之前的帖子中,我们提出,当我们的 Q 表近似不好时,随机行为在训练开始时更好,因为它为我们提供了关于环境状态的更均匀分布的信息。然而,随着我们训练的进行,随机行为变得低效,我们希望使用我们的 Q 表近似来决定如何行动。为此,我们在之前的文章中介绍了ε贪婪策略,这是一种混合了两种极端行为的方法,使用概率超参数 ϵ 在随机策略和 q 策略之间切换。通过改变 ϵ ,我们可以选择随机动作的比率。

我们将定义策略是ϵ-贪婪关于动作值函数估计 Q 如果对于每个状态,

  • 在概率为 1-ϵ的情况下,代理人选择贪婪行为,并且
  • 利用概率 ϵ ,代理从可用(非贪婪和贪婪)动作集合中随机一致地选择一个动作

所以ϵ越大,你就越有可能选择一个不贪婪的行为。

为了构造一个策略 π ,即ϵ-相对于当前动作值函数估计 Q 是贪婪的,数学上我们将设置策略为

如果动作 a 最大化 Q ( sa )。其他

对于每个 s ∈S 和 a ∈A( s )。

在这个等式中,因为所有概率的总和需要为 1,所以包含了最优行动的额外项ϵ/∣a(s)∣(∣a(s)∣是可能行动的数量)。请注意,如果我们对执行所有非最优行动的概率求和,我们将得到(∣A(s)∣−1)×ϵ/∣A(s)∣,并将其加到 1-ϵ+ϵ/∣a(s)∣,最优行动的概率,总和为 1。

设置ε的值

请记住,为了保证 MC 控制收敛到最优策略π∑,我们需要确保条件贪婪于无限探索的极限(在之前的帖子中介绍过)确保代理继续探索所有时间步长,并且代理逐渐探索更多和探索更少。我们提出了满足这些条件的一种方法是修改 ϵ 的值,当指定一个 ϵ 贪婪策略时,使其逐渐衰减。

通常的做法是从 ϵ = 1.0 (100%随机动作)开始,然后慢慢减小到某个小值 ϵ > 0(在我们的例子中我们将使用 ϵ = 0.05)。通常,这可以通过引入值接近 1 的因子 ϵ-decay 来获得,该因子在每次迭代中乘以ϵ。

伪代码

我们可以用这个用于常数- α MC 控制算法的伪代码来总结前面所有的解释,它将指导我们实现该算法:

一个简单的 MC 控制实现

在这一节中,我们将按照上一篇文章中介绍的伪代码编写一个 constant-𝛼 MC 控制的实现,它可以帮助代理恢复 21 点环境中的最优策略。

本帖的 全部代码可以在 GitHub*上找到,使用此链接 可以作为一个 Colab 谷歌笔记本运行。*

21 点环境下的 MC 控制算法

在之前的帖子中,我们实施了一个策略,如果玩家的纸牌总数超过 21 点环境中的 18 张,那么这个玩家几乎总是被粘住。在这种情况下,函数generate_episode使用程序员定义的策略对一集进行采样。

这里,MC 控制算法将估算并返回最佳策略,连同 Q 表,而不是由程序员硬编码的策略:

*env = gym.make('Blackjack-v0')
num_episodes=1000000
alpha = 0.02
eps_decay=.9999965
gamma=1.0policy, Q = MC_control(env, num_episodes, alpha, eps_decay, gamma)*

具体来说,policy是一个字典,它的关键字对应于一个状态s(一个 3 元组,指示玩家当前的总数、庄家的面朝上的牌以及玩家是否有可用的 a),并且对应条目的值指示代理在观察到该状态之后按照该策略选择的动作。

记住由函数返回的另一个字典,Q-table Q,是一个字典,其中字典中给定条目的键对应于一个状态s,并且相应条目的值包含一个维数等于动作数量的数组(在我们的例子中是 2 维),其中每个元素包含每个动作的估计动作值。

作为输入,该 MC 控制算法具有以下参数:

  • env:开放 AI 健身房环境实例。
  • num_episodes:生成的剧集数。
  • alpha:更新步长的步长参数。
  • eps_decay:ε参数更新的衰减因子。
  • gamma:贴现率。

设置ε的值

在开始编程之前,基于前面介绍的伪代码的代码需要花点时间来看看我们如何修改 ϵ 的值,使其在指定 ϵ 贪婪策略时逐渐衰减。记住,这对于保证 MC 控制收敛到最优策略π∑是很重要的。

使用以下代码设置每一集的 ϵ 的值,并使用print监控其演变,我们可以检查选择eps_decay = 0.9999965 是否可以获得 ϵ: 的逐渐衰减

*eps_start=1.0
eps_decay=.9999965
eps_min=0.05epsilon = eps_start
for episode in range(num_episodes):
            epsilon = max(epsilon*eps_decay, eps_min)
            if episode % 100000 == 0: print(“Episode {} 
               -> epsilon={}.”.format(episode, epsilon))*

在进入剧集循环之前,我们将 epsilon 的值初始化为 1。然后,对于每一集,我们通过将ε乘以值eps_decay来略微衰减ε的值。我们不希望 Epsilon 变得太小,因为我们希望在整个过程中不断确保 at leans 进行少量的探索。

主要功能

让我们开始根据前面给出的伪代码编写一个代码。伪代码之后的第一件事是将 Q 表中的所有值初始化为零。所以Q被初始化为一个空的数组字典,其中包含环境中的动作总数:

*nA = env.action_space.n
Q = defaultdict(lambda: np.zeros(nA)*

之后,我们在剧集上循环num_episodes,然后对于每一集,我们计算相应的 ϵ,相对于 q 表的最近估计构造相应的 ϵ- 贪婪策略,然后使用那个 ϵ 贪婪策略生成一集。最后,我们使用之前给出的更新等式来更新 Q 表:

*for episode in range(1, num_episodes+1):
       epsilon = max(epsilon*eps_decay, eps_min)
       episode_generated=generate_episode_from_Q(env,Q,epsilon,nA)
       Q = update_Q(env, episode_generated, Q, alpha, gamma)*

在完成剧集循环后,使用以下代码计算对应于最终 Q 表的策略:

*policy=dict((state,np.argmax(actions)) \ 
            for state, actions in Q.items())*

也就是说,该策略为每个状态指示要采取的动作,该动作恰好对应于 Q 表中具有最大动作值的动作。

参见 GitHub 获取我们恒α MC 控制方法的主要算法的完整代码。

使用 Q 表和ε贪婪策略生成剧集

相应的 ϵ- 贪婪策略的构造和使用该ϵ-贪婪策略的一集生成都包含在前面代码中实例化的generate_episode_from_Q 函数中。

该函数将环境、Q 表的最近估计、当前ε的值和动作的数量作为输入。作为输出,它返回一集。

代理将使用ε-greedy 策略来选择操作。我们已经使用 Numpy 的random.choice方法实现了这一点,该方法将一组可能的动作和对应于 Epsilon 贪婪策略的概率作为输入。对应于ϵ-贪婪策略的行动概率的获取将使用以下代码完成:

*def get_probs(Q_s, epsilon, nA):
    policy_s = np.ones(nA) * epsilon / nA
    max_action = np.argmax(Q_s)  
    policy_s[max_action] = 1 — epsilon + (epsilon / nA)
    return policy_s*

如果你看一下get_probs的函数代码,它实现了上一节详述的ε-贪婪策略。

显然,如果状态不在 Q-table 中,我们使用action_space.sample(). 随机选择一个动作。该函数的完整代码按照ε-greedy 策略生成情节,编码如下:

*def generate_episode_from_Q(env, Q, epsilon, nA):
    episode = []
    state = env.reset()
    while True:
          probs = get_probs(Q[state], epsilon, nA)
          action = np.random.choice(np.arange(nA), p=probs)     \
                   if state in Q else env.action_space.sample()
          next_state, reward, done, info = env.step(action) 
          episode.append((state, action, reward))
          state = next_state
          if done:
             break
    return episode*

更新 Q 表

一旦有了情节,我们只需查看每个状态动作,然后应用更新等式:

编程这个等式的代码是

 *def update_Q(env, episode, Q, alpha, gamma):
    states, actions, rewards = zip(*episode)
    discounts=np.array([gamma**i for i in range(len(rewards)+1)])
    for i, state in enumerate(states):
           old_Q = Q[state][actions[i]]
           Q[state][actions[i]] = old_Q + alpha   \
                   (sum(rewards[i:]*discounts[:-(1+i)]) — old_Q)
    return Q*

绘图状态值函数

如前一篇文章中的示例,我们可以获得相应的估计最佳状态值函数,并绘制它:

记住,有两个图对应于我们是否有可用的 a。

通过对这篇文章和前一篇文章的图形进行简单的可视化分析,我们可以看到,用这里给出的 MC 控件获得的策略更好,因为 state-value 值高得多。

时差学习

蒙特卡罗(MC)方法的主要缺点之一是代理必须等到一集结束才能获得实际回报(经验回报),然后才能更新价值函数估计并对其进行任何改进。这意味着蒙特卡洛具有非常可靠的收敛性质,因为它朝着实际回报 G 更新价值函数估计,这是真实价值函数的无偏估计

然而,虽然实际收益 G 是相当精确的估计,但它也是真值函数的高方差估计。这是因为实际收益在同一轨迹上累积了许多随机事件;所有的行动,所有的下一个状态,所有的奖励都是随机事件。这意味着实际回报收集并混合了多个时间步长的所有随机性。这就是为什么我们说,在蒙特卡洛,实际回报是无偏的,但方差很大。

此外,由于实际回报的高方差,蒙特卡洛的样本效率可能非常低。所有这些随机性都变成了噪音,只能通过大量的轨迹和实际回报样本来缓解。减少高方差问题的一种方法是,不使用实际回报,而是估计回报,并从未完成的情节中学习。

理查德·萨顿在 1988 年的一篇研究论文中提出了这种方法,称为时间差(TD)。这篇文章表明,虽然 MC 等方法使用预测和实际回报之间的差异来计算误差,但 TD 能够使用时间上连续的预测之间的差异(因此得名时间差学习)。

这一发现对强化学习方法的进步产生了巨大的影响,TD 学习是 SARSA、DQN 等技术的前身,我们将在本系列的后面介绍这些技术。

应该注意的是,这些方法中使用的估计回报是一个有偏估计,因为我们使用一个估计来计算一个估计。这种用估计值更新估计值的方式被称为自举(我们将在本系列的后面讨论),与动态编程方法有一定的相似性。

尽管这是一种有偏差的估计方法,但它的方差也比蒙特卡罗方法低得多。这是因为 TD 目标仅取决于单个行动、单个转变和单个奖励,因此累积的随机性要小得多。因此,TD 方法通常比 MC 方法学得快。

时间差分法

正如我们已经介绍过的,称为时间差分(TD)学习的方法是蒙特卡罗(MC)思想和动态规划(DP)思想的结合。像 MC 方法一样,TD 方法可以直接从原始经验中学习,而不需要环境动态的模型。然而,像 DP 一样,TD 方法部分地基于其他学习的估计来更新估计,而不等待最终结果。

请记住,在一个完整事件之后,蒙特卡洛控制的更新方程为:

在这个更新等式中,我们从 Q 表中查找当前估计值 Q ( StAt ),并将其与我们在访问状态-动作对后实际经历的回报 Gt 进行比较。我们使用新回归 Gt 来使我们的 Q 表更精确一点。TD 方法和 MC 方法之间唯一真正的区别是 TD 方法在每个时间步更新 Q 表,而不是等到剧集结束

有三种主要的变体,称为 Sarsa、Sarsamax 和 Expected Sarsa,它们实现了更新等式的三个版本。除了这个新的更新步骤,所有其余的代码都与我们在蒙特卡罗控制方法中看到的相同。让我们看看他们每一个人。

萨尔萨

使用这种方法,我们首先在构造相应的ε贪婪策略时将所有动作值初始化为零。然后,代理开始与环境交互,并接收第一个状态 S0 。接下来,它使用策略来选择动作 A0 。紧接着,它收到一个奖励 R1 和下一个状态 S1 。然后,代理再次使用相同的策略来选择下一个动作 A1 。在该序列之后

该方法更新对应于先前状态-动作对的动作值 Q 表。然而,我们没有使用回报作为更新 Q 表的替代估计,而是使用直接奖励 R1 和下一个状态动作对 Q ( S1A1) 的贴现值之和乘以伽马因子:

更一般地表达的更新方程是:

请记住,除了这个新的更新步骤之外,其余的代码与我们在蒙特卡洛控制案例中所做的是相同的。特别是,我们将使用 ϵ-greedy(Q) 策略来选择每个时间步的行动。

下面,读者可以找到一个总结了所解释内容的总体方案:

萨尔萨玛克斯

另一种 TD 控制方法是 Sarsamax 也称为 Q-Learning ,其工作原理与 de Sarsa 略有不同。

这种方法从 Sarsa 的动作值和策略的相同初始值开始。代理收到初始状态 S0 ,第一个 A0 动作仍然从初始策略中选择。但是接下来,在收到奖励 R1 和下一个状态 S1 之后,不是使用相同的策略来选择下一个动作 A1 (t 他使用ε贪婪策略选择的动作),w e 会在选择下一个动作之前更新策略。

特别地,对于估计,我们将考虑使用贪婪策略的动作,而不是ε贪婪策略。这意味着将使用使给定操作的 Q(s,a)值最大化的操作。因此,Sarsamax 的更新公式为:

其中我们依赖于这样的事实,即对应于一个状态的贪婪动作恰好是最大化该状态的动作值的动作。

因此,在我们使用贪婪动作更新时间步长 0 的动作值之后,我们使用与我们刚刚更新的动作值相对应的ε贪婪策略选择 A1。当我们收到奖励和下一个状态时,这种情况会继续。然后,我们执行与之前相同的操作,使用贪婪操作更新对应于 S1 和 A1 的值,然后使用对应的ε贪婪策略选择 A2,依此类推。遵循与 sarsa 相同的模式化,它可以直观地总结为:

预期 Sarsa

更新方程的最终版本预计为 Sarsa。Sarsamax 在所有可能的下一个状态-动作对的所有动作中取最大值,而 Expected Sarsa 使用下一个状态-动作对的期望值,其中期望值考虑了代理从下一个状态中选择每个可能动作的概率:

下面是三个 TD 更新方程(和 MC)的总结:

如果 ϵ 的值按照贪婪极限与无限探索 ( GLIE)条件衰减,并且步长参数 α 足够小,则所有三种 TD 方法收敛到最优动作值函数q∫(并因此产生最优策略π∫)。

自举方法

请注意,TD 方法部分基于其他估计来更新它们的估计。他们从猜测中学习猜测,他们引导。在 TD 方法中,从状态-动作对开始的回报是估计的,而在 MC 中,我们使用确切的回报 Gt

RL 中的自举可以理解为“将更新步骤中的估计值用于估计值的同类”。

MC 方法和一步 TD 方法都不总是最好的。n 步自举方法统一了 MC 方法和 TD 方法,概括了这两种方法,从而可以根据需要从一种方法平滑地转换到另一种方法,以满足特定任务的需求。这些方法超出了本系列的范围,但是,如果读者对进一步的细节感兴趣,他或她可以从理查德 s 萨顿和安德鲁 g 巴尔托的教材 强化学习:简介 的第 5 章开始。

政策内与政策外方法

让我们使用这些提出的方法来深入研究强化学习中广泛使用的方法分类概念之一:基于策略的方法和不基于策略的方法。

我们说 Sarsa 和预期 Sarsa 都是策略上的 TD 控制算法。在这种情况下,经过评估和改进的相同(ϵ-贪婪)策略也用于选择动作。

另一方面,Sarsamax 是一种非策略方法,其中被评估和改进的(贪婪)策略不同于用于选择动作的(ϵϵ-贪婪)策略。

下一步是什么?

我们已经到达这篇文章的结尾了!。到目前为止,我们已经介绍了在一个小表(Q 表)中表示动作值的解决方法。在下一篇文章中,我们将向您介绍使用神经网络来扩展我们可以通过强化学习解决的问题的规模和复杂性的想法。下期帖子再见!**

深度强化学习讲解系列

UPC 巴塞罗那理工 巴塞罗那超级计算中心

一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。

** [## 深度强化学习解释-乔迪托雷斯。人工智能

本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)

关于这个系列

我在五月份开始写这个系列,那是在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我 #StayAtHome 。感谢您当年阅读这份刊物;它证明了我所做的努力。

免责声明 —这些帖子是在巴塞罗纳封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。**

McNemar 使用 Python 从头开始的精确测试:SARS-CoV-1 诊断测试性能评估

原文:https://towardsdatascience.com/mcnemars-exact-test-from-scratch-with-python-evaluation-of-sars-cov-1-diagnostic-test-performance-327f355ba72a?source=collection_archive---------26-----------------------

这篇文章是关于 McNemar 的精确测试及其在 Python 中的实现。在我们讲述如何用 Python 从头开始执行测试之前,我想先从 McNemar 的精确测试的指示和测试理论开始。我们将使用 2003 年 SARS 冠状病毒流行的真实数据作为例子。最后,我们希望通过与使用 Python 内置函数获得的结果进行比较来验证我们的结果。

McNemar 的精确检验是一种统计检验,用于 2x2 表中相关的二进制数据。McNemar 的精确检验是与配对 t 检验等价的二分检验,后者应用于连续变量。该测试由美国心理学教授奎因·麦克尼马尔于 1947 年发表。McNemar 精确测试在医疗保健领域的常见应用是数据集,其中包含相关(如匹配)对。这些包括前后测试研究、病例对照研究(如双生子研究)和诊断测试的统计比较。

为了介绍测试背后的数学原理,我想用一个简单的例子:假设我们想检验吸烟和肺癌之间是否有联系。因此,我们根据年龄和肺癌家族史将 42 名肺癌患者(=病例)与 42 名对照者(=对照)进行匹配。接下来,我们获得 84 个人中每个人的吸烟状况。我们得到下表:

在 42 对配对中,有 21 对健康个体(=对照)和肺癌患者(=病例)都是吸烟者,8 对肺癌患者是吸烟者但对照不是,12 对两者都不吸烟,1 对癌症患者不吸烟但对照吸烟。

注意:这不是一个“典型的”列联表,因为单元格反映的是成对而不是个体!因此,我们不能使用通常的列联表分析,如皮尔逊的卡方检验或费希尔的精确检验,它们都假设独立样本!

这 21 对病例和对照组都暴露于危险因素,没有提供关于吸烟和肺癌之间联系的信息。类似地,12 对病例和对照组都没有暴露于危险因素,没有提供进一步的信息。

McNemar 的测试只使用了表中两个不一致单元格的数据(“病例吸烟者|对照非吸烟者”和“病例非吸烟者|对照吸烟者”)。如果吸烟状况和肺癌之间没有联系,我们会直觉地认为不一致的配对在这两个细胞中大致相等地分布。换句话说,如果我们感兴趣的变量相互独立(=零假设),不和谐对可能以相等的机会落入一个不和谐细胞或另一个不和谐细胞( p=0.5 )。

在零假设下观察到两个细胞中 9 个不一致对的特定分布的概率可以用二项式计算。在我们的例子中,我们得到:

在假设检验中,我们通常感兴趣的是在零假设下观察到特定结果的概率——或者更极端的结果。本研究中更极端的不一致对分布对应于“吸烟者|对照非吸烟者”中的 9 对和“非吸烟者|对照吸烟者”中的 0 对:

McNemar 的检验通常是双边检验,因为从理论上讲,所有不一致的配对也可以在表格的“非吸烟者|控制吸烟者”一方找到。这就是为什么我们还要加上

我们首先计算的两个概率导致 0.0176+0.00195+0.0176+0.00195 = 0.039 的双侧 p 值。因此,在本例中,我们在 0.05 的显著性水平上拒绝独立性的零假设。

我们可以简化 p 值的计算,正如数学上所示

b 和 c 是表中不一致细胞的计数。

McNemar 的精确检验是一种非参数检验,必须与 McNemar 的卡方检验相区别,卡方检验使用二项分布的卡方近似值。像 Fisher 精确检验一样,McNemar 精确检验适用于任何样本量,但对于稀疏数据是强制性的。一般的经验法则是,只要不一致对的数量少于 10,就使用精确检验。

McNemar 对 Python 的精确测试:

2002 年底,一种新的病毒性疾病,后来被称为严重急性呼吸系统综合症(SARS),出现在中国东南部,并迅速蔓延到全世界 8000 多人,造成 774 人死亡。由于全球的努力,这种病毒可能最终在 2004 年被控制住。导致 2002 年爆发的病毒(SARS-CoV-1)在基因上与导致 2019 年冠状病毒疾病疫情(新冠肺炎)的新型冠状病毒病毒密切相关。

冠状病毒有着典型的状表面突刺(来源:BSIP SA/Alamy 股票图片

2000 年代初遏制 SARS 传播的一项关键措施是快速发现人类 SARS 病例。像今天一样,定量 RT-PCR 检测是检测 SARS 冠状病毒最敏感的诊断工具。然而,基于 PCR 的方法的一个主要缺点是需要非便携式的实验室环境。这可能导致 RT-PCR 在偏远地区不可行。反转录环介导扩增试验(RT-LAMP)是基于 PCR 的方法的一种更快和逻辑上更简单的替代方法,可用于偏远地区的疾病爆发。

为了比较两种方法(定量 RT-PCR 与 RT-LAMP)的检出率,研究人员进行了以下研究 ⁴:回顾性 59 例 SARS 确诊病例的鼻咽抽吸物分别用两种方法进行检测。获得了下表:

(表格经作者 ⁴许可转载)

乍一看,我们可以看到 RT-LAMP 正确地将 42/59=71 %的吸出物识别为病例,相比之下,RT-PCR 中为 46/59=78 %。看着这些数据,我们可能会被误导,认为 RT-LAMP 可能具有较差的检测率。

我们现在想使用 Python 来找出两种诊断测试在检出率方面是否有显著差异。由于我们处理的是二元结果(“阳性/阴性”),并且两种诊断试验分别在同一鼻咽抽吸物上重复进行,因此我们必须使用麦克内马试验。不和谐对的和等于 2+6=8。正如我们对不一致的观测数是< 10, we have to use McNemar’s 确切的检验一样。

在 Python 中,我们从导入一些有用的库开始:

…并插入我们的数据:

然后,我们使用 while 循环来计算相应的二项式概率,就像我们在前面的例子中所做的那样。

这些二项式概率的总和就是我们的 p 值:

Statsmodels 是一个 Python 模块,它提供了一个内置函数来直接应用 McNemar 的精确测试:

正如我们所看到的,statsmodels 的函数和我们自己的 Python 代码都给出了 p 值 0.29,这基本上就是原始论文中报告的值。⁴ 作者得出结论,彼此的检出率总体上没有统计学意义。今天,在全球努力阻止新冠肺炎病毒的过程中,除了基于 PCR 的检测外,还使用基于 LAMP 的方法。⁵

完整的 jupyter 笔记本可以在我的 GitHub 上找到!

参考文献:

  1. 奎恩·麦克内马(1947 年 6 月 18 日)。“关于相关比例或百分比之间差异的抽样误差的说明”。心理测量学
  2. 成对二元数据的评估。骨骼放射学 40,1–4(2011)。https://doi.org/10.1007/s00256-010-1006-1
  3. 李帕特丽夏。(2017).DNA 扩增领域:移过 PCR,LAMP 来了。分子生态学资源。17.138–141.10.1111/1755–0998.12548.
  4. Poon LL,Wong BW,Chan KH,等。严重急性呼吸综合征冠状病毒检测的实时逆转录酶 PCR 和实时环介导扩增试验的评估。 J 临床微生物学。2005;43(7):3457–3459.2005 年 7 月 43 日至 3459 日
  5. 沈敏哲,,叶佳伟,Abdu Ahmed Abdullah AL-maskri,于康,苏增,,冠状病毒核酸检测的新进展和展望,药物分析杂志,
    2020,ISSN 2095–1779,https://doi.org/10.1016/j.jpha.2020.02.010

[## 麦克内马试验

在统计学中,麦克内马检验是一种用于成对名义数据的统计检验。它适用于 2 × 2 偶然性…

en.wikipedia.org](https://en.wikipedia.org/wiki/McNemar's_test)

我(电脑)有一天说得很好

原文:https://towardsdatascience.com/me-a-computer-talk-pretty-one-day-9f4ca0265137?source=collection_archive---------37-----------------------

为什么语言对我们来说如此简单,对计算机来说却如此困难

照片由 Unsplash 上的尼克·费因斯拍摄

考虑下面的句子(例子取自 Gibson 和 Warren 2004):

  • 顾问声称该提案取悦了谁?
  • 顾问想知道哪个建议让谁满意?

如果我让你说哪个句子是格式良好的,你可能会说第一句是,第二句不是。在语言学中,我们会说第一个符合语法,第二个不符合语法。然而,语法性并不总是像“这一个有效”和“这一个无效”那样简单。在许多情况下,包括我自己的 BA 论文,人们会被要求在一个尺度上对一个句子的语法性进行评级(在我的研究中,我要求受试者在 1 到 7 的尺度上对句子进行评级,这是相对标准的)。

我提出语法这个概念的原因是为了强调语言的一个重要方面,它的模糊性。人们可能会看着同一个句子,得出截然不同的判断。一个人可能会说,“是啊,听起来是一个非常好的句子,”另一个人可能会说,“这个句子完全没有意义,”另一个人可能会说,“嗯,在特定的上下文中,或者如果有特定的重音模式,它可能有意义。”虽然我们肯定有一些规则,关于什么可以和不可以创建一个格式良好的句子,我们不能总是肯定地说,如果一个给定的句子明确违反或不违反规则。此外,在某些情况下,一个句子可能不违反规则,但其结构具有较高的处理成本。这也是为什么语言学家仍然试图确定句子产生的规则。

语言比我们想象的要复杂得多。不仅在我们解释单词和句子的方式中存在歧义(即词汇结构歧义),而且在构成规则违反的内容中也存在歧义。也就是说,为什么表面上看起来并没有那么复杂呢?这些限制说明了为什么对一台处理绝对值和数字的计算机来说是困难的。那么,为什么它对我们来说如此自然?

https://twitter.com/BiIIMurray/status/755545329563475968

如果你像我一样,花太多时间看迷因,你可能会也可能不会在某个时候看到这条推文。现在想象一下,你有一个奥林匹克花样滑冰运动员,在他们的整个舞蹈中做跳跃和转身,而且通常很优雅。然后你有像我这样的人,她已经很多年没有滑冰了,在她的芭蕾课上表现得非常糟糕,她紧紧抓住围墙,当我试图做一些跳跃的时候,她可能会变脸。

当然,花样滑冰运动员可以轻松地做脚尖旋转,我甚至不知道那会是什么样子,因为花样滑冰运动员大部分时间都在训练。换句话说,一个复杂的动作对他们来说很简单,因为他们已经做了很长时间了。这就是莫拉维克悖论,对我们来说最简单的东西对计算机来说却是最困难的。语言的产生和理解对我们来说很简单,因为我们已经交谈了几千年。另一方面,我们刚刚开始教计算机这么做。

在我以前的一篇帖子中,我谈到了我们应该如何使用人工智能来帮助我们,而不是取代我们。我讨论了几个原因,但另一个重要的原因是,我们真的不太相信我们人类的能力。仅仅因为像语言这样的东西对我们来说很容易,并不意味着它很容易,这是我们在 NLP 领域学到的一课。我们的大脑已经成型并进化了数千年。当然,虽然我们希望创新和发展技术,但我们不应该渴望完全取代人类,因为这需要大量的工作。我们已经有了一个非常好的轮子,为什么还要重新发明轮子呢?如果我们想高效地使用时间和资源,就让我们建造能和轮子一起工作的东西,而不是取代轮子。

[1]吉布森、爱德华和泰莎·沃伦。"远距离依存关系中中间语言结构的阅读时间证据."语法 7,第 1 号(2004):55–78。

[2]森奈特、亚当,《歧义》,《斯坦福哲学百科全书》(2016 年春季版),爱德华·n·扎尔塔(ed .),URL =<https://Plato . Stanford . edu/archives/SPR 2016/entries/ambiguity/>。

[3]哈默,阿什利。2018."莫拉维克悖论解释了为什么对人工智能来说简单的事情是最难的."Curiosity.com。2018 年 6 月 11 日。https://curiosity . com/topics/mora vecs-paradox-is-why-the-easy-stuff is-hard-for-artificial-intelligence-curiosity/。

膳食计划的数据可视化方式

原文:https://towardsdatascience.com/meal-planning-the-data-visualization-way-83dc8cf91d96?source=collection_archive---------41-----------------------

一个简单的应用程序,帮助你计划一周的膳食,重点是减少浪费和简化购物旅行。

斯潘塞·戴维斯Unsplash 上拍摄的照片。除非另有说明,所有其他图片均由作者提供。

周日通常是我家的购物日,所以周日下午早些时候通常听起来有点像这样:

我们能至少做两次披萨吗?

我厌倦了豆子…

我们应该做豆子和米饭!还有咖喱。还要点寿司!

米饭太多了…

事实上,选择一周的食物是在每个人的偏好、我们的预算和一堆关于健康选择的意见之间的平衡。此外,我们还希望购物变得简单,而不必购买大量会被浪费的东西(看看你,一捆捆的香菜)。

有罪的一方。托马什·奥尔谢夫斯基在 Unsplash 上的照片。

因此,我构建了一个小的应用,它可以生成膳食计划建议,并可视化食材之间的重叠。因为你上传了自己的食谱数据文件,你可以选择如何对配料进行分类,因此该应用程序可以帮助优化对你来说重要的东西。例如:

  • 通过购买大量的一种将在多种食谱中使用的配料来省钱
  • 减少食物浪费
  • 选择不同种类的谷物、蔬菜、香料等来满足每个人
  • 如果你是素食者或纯素食者,摄入不同种类的蛋白质

想象一份膳食计划

这里的技术并不复杂。基本上,该应用程序获取一个文件,其中包含食谱列表、相关元数据(如 URL)和按类别列出的配料列表。看起来是这样的:

我们的“配方盒”文件样本。

你挑选一个感兴趣的初始食谱开始,然后算法会将新食谱添加到膳食计划中,直到你有 5 个(或者你想要的任何数量)。下一个食谱是由交集超过并集选择的——到目前为止,一个食谱与膳食计划中所有配料共享的配料数除以所有配料数。然后这个公式被稍微随机化,所以我们得到的食谱有一些共同点,但不是十种不同版本的西班牙海鲜饭。

我intersection over union 实际上与我在黑暗的前 app 时代做膳食计划的思维过程非常接近。因此,我设计了输出来可视化每个食谱中哪些成分是共同的或独特的。

一个饮食计划的例子。

In 配料由配方文件中指定的“类别”着色。这就很容易看出我们是否有各种各样的蛋白质,蔬菜,谷物,或者其他什么。可以想象,你可以根据每种商品最便宜/最容易买到的杂货店来设置类别,或者根据节食疗法所使用的类别来设置类别。

上面我看到两餐有米饭,两餐有面条,还有一餐没有任何碳水化合物。也许我想为此买面包?一顿饭没有蛋白质,所以也许我想在食谱上加点东西。我们在多种食谱中使用几种蔬菜,所以大量购买是有意义的。大葱也是“每捆太多,很难冷冻,所以它们最终会变坏”这一类别中的常见罪犯,所以在三个食谱中使用它们是很好的。

该应用程序

该应用程序构建于 Jupyter Lab 之上,使用 Jupyter 小部件进行控制。

你可以按名称和成分搜索食谱。

你可以改变每周的食谱数量,并获得新的饮食计划建议。

您可以保存膳食计划,稍后再返回。

最后,将鼠标悬停在菜谱上,会显示其名称和元数据。我们用这个作为食谱或者食谱所在的 URL,但是你也可以添加烹饪,卡路里或者减肥中心的点数等等。

入门

你可以在 Binder 上访问这个应用,或者从 GitHub 上克隆它。唯一需要的是一份你喜欢做的食谱文件。我们的有 300 多行,花了几个小时翻阅食谱来创建。或者,默认情况下,应用程序会加载一个从 Spoonacular API 中提取的食谱样本文件。您可以使用 get_sample_recipes.py 脚本获得任意多的食谱,尽管注意免费层每天有几百个的限制。你需要一个免费的 API 密匙来完成这项工作。如果你想探索新的美食和食物,这是一个不错的选择,因为 Spoonacular 的食谱来自各种美食网站和博客。

如果这个工具对你有用,请在评论中告诉我!

均值、中值和众数——何时使用哪个集中趋势指标?

原文:https://towardsdatascience.com/mean-median-mode-which-central-tendency-measure-to-use-when-9fb3ebbe3006?source=collection_archive---------21-----------------------

为了将数据集表示为 1 个数字的汇总,我们使用集中趋势度量。存在三种集中趋势度量,即均值、中值和众数。当只有一个(均值)可以完成工作时,为什么需要这三个度量?这就是这篇博客的全部内容,随着这篇博客的结束,你将能够回答这个臭名昭著的问题——选择哪一个&什么时候?由于每一个都有自己的优点和缺点,相同的将被详细阐述,以建立概念清晰。

让我们从视觉表现开始,以便更好地解释这些概念:

*使用的数据集——七个健美运动员的身高(假定为离散系列)

(图片由作者提供)

现在,我们将使用平均值、中值和众数来计算这些数据的集中趋势。

在计算之后,我们将确定当一个新的数据点被添加到数据中时,这些集中趋势度量中的每一个是如何表现的,这将进一步使我们能够理解每个集中趋势度量的重要性以及对于不同条件的应用适用性。

我们先来计算一下这个数据的均值:

150,160,160,170,155,180,175——这些数字反映了什么?

如果我们试着把它们放在一条数轴上,每个点除了离一个参考点的距离之外什么也不是(在这种情况下=0)

(图片由作者提供)

(图片由作者提供)

开始计算该数据的中值:

步骤:

  1. 按升序排列数据点
  2. 一半数据点位于上侧,另一半位于下侧的横截面分割是中间值测量。想象一下,您正试图使用分隔符将数据点分成两半
  3. 如果数据点计数为奇数,则有一个中心值位于分隔符上,这就是中值本身,否则位于分隔符两侧的两个点的平均值就是中值

(图片由作者提供)

(图片由作者提供)

对于给定的数据集,N 是奇数(7 个数据点),从上图可以明显看出,在分隔符数据点 C 的上方和下方有 50% (3)个观察值(也可以是 B,因为两者具有相同的值)。所以这个数据的中间值是 160 厘米。

开始计算该数据的模式:

这个是最容易计算的,只需要确定数据中每个数据点出现的频率,频率最高的就是数据的模式。当数据是非数字时,也可以使用这种方法。

(图片由作者提供)

由于有两个身高 160 cm 的健美运动员,这意味着该数据集的模式将是 160 cm。

(图片由作者提供)

现在进入最重要的讨论,为什么需要这三个集中趋势的测量而不是只有一个?

为了得到一个一位数的汇总(集中趋势),总是希望用这一个度量得到整个数据的无偏反映。但是,在下面的练习中,我们会注意到,有时均值本身无法保持无偏,并且该度量是数据的错误反映。

继续使用相同的健美运动员数据,我将添加一个外部数据点,并通知集中趋势测量的变化:

我已经向数据集添加了一个健美运动员(H )(身高= 200 厘米)

(图片由作者提供)

之前平均值= 164.3 厘米(7 次观察)

平均后= 168.75 厘米(8 次观察)

前中值= 160 厘米(7 次观察)

后中值= 162.5 厘米(8 次观察)

*在计算中值之前,不要忘记按升序排列数据

之前的模式= 160 厘米(7 次观察)

= 160 厘米后的模式(8 次观察)

注意事项:

与中位数和众数相比,平均值对数据集的任何大的增加都非常敏感。中位数变化很小,而众数则完全没有变化。到现在为止,你将开始得到为什么会想到这些措施的提示,一个简单明了的答案是作为处理他们先天偏见的最佳可行替代方案(我们刚刚展示了上面的一个例子)。

让我们总结一下这三种方法的优缺点:

(图片由作者提供)

我希望现在您已经清楚地了解了使用哪种中心趋势度量以及何时使用。这篇文章到此结束,请关注更多即将到来的博客。

谢谢!!!

如何度量一个统计模型的方差?

原文:https://towardsdatascience.com/measure-variance-of-statistical-model-e3b4725095b6?source=collection_archive---------33-----------------------

作为数据科学家,我们经常强调偏差-方差权衡。但是在比较模型的时候,我们需要量化方差。

由 Pritesh Sudra 在 Unsplash 上拍摄的图像

本文假设您理解并知道如何构建回归或分类模型。

任何统计模型的误差都由三部分组成——偏差、方差和噪声。通俗地说,偏差是预测准确性的倒数。方差指的是预测展开的程度。另一方面,噪声是无法系统表达的随机波动。

然而,上述定义是模糊的,我们需要从数学的角度来考察它们。在本文中,我将强调方差——困扰我们模型的更令人困惑的恶魔。

关于方差的一个简短注记

当我们允许我们的模型灵活地无用地学习训练数据的复杂关系时,它就失去了概括的能力。大多数情况下,这种灵活性是通过特征提供的,即当数据具有大量特征时(有时多于观测值)。这也可能是由于复杂的神经网络架构或过小的训练数据集。

由此产生的是一个也学习训练数据中的噪声的模型;因此,当我们试图根据看不见的数据做出预测时,模型就失灵了。

方差也是同一观测在模型的不同“实现”中的预测差异的原因。我们稍后将使用这一点来寻找方差的精确值。

数学解释

Xᵢ 为模型 M 根据观察值 i. 做出的预测总体。如果我们取大小为 n 值的样本,方差将为:

这是我们已经知道的事情。然而,我们需要计算总体的方差(相当于生成它的统计模型的方差),我们还没有完全做到这一点。在此之前,我们需要了解一个概念——bootstrap 重采样。

请注意,这个方差公式假设模型的结果是一个连续变量—这发生在回归中。在分类的情况下,结果是 0/1,因此,我们必须不同地测量方差。你可以在这篇论文中找到对此的解释。

自举重采样

通常,我们无法访问整个人口来计算统计数据,如方差或均值。在这种情况下,我们利用自举子样本。

bootstrapping 的原理表明,如果我们从大小为 n 的样本中抽取大量大小为 n 的子样本,并替换为,那么它就是从原始总体中抽取这些样本的近似值。

我们找到每个子样本的样本统计量,并取它们的平均值来估计总体的统计量。我们获取的子样本数量仅受时间和空间约束的限制;然而,你拿的越多,你的结果就越准确。

模型的实现

M 为我们的统计模型。 M 的实现是从输入到输出的映射。当我们在一个特定的输入上训练 M 时,我们获得了模型的一个具体实现。通过在来自输入数据的子样本上训练模型,我们可以获得更多的实现。

最后…

我们可以将这两个概念结合起来,通过引导训练数据来获得模型的实际方差的估计,从而获得模型的多个实现。

现在让我们将方差公式转化为模型 M观察X 的算法。

  1. 从训练数据中抽取一个 bootstrap 子样本。
  2. 在子样本上训练 M 并生成观测值 X 的预测 Pₓ
  3. 重复第 1 步和第 2 步 n 次
  4. 使用方差公式计算 Pₓ 的所有值的方差。

我们可以对更多的观察重复这一过程,并报告平均方差。

回归模型的方差

我使用了一个数据集来预测混凝土的抗压强度,单位为兆帕(兆帕)。

单点分析

我们评估不同模型的单个样本外观察的预测方差(通过 bootstrapping 获得)。

引导子样本数= 1000

正如预期的那样,bagging 和 random forest 模型比它们的基础模型(即决策树)变化更小。在所有模型中,预测值在实际值处达到峰值;然而,决策树分布是双峰的,并且更加分散。

分散分析

我们可以使用散点图比较所有样本外观察的模型的总体变化。

样本数量= 1000

较暗的金线代表实际值。再一次,决策树的预测更多的是分散在这条线上。

分类模型的方差

对于分类任务,我将使用修改后的鸢尾数据集来预测该花是否是海滨鸢尾(1 或 0)。我还添加了一种传染性的花,伪装成鸢尾。

灵敏度分析

基础模型对错误的观察(圆圈)更敏感,如在决策区域中所见。换句话说,它试图对训练数据中的噪声进行建模。

分类器的决策边界

奖金代码

这是一个基于 bootstrap 子采样计算方差的实现。

从 mlxtend 库中的 bias_variance_decomp()扩展而来

一锤定音

在比较两个或更多模型时,测量和模拟误差是很重要的。当你考虑升级到合奏时,这一点尤其重要。

还要注意,方差较低的模型不一定是更准确的模型(还记得有偏差的权衡吗?).偏差以类似的方式测量。

可变性和 z 分数的测量。为什么、何时以及如何使用它们?

原文:https://towardsdatascience.com/measures-of-variability-and-z-scores-why-when-and-how-to-use-them-a552005cc1a1?source=collection_archive---------11-----------------------

方差、标准差、变异系数、IQR 和 z 值的公式和示例

照片由罗斯季斯拉夫·乌祖诺夫像素上拍摄

内容

  1. 简介
  2. 范围
  3. 四分位间距
  4. 差异
  5. 标准偏差
  6. 变异系数
  7. Z 分数
  8. 结论

简介

为什么可变性的测量很重要?他们能给我们提供什么?

可变性是指数据的“分散”程度,以及每个分数与其他分数的差异程度。例如,让我们想想某个特定商店的顾客及其年龄。在运动服装和装备商店的例子中,最频繁的购买者可能来自较年轻的年龄组,数据集中在后者周围。然而,在超市的情况下,我们可能会注意到它的顾客可能属于不同的年龄组,在这种情况下数据更加分散。

最常见的可变性测量方法,尤其用于定量和连续数据,包括:

  • 范围
  • 四分位数和四分位数间距
  • 方差和标准差

为此,我还将添加关于变异系数的信息,这在希望比较不同数据集之间的可变性时很有用,以及 z 分数,这也称为标准分数,因为它们帮助我们了解某些数据分数离平均值有多远,特别是当我们希望将它们与同一分布或另一分布中的分数进行比较时。

每一种方法都有相应的公式和一些例子来说明它的用法。

范围

该范围是数据集中最高分和最低分之间的差值。

在本例中,范围是最高分 98 和最低分 11 之间的差值。可以看出,计算起来是非常容易的。然而,它也很容易受到异常值的影响,在本例中为 11、25 和 98。这就是我们计算 IQR 或四分位间距的原因。

四分位间距

四分位数来自四分之一。并且四分位范围表示包含在特定分布中的中间 50%分数的范围。

IQR =第 75 百分位(Q3) —第 25 百分位(Q1)

作者的图像标题

要计算 IQR,需要经过以下步骤:

  1. 将数据从最小到最大排序。
  2. 找出中位数(Q2),在上例中是 73。
  3. 计算下半部分(Q1)和上半部分(Q3)数据的中位数,在我们的例子中是:Q1 = 57,Q3 = 79。执行此操作时,不要包括最中心的值 Q2(在本例中为 73)。
  4. 从上半部中值 Q3 减去下半部中值 Q1。在上面的例子中,中间 50%的分数具有 22 分的范围,包含在 57 分和 79 分之间。

在进行 k-均值聚类之前,IQR 有时用于市场细分分析和剔除异常值。

差异

方差是说明一组分数有多少可变性的度量。它可以计算为每个数字与其平均值的平方偏差的平均值。

或者,为了更好地理解公式,让我们换一种说法。方差是平方和(平均值偏差平方和的简称)除以总体或样本中分数/数据点的数量。

人口方差公式

样本方差公式

尽管我们可以使用电子表格或其他工具来计算它,但最好是理解它们的公式以及其中包含的内容,以便更好地了解在什么情况下它们可以提供有用的见解。

标准偏差

标准差(方差的平方根)很有用,因为它可以用与原始度量相同的单位显示可变性。使用它比使用方差更有帮助。例如,如果我们测量一组样本人口身高数据的可变性,标准差有助于我们从方差单位到厘米和米。

总体标准差公式

样本的标准偏差公式

当看下面的例子时,也可以理解使用方差和标准差之间的区别,对于这个例子,我使用了 5 只狗的高度。320.213 方差单位对我们的样本没有太多说明,也很难解释。另一方面,这里的标准差用英寸表示,在上下文中更容易看到。样本狗之间 17 英寸的差异表明我们从不同大小的群体中选择了狗。

由作者完成的图像标题

变异系数

变异系数或相对标准偏差可以通过将标准偏差除以平均值来计算。并且当希望比较两个或更多数据集之间的可变性时使用它。

总体和样本的变异系数公式

我在上面的例子中使用了罗马尼亚布加勒斯特和英国伦敦的房价。价格用两种不同的硬币来表示,欧元和英镑。在这种情况下,如果我们想要比较两个数据集之间的可变性,标准差是没有用的。但这可以在变异系数的帮助下成功完成,变异系数在数据集之间是通用的。

z 分数

z 分数或标准分数在将数据放入上下文中时特别有用。

为了计算它,我们需要平均值和标准偏差,因为我们将比较分数与平均值和标准偏差的偏差。要计算分数的(x) z 分数,我们首先从中减去平均值,然后将结果除以标准差,如下所示。

人口的 z 得分公式

样本的 z 分数公式

如何解读结果?

  • z-score = 0,分数(x)正好是平均值;
  • z 得分为正,得分(x)高于平均水平;
  • z 分数为负,分数(x)低于平均值。

z 分数可用于比较同一分布之间或不同分布之间的分数。

现在让我们看一个例子。一家公司的雇员接受了一项能力倾向测试,他们获得了不同的分数。从下表中我们可以看到,乔安妮和马克获得了最高分(91 分和 88 分),而萨姆获得了最低分(49 分)。如果我们计算 z 分数,我们也将知道每个分数低于或高于平均值多少。

作者的图像标题

但是,如果对所有员工进行第二次测试,并且我们希望看到,例如,那些在上次测试中表现不佳的员工是否随着时间的推移而有所改善。我们再次查看 Sam 的案例,注意到他在第二次测试中获得了更高的分数。这可能会让我们认为他的表现有所提高。然而,如果我们计算 z 分数,我们将得到一个不同的结果。事实上,他的表现略有下降。这可以用以下事实来解释:总体而言,其余员工的绩效有所提高,这导致了平均值的提高,同时也是由于可变性的降低(标准偏差降低)。这就是背景有时会产生影响的原因。

作者的图像标题

结论

当我们希望用数字来描述数据时,可变性和 z 分数的度量与集中趋势和相关性的度量一起可以为我们服务。它们都是所谓的描述统计学的一部分。

我希望这篇文章是统计学系列文章的开始,因为我了解了不同的概念,并试图用我自己的例子更好地探索它们。所以,请让我知道你是否想看到某些话题。或者如果你认为这篇文章应该增加一些东西。

[## 在欧洲,现在是成为数据科学家或数据管家的最佳时机

为什么欧盟计划培训 50 多万名数据科学家和数据管理员

towardsdatascience.com](/now-is-the-best-time-to-be-a-data-scientist-or-a-data-steward-in-europe-618143a80dd0) [## 造福社会的数据科学

超越我们想看什么类型的电影,到我们想生活在什么类型的世界。资源、示例和…

towardsdatascience.com](/data-science-for-social-good-a88838bc8ed0) [## 用于社会公益的数据科学:免费开放数据的最佳来源

类型、优势以及在哪里可以找到它们

towardsdatascience.com](/data-science-for-social-good-best-sources-for-free-open-data-5120070caf02)

衡量时间序列模型[ETS 或 ARIMA]的性能

原文:https://towardsdatascience.com/measures-performance-for-a-time-series-model-ets-or-arima-18b0a3e91e83?source=collection_archive---------25-----------------------

解释时间序列数据的误差度量,并了解模型的性能以选择最佳模型

马库斯·斯皮斯克在 Unsplash 上的照片

在这篇文章中,我们将讨论处理时间序列数据时的误差测量技术的类型,以及如何从您之前创建的模型(如 ETS 或 ARIMA 模型)中选择最佳模型,并根据 ACFPACF 图找到最佳模型。

比例相关误差

与尺度相关的误差,如平均误差( ME )、平均百分比误差( MPE )、平均绝对误差( MAE )和均方根误差( RMSE )都是基于一个设定的尺度,对我们来说,这就是我们的时间序列,不能用于在不同尺度上进行比较。例如,我们不会从苏格兰绵羊数量的时间序列模型中获取这些误差值,并将其与美国的玉米产量预测进行比较。

  • 平均误差(ME) 显示实际值和预测值之差的平均值。
  • 平均百分比误差(MPE) 显示实际值和预测值之间的平均百分比差值。ME 和 MPE 都将有助于表明预测是偏向于不成比例的积极还是消极。
  • 均方根误差(RMSE) 代表预测值与观测值之差的样本标准差。当对用于估计的数据样本执行计算时,这些个体差异被称为残差,当样本外计算时,这些个体差异被称为预测误差。在比较模型时,这是一个很好的测量方法,因为它显示了预测值偏离平均值的程度。
  • 平均绝对误差(MAE) 取实际值与预测值的绝对差值之和,并取平均值。它对偶然出现的非常大的误差不太敏感,因为它不计算误差的平方。

百分比误差

MAPE 这样的百分比误差是有用的,因为它们与尺度无关,所以它们可以用来比较不同数据序列之间的预测,而不像尺度相关误差。缺点是它不能用于有零值的序列。

  • 平均绝对百分比误差(MAPE) 通常也可用于报告目的,因为它以通用百分比表示,即使对于不知道在花费的美元或售出的小部件方面什么构成“大”误差的人来说也是有意义的。

无标度误差

无标度误差是最近引入的,以提供一种与标度无关的测量,它没有百分比误差等其他误差的许多问题。

  • 平均绝对标度误差(MASE) 是另一种仅适用于时间序列数据的相对误差度量。它被定义为模型的平均绝对误差除以序列的一阶差的平均绝对值。因此,它衡量的是与简单模型相比误差的相对减少。理想情况下,它的值将明显小于 1,但相对于同一系列的其他模型的比较而言。由于这种误差度量是相对的,并且可以跨模型应用,因此它被认为是误差度量的最佳指标之一。

想了解更多,请看澳大利亚莫纳什大学统计学教授罗布·海曼的四页论文

当您使用 ARIMAETS 预测值,并在 TS 比较工具中比较这些预测结果时,如果您还使用 Alteryx 统计工具。

结论

希望这篇文章能给你一个简单的概念,告诉你如何评估你的模型,比较它们,选择最好的一个,如果你正在处理一个时间序列问题,并建立 ETS 或 ARIMA 模型。关于如何建立 ETS 模型的详细讨论可以从这里阅读,关于如何建立 ARIMA 模型的详细讨论可以从这里阅读。

本文原载于2020 年 10 月 30 日

谢谢你!

与 Cohen 的 Kappa 统计量的测量一致性

原文:https://towardsdatascience.com/measuring-agreement-with-cohens-kappa-statistic-9930e90386aa?source=collection_archive---------44-----------------------

这个鲜为人知的指标可以帮助您更好地评估模型在不平衡数据上的表现

对我来说,许多最有趣的分类用例是识别异常值。异常值可能是你收件箱里的一封垃圾邮件,对一种极其罕见的疾病的诊断,或者一个有着非凡回报的股票投资组合。由于这些实例是离群值,很难收集足够的数据来训练一个如何发现它们的模型。有些人把他们的整个职业生涯都奉献给了创造策略来对抗不平衡的数据。改天我会在另一篇博客中提出这些策略。

每个人对什么是准确和误差都有很强的直觉。这和我们在学术生涯中使用的评分系统是一样的。准确率是正确答案占全部问题的比例。错误是错误答案占全部问题的比率。这些指标适用于理想的数据集,而现实世界中并不存在这种数据集。

准确性悖论的一个例子是,如果一个人有 99%的机会没有特定的疾病,那么预测没有人患有该疾病的模型将是 99%准确的。

手动计算 Cohen 的 kappa 统计量

科恩的 kappa 统计很容易理解,不会成为准确性悖论的牺牲品。请听我解释技术术语。 Pₒ是评分者之间观察到的一致 。Pₑ是评分者得出相同答案的假设机会。1 级将是你的模型预测,2 级可能是你的 y_test 数据(答案)。

科恩卡帕统计公式

让我们用一个简单的例子来手工计算 Cohen 的 kappa 统计量。你在一次只有对错答案的考试中得了 7 分。老师有答案(y_test 数据)。为了计算你的预测和答案之间的一致性,我们必须找到 Pₒ和 Pₑ.首先,为了找到 Pₒ,我们加入正确答案的协议。

例题的设置和计算

我们现在已经计算出 kappa 统计值为 0.4,并且 Sci-kit learn 确认了该值。kappa 统计范围从-1 到 1。最大值 1 表示两个评分者完全一致。值为 0 等于达成协议的随机几率。所以我们的值 0.4 意味着我们略有一致。根据具体情况,这可能是可以接受的,也可能是不可以接受的。例如,在确定患者是否患有癌症时,您可能希望模型的 kappa 统计值高得多。

科恩卡帕统计可视化

我创建了两个类不平衡的点簇,比例为 10:1。这种类别失衡问题可能会导致诸如错误和准确性等指标的问题。左边的图像是我们创建的数据,右边的图像是我们的模型预测数据的方式。

原始创建的数据和我们模型的预测

该模型对 25%的数据进行训练,然后该模型对整个数据进行预测,以便于比较。你可以清楚地看到我们回归的决策边界在哪里。

在上图中,对应于 0 和 2 的点是两个模型在类别上一致的值。值为 1 意味着模型和数据具有不同的类标签。

如果你熟悉混淆矩阵,1 的值就是所有的误报和漏报。0 和 2 表示所有的真阳性和真阴性。

显示所有值的混淆矩阵

结论

Cohen 的 kappa 统计对模型的评分比其他任何指标都要严格。值为 0.648 意味着模型和测试数据基本一致。这个统计很简单,因为它可以比较你的模型。在不平衡的数据集上尝试一下吧!

感谢你花时间阅读我的博客。下面链接的 my GitHub 中提供了该笔记本的全部细节。如果您有任何问题或有建设性的批评,请随时联系我!

我的 GitHub 库**:https://github.com/bsamaha/Cohen-s-Kappa/tree/master

领英:www.linkedin.com/in/blake-samaha-54a9bbaa

推特:@Mean_Agression

测量和计算普利特维采湖国家公园的河流流量

原文:https://towardsdatascience.com/measuring-and-calculating-streamflow-at-the-plitvice-lakes-national-park-678223318191?source=collection_archive---------51-----------------------

克罗地亚普利特维采湖国家公园的普利特维采溪流

介绍

水流(或流量)描述了单位时间内沿着溪流或河流流动的水量,通常以立方米每秒[m /s]或立方英尺每秒[ft /s]为计量单位。它可能是水循环中最重要的元素。通常,它是通过将渠道横截面中的水面积乘以该特定横截面中的平均速度来计算的,也称为“速度-面积”方法。

Q = A * v

图一。“速度-面积”方法的可视化(来源:[1])

本文介绍了克罗地亚普利特维采湖国家公园普利特维采河和萨尔图克河的流量测量和计算。水文测量是“普利特维采湖国家公园普利特维采河流域水文地质调查”项目的一部分。

普利特维采湖 是克罗地亚最古老(1949 年 4 月 8 日宣布成立)和最大(300 公里)的国家公园。它位于 Lika-Senj 县,位于西部和西北部的 Mala Kapela 山脉和东南部的 Lič ka Plješ ivica 山脉之间。普利特维采湖于 1979 年 10 月 26 日被列入联合国教科文组织世界遗产名录,得到了国际认可[2]。普利特维采湖的独特之处在于,该湖泊系统有 16 个已命名的湖泊,还有几个较小的未命名湖泊。

图二。普利特维采湖湖泊系统(资料来源:meaki h .,以普利特维采湖国家公园为例的岩溶水资源保护模型,博士论文,2011 年)

图 3。克罗地亚普利特维采湖国家公园

首先,将介绍现场测量过程以及三个横截面的测量数据(水流速度),而第二部分则侧重于开发 Python 3 脚本来计算河流流量的过程。

现场测量

现场测量使用海流计进行,这是一种通过机械、倾斜、声学或电学手段进行流量测量的装置。对于该测量,使用来自 Seba Hydrometrie 的电磁电流计。具体来说,FlowSens 单轴电磁流量计。它可以以 0.5%的精度测量-5 至+5 米/秒的流速(仅针对正流量进行校准)。

图 4。801 型单轴电磁流量计—主机(图片由作者提供)

在测量之前,重要的一步是找到一个合适的测量点。有几个推荐指南,即来自美国地质调查局(Rantz 等人,1982 年)。

  • 测量点上游和下游约 300 英尺的河道是直的。

图 5。801 型单轴电磁流量计—圆柱形传感器单元(图片由作者提供)

  • 在所有阶段,总流量都被限制在一个单一的通道内。也没有地下或地下水流绕过场地。
  • 场地附近的河床不受冲刷和填充。它也没有水生植物。
  • 河道的两岸是永久性的。那里没有灌木丛,高度足以容纳洪水。
  • 河道有不变的自然控制。这些控制点是基岩露头或低流量条件下的稳定浅滩。在高流量期间,控制是渠道收缩或瀑布或瀑布,在所有阶段都不浸没。
  • 在极低水位时,现场上游有一个水池。这将确保记录极低的流量,并避免与高流量相关的高速度。
  • 测量位置远离与另一条河流的汇合处或潮汐影响,以避免对河流水位测量产生任何可能的影响。
  • 在测量点附近,可测量所有阶段的流量。
  • 该场地可用于测量场地的安装、操作和维护。

在大多数情况下,检查所有建议的点几乎是不可能的,尤其是在较小的溪流中,比如那些向普利特维采湖供水的溪流。他们水井位于复杂的地形和树木繁茂的地区。所以主要的重点是找到一个尽可能直的,容易到达的地点,尽可能少的植物和碎片。此外,对于这个特定的项目,需要在某些区域进行测量,因为项目的主要目标是发现由于喀斯特地形导致水“流失”的河段。

当在感兴趣的段中找到合适的位置时,我们将设置横截面并测量河流的宽度。我们用了一根 20 米的卷尺。此外,卷尺还可作为流量计操作员的定位点,以便在相等的分段中进行测量,即所谓的分段(图 1。)在每个分段中,操作者进行几次测量,每次在不同的深度,其中测量的次数取决于该分段的深度。此外,还有几种经验方法,即可以在深度 0.6 处的 1 个点进行测量,对于非常浅的河流,可以在深度 0.2 和 0.8 处的 2 个点进行测量,等等。

图 6。Petar,我的朋友和学生,操作流量计(图片由作者)

在本次分析中,我们采用的方法是,通过计算算术平均值,对每个分段的测量速度进行平均。

接下来,通过对分段 i-1i+1 处的深度求和并除以 2,计算每个分段 i 处的平均深度。这个平均深度乘以每个子部分的宽度得到子部分的面积。然后将每个分区的平均速度乘以分区面积,得出每个分区 qi 的流量。将这些分段流量相加,得出断面总流量 Q

测量数据示例

图 7。测量数据示例数据框架—横断面图 1—普利特维察河

我们用表格(在纸上)记下测量的数据。 列代表测量点,而是距河岸的距离,单位为米。 h 为每个分段的深度。 v1vn 为各分段不同深度测得的速度米/秒,而 d1dn内的深度。数据帧的大小和形状取决于横截面的几何形状和大小。展示的示例是最宽的横截面,宽度为 15.6

流量的计算

为了计算每个横截面的流量,编写了一个简单的 python 脚本。我将简要地解释它是如何工作的。

首先,我们导入依赖项,在这种情况下,我们需要 numpy 和 pandas。我们用数据定义 excel 文件的文件路径。由于我们有几个横截面,每个横截面都在 excel 中的单独工作表中,我们使用 pandas 函数“read_excel”读取文件,并将其存储到字典中,其中键是工作表名称,值是包含数据的 pandas dataframe。

图 8。测量数据字典(7 个条目,7 个横截面)

接下来,定义用于计算平均分段速度、分段宽度和面积、分段流量以及横截面面积和流量的函数。

首先,以厘米为单位的列被转换成米,空的单元格被填充-999。

接下来我们要计算平均分段速度。条件相当简单。所以比如我们只有一次测量,深度【D1】**不同于-999,但是测量深度 d2 不存在,所以是-999,平均速度就是 1 次单次测量的速度。如果我们有例如 3 次测量,深度 d3 存在,但深度 d4 不存在,那么 d4 就是-999。我希望这个类比是清楚的🙂。此外,如果深度 h 为 0,速度也为 0,因为该点代表河流两侧的海岸线。这一原理是可行的,因为自然的溪流总是有这样的形状(图 7。).**

在下一步中,计算分段宽度。每个分段的宽度等于从测量点到下一个点和前一个点的一半距离的总和(图 9。)例如,子部分 II 中的子部分宽度等于到点 I 的距离的一半+到点 III 的距离的一半。同样,分段宽度的起点和终点等于到最近点(图 9 中的点 I 和 VII)的距离的一半。).这里我们用熊猫。DataFrame.shift 获取上一个和下一个距离的值( df.stac )。

图 9。计算截面宽度的原理(来源:[3])

接下来,我们计算分段面积。这里我们需要考虑到,没有一个天然河床具有规则的形状,因此,要考虑一些近似的情况。在实践中,每个分段的平均深度是通过平均前一个和下一个分段的深度来计算的,类似于分段宽度。此外,第一个和最后一个子部分的深度是根据起点和终点计算的。我们再次使用熊猫。DataFrame.shift 得到上一点深度和下一点深度的值( df.h )。

每个分区的平均流量通过平均流速和分区面积相乘计算得出。此外,当深度为零时,没有流量,因此,对于海岸线点,我们将 streamflow 设置为零。

接下来,计算 宽度面积** 和总截面 流量 Q 。同样,返回 数据帧宽度面积总 Q 。**

我们用一个字典理解调用这个函数,以便再次得到一个字典名为 results_Q 以截面(剖面)名称为关键字,以及一个由此产生的元组 dataframewidthareatotal Q 作为值。

图 10。数据帧的结果元组和具有计算值的字典

图 11。结果数据帧

数字结果如图 10 和 11 所示。索引 2 和 3 包含最重要的结果,剖面横截面面积和总横截面流量 q。对于该特定横截面,我们计算出横截面面积为 9.01 m,总流量为 0.115 m /s ,或 115 l/s

可视化

图 11。河床横截面的可视化(作者)

假设我们想看看河床的横断面是什么样子。我们可以定义一个函数,使用线图在 y 轴上显示沿横截面测得的深度,而沿 x 轴显示距河岸的距离。

这种图对于比较通过该过程测量的不同横截面非常有用,对于比较下游河床的变化也非常有用。

我要强调的是,在这个例子中,测量不是从最上游的站开始的。

点 5 (Plitvica stream well)和点 6 (Sartuk stream well)位于最上游,点 7 位于 Sartuk 和 Plitvica 汇合处之后,紧接着是点 1、2、3 和 4。4 号点位于大瀑布之前。

另一个选项是显示横截面速度。因此,我们定义了一个创建网格的函数,并对计算出的分段速度的空间分布进行插值。这样,我们可以直观地检查通过横截面的流量分布。

图 12。横截面速度可视化(作者)

结论

测量溪流或河流的流量在水文学中非常重要。在这个项目中,对河流流量的测量应能让我们了解测量到的水流失发生的确切位置。

本文介绍了从测量到计算流速和计算断面总流量的全过程。在第一部分中,讨论了现场任务和原理,而第二部分集中于整个过程的计算和自动化。另外,还提供了可视化数据的代码。

如果你喜欢这篇文章或者你对水文学感兴趣,请随时关注我的 mediumLinkedIn 。干杯!

参考

[1] Turnipseed,D.P .和 Sauer,V.B .,2010 年,测量站流量测量:美国地质调查技术和方法第 3 册,第 3 章。A8,87 p。

[2]普利特维采湖国家公园官方网站,https://NP-plitvicka-jez era . HR/en/about-the-Park/general-information/

[2]ugaj,R: Hidrologija ,萨格勒布大学采矿、地质和石油工程学院,萨格勒布,2000 年

衡量变化

原文:https://towardsdatascience.com/measuring-change-54bb44e26a14?source=collection_archive---------29-----------------------

集中趋势测度和扩散测度背后的真正含义

作者图片(地点:新泽西马纳斯泉水库https://www.instagram.com/gauravkantgoel/

让我们做一个思考实验。想象一下,你周围的世界刚刚冻结。什么都没有改变。一切都停滞了。有什么是有意义的吗?你能学到什么吗?没什么。一个停止的世界相当于一个没有的世界!世界因为“变”而存在。行星的自转和公转,物种的进化,经济的增长或衰退,人口力学,股票市场的涨跌……..每个现象的核心都有一个“改变”的概念。

如果你进行一次大的概括,你会发现人类所有的知识都是关于识别、理解、测量和操纵自然界发生的变化。任何关于现象的知识都会大致试图回答以下问题:

有变化吗?哪些事情在改变?

一件事的变化会影响到其他人吗?

如何衡量这种变化?有没有一个规则可以解释和表达这种变化?可以用来预测未来的变化吗?

当你在观察或研究一个现象时,你关注的是相关的事物。这些东西被称为“ 变量 ”,因为它们“变化”或者它们“改变”。它们经历的“变化”或“变异”取决于它们是什么样的变量。

定量还是定性

作者图片

从根本上说,所有变量(或所有数据)只能有两种类型: 定量或定性

有些事情你可以衡量“大小”或“价值”,如速度、距离、体积、体重、身高、收入等。这些是数值,对这些变量执行算术运算(如加或减)是有意义的。数量变量通常有度量单位,如千克、美元、年等。

另一方面,有些变量描述了一些事情。例如人名、地名、性别、种族或动物种类等等。对这些变量的算术运算没有意义。你不能增加或减少性别或类别。这些变量通常没有单位。请注意,定性变量也可以采用数值,如 PIN 码或社会安全号,但您不会想要添加 PIN 码或 SSN。这毫无意义。

现在想想任何数据值。该值可以是定量的,也可以是定性的。数量变量也叫“连续”变量。本质上,它们代表了一个被测量的“量”。例如重量。它是“连续的”,因为值可以是任何值。例如 50 公斤,50.1 公斤,52 公斤,52.5 公斤…几乎任何事情。

定性变量也被称为“分类变量”。本质上,它们代表一个“组”或一个“类别”,值将属于该组或类别的一个固定集合。例如,性别—(男性或女性),医学检验结果(阳性或阴性)

变量的类型(定量或定性)将决定可以进行的分析类型。

让我们来看一些可以用来描述或理解这些变量变化的操作。

集中趋势测量

图片作者(【https://www.instagram.com/gauravkantgoel/】T4)

每当事情发生变化时,我们表达或总结这些变化的自然倾向是什么?平均而言,人们会倾向于找到“。(双关语:)

计算“平均值”是我们在分析数据时自然产生的最直观的事情。假设你想知道一个击球手有多好?(在板球比赛中)给你他在最后 10 场比赛中得分的分数。

为了衡量他的表现或者判断这个球员有多好或者有多差,难道你没有一瞬间的冲动去计算 10 场比赛的平均得分吗?你不能仅仅孤立地看每场比赛的比分就做出决定或推论。你需要一个代表数字来反映它。而自然的倾向是找出“平均”。

我们很多人都没有意识到,但是有很多方法可以衡量“平均”。这些测量被称为“集中趋势测量”。

平均:

大多数时候,当人们谈论平均水平时,他们实际上是指“平均水平”😃

平均值就是所有给定数字的总和除以有多少个数字。

在我们的例子中,平均值是(5+2+12+32+21+3+12+0+15+9)/10,得出 11.1

你可以说“mean”是“average”的一种。还有其他类型吗?

中位数:

假设这个球员在另一场比赛中获得了惊人的 400 分!

现在得出的平均值是:46.45

在这种情况下,平均值可能会产生误导,因为在所有比赛中,该球员的得分都远低于 46.45。因为只有一场比赛他得了 400 分,总的来说有点失真。这样的数据点称为异常值。在这种情况下,衡量平均值的更好方法是“中值”,即数据值的中间点。在我们的示例中,我们将对所有数据值进行排序,并选择中间的一个。

中位数是 12,在这种情况下,这是一个更合适的“平均”度量。

模式:

“平均值”的一个不太为人所知的度量是众数,众数是我们的数据集中出现频率最高的数据值。在我们的例子中,“12”重复了两次。所以众数是 12。均值和中值用于定量变量,而众数便于定性变量。计算性别、肤色等定性变量的平均值或中值是没有意义的。比方说,在我们的例子中,我们有一个列,它告诉我们某场比赛是球队赢了还是输了。

在这种情况下,变量“匹配结果”的模式是“赢”,因为“赢”出现了 7 次,而“输”只出现了 3 次。

我们可以说,就“平均”而言,该团队正在获胜。

“平均值”、“中值”和“众数”是三种对平均值的度量,它们给出了关于数据“中心性”的概念。

但是,在分析或总结数据时,平均值是否提供了足够的信息?我们还能做更多的事情。

差异量数

图片作者(【https://www.instagram.com/gauravkantgoel/】T2)

除了找出一个数据集的平均值之外,我们还可以看看数据被分散了多少。或者换句话说,数据集中有多少“可变性”。让我们通过一个例子来理解它。到目前为止,我们一直在关注单个玩家的分数。假设,我们已经得到了所有 10 场比赛中 2 名球员的得分。我们必须比较这些分数,并试图了解这些球员在相互比较中的表现。

下面是数据集:

两位运动员的平均成绩都是 50 分。那么怎么才能比较呢?一个微妙的事情是检查这些球员在比赛中的平均表现如何。一个球员比其他人得分更稳定吗?一个球员在几场比赛中得分很高,而在其他比赛中得分很低吗?这些玩家在不同比赛中的“分数如何变化?

范围

检查分数如何变化的一个非常基本的指标是计算每个玩家的分数范围。

范围就是数据中最大和最小观察值之间的差值。

玩家 1 的范围= 200–0(最高分-最低分)= 200

玩家 2 的范围= 70–30 = 40

看起来参与人 1 比参与人 2 的得分范围更大。这意味着参与人 1 的分数比参与人 2 的分数更具多样性。如果我们仔细观察参与人 1 的数据,会发现存在异常值。在一些比赛中,这个球员得分特别高,比如 200 分,而在一些比赛中,他什么也没得分(0 分)。Range 可以度量值分布的范围,但它对异常值很敏感。

四分位数间距(IQR):

克服范围不足的一个方法是以某种方式排除异常值并构建一个“迷你范围”。一个这样的标准是“四分位间距”。我们按升序对数据进行排序,并将数据值分成 4 组(四分位数)。然后我们只考虑中间的 50%的值。这给了我们四分位间距。

参与人 1 的 IQR:

0 0 0 0 40 50 50 50 100 200

我们有 10 分。下四分位数的位置是 n/4 = 3(四舍五入后)

上四分位数的位置是 3n/4 = 8(四舍五入后)

IQR 是(8 号位得分—3 号位得分)

IQR = 50–0 = 50

参与人 2 的 IQR:

30 34 46 50 50 50 54 56 60 70

我们有 10 分。下四分位数的位置是 n/4 = 3(四舍五入后)

上四分位数的位置是 3n/4 = 8(四舍五入后)

IQR 是(8 号位得分—3 号位得分)

IQR = 56–46 = 10

一种叫做“盒须”图的特殊图形被用来显示范围。

对于给定的数据属性,它显示 5 个指标:

  1. 最小值
  2. 最大值
  3. 中位数
  4. 四分位数 1
  5. 四分位数 3

让我们通过绘制方框图和胡须图来比较两位玩家的得分:

从上图可以明显看出,与参与人 2 相比,参与人 1 有更多的变化。两个玩家的中值或平均值是相同的,但是玩家 1 的分数比玩家 2 的分数差很多。我们可以说参与人 1 不如参与人 2“一致”。尽管玩家 1 的最高分即 200 比玩家 2 的最高分(70)高得多,但是他在得分上并不一致。

判断一个玩家表现的更有效的方法是找出一个玩家偏离其“平均”分数的程度。偏差越大,玩家的一致性越差。偏差越小,一个球员就越稳定。

差异

方差是一个简单的度量,它表示数据属性与其平均值的“偏差”。你不需要记住下面的方差公式:

请记住,我们试图找出一个数据属性中有多少变化。因此,我们可以采取以下简单的步骤:

  1. 计算数据属性的平均值
  2. 找出每个数据点与平均值之间的差异。它实际上给了我们一个数据值偏离平均值的程度。现在,这种差异可以是正的,也可以是负的(因为数据值可以小于或大于平均值)。为了避免负数和正数互相抵消,我们可以取它的平方。
  3. 计算所有差异的总和
  4. 除以数据值的数量。这给了我们平均的变化。

标准偏差

标准差就是方差的平方根

计算方差时,用平方根来抵消步骤 2 中平方的影响。

标准差是关于平均值的数据分布的度量。它大致衡量了这些条目与平均值的差距。它告诉我们数据是如何分布的。SD 越多,数据越分散。因为它只是一个衡量标准,所以不可能是负数。

在我们的例子中,

参与人 1 的标准差= 59.32

参与人 2 的标准差= 11.06

Python 代码片段

玩家 2 的标准差比玩家 1 小得多。因此我们可以说这个玩家更加稳定。他的表演变化较少。虽然他得分不高,但他在所有的比赛中都相当稳定。

想想自然界的任何变量。如果这个变量的标准差很大,你可以有把握地说这个变量有很多不同的值。行为不一致。但是如果它的标准差很低,那么你可以假设这个变量的行为是相当一致的。

你有一个总是很冷静的朋友,而另一个却喜怒无常(有时生气,有时冷静,有时冷漠)?你现在知道谁的“标准差”更大了。

如果一个变量有一个常数,那么它的标准差是多少?你不需要分子式。它将是 0。

"平均值"偏离平均值"是在研究数据集时应该记住的两件事。

衡量公关行业的内容参与度

原文:https://towardsdatascience.com/measuring-content-engagement-in-pr-industry-4644dbb4ed4c?source=collection_archive---------31-----------------------

来自 campaignasia.com 的照片

内容参与度测量在公关测量中至关重要,它证明了发布内容、媒体和品牌价值的影响。衡量敬业度时考虑的指标和属性真正解释了它的有效性。和常用的指标,大多数公关公司使用的是一些访问,分享,喜欢,评论,转换,花在一个页面上的时间,总页数访问和访问次数。

衡量内容参与度的挑战在于选择正确的公关指标来跟踪内容参与度的不确定性。这是因为任何社交媒体上的分享或喜欢并不意味着读者积极参与或打算采取行动。这意味着,分享或喜欢该内容的读者没有百分之百的机会积极参与该内容。

在本文中,我将对上述指标在解释实时内容参与度方面的不良联系做出一些假设。

为了衡量内容参与度,我考虑了下表中显示的一些指标/属性。

表 1 —预测内容参与度的方法

使用上面的列表,我们可以回答类似“访问(或)分享(或)喜欢(或)会话持续时间的数量决定内容参与度吗?决定客户是否积极参与内容的因素是什么?在所有列出的属性中,衡量内容参与度的两个不太重要的指标是“触及度”和“会话持续时间”。

  • 接触与参与:接触被定义为访问网站的次数。有些情况下,客户访问网站是因为他们被内容误导了。在这种情况下,这不是衡量内容参与度的好方法。
  • 会话持续时间与参与度:会话持续时间是指阅读内容所花费的时间。有时候,人们会打开多个标签,分心,然后离开屏幕。在这种情况下,时间累积起来,可能会给出误导性的结果,说某个特定的读者正在积极地参与内容。

我列出了上述所有衡量标准的一些随机组合,以证明很难完美地衡量内容参与度。从下表中可以看出,输出变量是“转化率”,因为主动参与内容的最终结果是以销售的形式对内容采取一些行动,其余的都是用于分析参与度的输入变量。以下所有这些组合适用于各种“网站来源”和“位置”。

表 2-读者参与的各种可能性

如果我们考虑他们使用的资源和读者来自的国家,存在上述措施的许多组合。因为,来源和状态对内容参与度也有影响。如果一个来源更受欢迎,例如像福布斯或 LinkedIn,那么读者可能会认为这是一个好内容,并可能采取行动。同样,来自特定位置的读者比来自其他位置的读者更有可能采取行动。

:我已经用上面列出的组合(来自表-2,用于进一步分析)组成了 214 条数据点记录,并将数据分成训练集和测试集。

数据集的链接:https://github . com/ShailuSurya/content engagement/blob/master/content engagement % 20 dataset . CSV

I .我们如何决定读者是否积极参与内容?

使用上面列出的组合,很难预测读者是否积极参与。决定内容参与度的唯一属性是“转化”。如果客户在访问内容后采取了行动,那么他/她就被认为是积极地参与了内容,否则就不是。因此,主要任务是预测“转换”。

存在许多机器学习分类模型来预测结果。在这里,我使用逻辑回归和随机森林分类算法来预测转换的概率。

代码链接:https://github . com/ShailuSurya/content engagement/blob/master/contentengagementmeasurement . ipynb

a.逻辑回归

我采用了输入变量,“状态”,“来源”,“喜欢”,“分享”,“评论”,“访问次数”,“新用户”,“年龄”,“总访问页数”,“会话持续时间(分钟)”来训练模型,以预测转化率。数据被分成 75/25 的比例。测试数据的混淆矩阵如下所示。从模型结果来看,假阴性(第二类错误)率为 66%。模型的整体准确率为 46.2%。

逻辑回归的混淆矩阵

逻辑回归的前五个记录的预测结果如下表所示。结果并不准确,即使我们预测某个读者会采取行动,也有 66%的几率我们的预测是错误的。转换预测列中所有“橙色”单元格都被错误预测(当与提供的原始数据比较时)

表 3 —逻辑回归模型结果

b.随机森林分类

预测“转换”的随机森林分类模型使用 600 个决策树进行训练,其中 70%为训练数据,30%为测试数据。模型的混淆矩阵如下所示。

随机森林分类的混淆矩阵

从上面的混淆矩阵中,如果我们预测读者将要采取行动,那么有 59%的机会(假阴性率)读者不会采取行动。同理,如果我们预测一个读者不会采取行动,那么有 46%的几率我们的预测是错误的。因此,很难说客户是通过喜欢、分享、评论、会话持续时间和总访问量来参与内容的。

从下表中可以看出,橙色单元格是随机森林模型的错误预测。它类似于前五个记录的逻辑模型。在此分析中,随机森林模型的精度比逻辑回归高 1%。我认为这 1%的增长不会影响错误预测的数量。我认为,这两种方法都不能准确预测读者转化率。

表 4-预测转换的随机森林分类

随机森林模型的可变重要性

随机森林模型确定预测转换最重要的变量是“年龄”、“州代码”(州)、“会话持续时间”和总访问页数。它不重视喜欢、分享、用户类型和评论。我认为年龄这个变量很重要,因为选择特定的阅读内容会随着年龄的变化而变化。有些品牌在某些地区很有名。因此,上图中的“StateCode”定义了不同地区的品牌认知度会影响转化率。

二。公司如何衡量内容参与度?

从以上两个模型来看,我们肯定无法准确衡量内容参与度。但是公司如何衡量呢?

  • 通常,公司根据数据中可用的模式来衡量“内容参与度”。如果“喜欢具有高会话持续时间的内容”的读者采取行动,那么模型将预测喜欢内容或在内容上花费大量时间的读者将会采取行动。但是这些结果有多准确呢?这要看数据的准确程度。
  • 如果可用的数据是有偏差的,那么结果将是有偏差的。例如,如果大多数客户多次喜欢、分享、评论和查看该内容,请采取行动。然后使用这种类型的数据点,我们可以说喜欢/分享/评论该内容的客户更有可能采取行动。

但是如果我们的预测是错的呢?所以,我认为没有正确的方法来猜测读者参与度。因为如果顾客不想采取行动,他/她就不会采取行动。这完全和客户在那一瞬间的行为有关。同样在 2014 年,悉尼科技大学的教授 Jim Macnamara 解释说,读者参与度是一个心理学概念,被错误地用点击量和分享量来衡量。我觉得这是真的。公司应该怎么做才能如此精确地衡量读者参与度?

公司应该考虑更多的指标以及与可用指标相关的风险。要建立任何衡量标准,最好是每个公司内部都有一定的广泛标准。我还认为,沉迷于数字,只分析定量数据,并且未能应用测量和评估技术,也会导致在测量内容参与度方面的失败。

结论

总的来说,没有一个输入变量真正定义转换率。逻辑回归和随机森林分类这两种模型都未能预测转化率。因此,我们必须首先了解数据可用性,以及预测转化率需要考虑哪些额外指标。

参考

《T2》吉姆·麦克纳马拉(2014)。重访评估的学科家园:公共关系评估标准的新视角

达利博·杰克斯,公共关系专家。公共关系传播的测量与评估

测量通过过滤器的浓缩咖啡萃取量

原文:https://towardsdatascience.com/measuring-espresso-extraction-across-the-filter-c9a4ccee117f?source=collection_archive---------28-----------------------

不久前,我决定去测量浓缩咖啡过滤器上的孔,目的很简单:我后悔买了一台意大利的 Enrico 浓缩咖啡机,我想要一些可以量化的指标来忽略某些机器。结果变成了一项关于过滤器的大型研究,我发现即使是最好的过滤器,其过滤器平面上的孔径分布也会影响流量。然而,在现实生活中很难衡量这种现象。

过了一会儿,我找到了进行这种测量的方法,我终于有了合适的数字折光仪来进行这项工作。在提取过程中,测量需要分离浓缩咖啡过滤器的不同部分,我使用了一个微型冰块托盘。

背景

我开始注意到我的机器中带有无底的 portafilters 的模式。这种模式看起来与我从原始测量中发现的模式相似,但是裸 portafilter 的困难还是在于一些水流重叠,可能会隐藏堵塞的孔洞,使咖啡无法流出。此外,在拍摄过程中,我看到了更暗的流动,这表明流动如何在镜头内动态变化是更大的未知。我一直梦想能够测量这种现象。

几个月后,我得到了一台白利糖度折射仪和一台 Atago TDS 咖啡测量仪。Brix 很难用于收集多个数据点,但 Atago 非常适合数据收集。我开始收集各种数据,特别是在整个拍摄过程中提取的数据,并且对这种测试的渴望越来越强烈。我想要的不仅仅是最终的 TDS 读数。在进行跨时间的 TDS 测量时,我使用了一个冰块托盘来收集多个时间间隔的拍摄输出。这让我开始调查是否有人制作了一个小冰块托盘。我在亚马逊上发现了一个微型冰块托盘,我想我会冒险花 12 美元做一次实验。

实验准备

收到托盘后,看起来我最多只能得到一个 5×5 的样品网格,缺角(总共 21 个样品)。我还用水做了一些测试,我发现正方形很浅,所以在拍摄过程中,我必须将它在过滤器上移动两次(总共三个位置)。杠杆机器的好处是我可以减缓压力,把托盘稍微拉下,然后把它移到下一个点。这确实对结果有轻微影响,但没有其他选择。

还有另外两个主要问题:

关注点#1 :冰块托盘中的空气是否会阻止咖啡进入托盘,因为托盘会被压在过滤器的底部?这在很大程度上是未知的,似乎是大气压下水通过过滤器的一个问题。我没有解决办法,在拍摄的时候,这并没有产生明显的影响。

关注点 2 :立方体之间的隔板会阻挡液体通过过滤器并影响圆盘内部的流动吗?这种情况很有可能发生,但我无法知道目前的工具是否产生了影响。如果它确实有影响,它将通过滤波器被感觉到,并且不会不均匀地影响输出(理论上)。

在准备我的设置时,我也不得不剪下滤镜,这很简单,用剪刀就能帮助我对准滤镜,尤其是当我在整个镜头中移动的时候。

这一枪

至于设备,我用的是金快线弹簧驱动手动咖啡机。在第一次破裂后的 1:15 分钟,我烘烤了等量的埃塞俄比亚干法和尼加拉瓜芬卡的混合物。我用 Lume grinder 打磨它们,我开始用常规击球代替断奏以防击球完全浪费。

我使用了一个 IMS 三重篮子,在准备冰球的过程中,我使用了一个弯曲的回形针来打碎团块并分配场地。然后我捣了两次:一次是在分发后一半的地面上,一次是在分发后的最后。我用了 24 克咖啡,我发现如果我不中途捣实,很难得到好的分配而不损失咖啡。我知道这不符合标准。然后我用一个水平仪确保从顶部看,一切都是水平的。

我还想说明的是,我没有想到的第一次测试会进行得如此顺利,我很惊讶。

第一次测试的结果是惊人的。唯一的错误是没有将最左边的过滤器摆正,浪费了几列。最终的结果是,镜头最后三分之一的最右边的三列不见了。

后来,冰球上出现了一条裂缝,但这可能是在我把冰球拉进托盘并让压力不减的情况下发生的。过滤器的底部似乎显示了均匀流动的模式,但下一次,我应该有一个辅助相机来看看均匀流动是如何通过过滤器后的冰块托盘。

测量数据

我使用了 Atago TDS 咖啡折射仪和一个可以精确到小数点后两位数的标尺(500 克 x 0.01g 克)。我为整个托盘设置了一个数据表,我涂黑了没有液体或液体太少无法测量的方块。

我还应该注意到,我用保鲜膜盖住托盘,让咖啡冷却到室温。我担心测量需要一段时间,我不希望水分蒸发成为一个重要因素。我不确定我是否会再次覆盖,但冷却的时间很重要。通常应该在你喝饮料的温度下进行 TDS 测量,但是在这个实验中控制它的唯一方法是确保它不变。控制这一变量的唯一完美方法是拥有一个 100%湿度的房间,并且当镜头离开时,温度与镜头相同。

为了测量,我将托盘放在秤上,并将秤盘归零。然后,我会用注射器从立方体中取出尽可能多的咖啡,滴入 3 滴(偶尔偶然 4 滴)到 TDS 阅读器中。剩下的,我会倒进杯子里。我用一些棉签将立方体擦干,并记录重量。大约在那个时候,TDS 测量可用于记录。

至于从哪里开始测量,拍摄的第一部分不多,我知道 TDS 会这么高,我必须稀释样品才能测量(Atago 只上升到 22.4% TDS)。所以我开始记录照片中间、结尾和最后开头的数据。

对于 TDS 过高的立方体,我会将计量器放在秤上,添加 3 滴(通常重 0.07 克,我承认这有可变性,因为它在秤上可以分辨的低端),我会添加 0.14 克过滤水。我没有蒸馏水,但测量过滤水的 TDS 为 0.07%,我认为这可以忽略不计。

结果

即使在记录数据时,很明显过滤器上的分布是不均匀的,但奇怪的是分布如此不同。有些可能是因为拍摄的不均匀,但不清楚哪一方更受青睐。

将三个时间实例中的每一个的所有方块相加,似乎可以清楚地看出,在最初的一点咖啡中提取了大块咖啡。与之前的数据相比,这似乎有点高,这可能是由测量误差引起的。

如果我们观察液体重量、咖啡萃取重量和 TDS 这三个时间段,就会发现奇怪的模式。仅仅因为过滤器上的一个点提取了大量的液体,提取的咖啡并不完全是趋势。在整个过滤器上也存在不均匀性。

我为过滤器添加了累积的液体/咖啡/TDS,这样人们就可以看到总量是如何随时间变化的。就哪些方块有最多的液体通过而言,有一些通道,但这种模式并不像我想象的那样遵循提取咖啡的模式。

一段时间内的累积数字

为了了解液体重量与提取的咖啡之间的关系,我取了中间的样本,用提取物与重量的关系对它们进行了线性作图。它们看起来大多是线性的,但没有我想象的那么紧密。

我们再深入一点!

1.与上面的网格提取方向相同的过滤器的原始图像。2.基于标准图像处理技术的孔径彩色化。

现在,对于真正的测试,流量与基于井眼尺寸的过滤器分析相比如何?一年前,我从事各种浓缩咖啡过滤器的滤网孔分析。孔尺寸较大的区域会导致较高的流量,从而有助于形成沟道吗?

主要问题是孔的数量远大于用于收集样本的立方体的数量。因此,让我们向下采样到 5 乘 5 进行比较,记住,无论哪种方式,结果都应该是有保留的。

在中间一行,第 2 列到第 4 列有一个明显的带,这里的流量低于周围的方块。这在一定程度上与重量和提取的咖啡的最终数据收集相一致。中心像素似乎也排列得很好。需要更高的分辨率才能做出合理的结论。

这个实验可能是新奇的,但它仅仅是一个开始。一个更好的实验应该有更小的正方形和更多的正方形,并且可以重复多次。结果表明一件事是肯定的:过滤器下面发生的事情不能仅仅通过一对音量和 TDS 测量来总结。

虽然数据收集很复杂,容易出错,但我想再做一次,检查断奏镜头和其他过滤器。我还打算看看我是否能得到一个更好的设计,有更深更小的正方形。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。

我的进一步阅读:

断续浓缩咖啡:提升浓缩咖啡

浓缩咖啡中咖啡溶解度的初步研究

浓缩咖啡模拟:计算机模型的第一步

咖啡数据表

工匠咖啡价格过高

被盗浓缩咖啡机的故事

平价咖啡研磨机:比较

浓缩咖啡:群头温度分析

浓缩咖啡过滤器分析

便携式浓缩咖啡:指南

克鲁夫筛:一项分析

衡量金融风险:逐步指南

原文:https://towardsdatascience.com/measuring-financial-risk-a-step-by-step-guide-dd51d647103b?source=collection_archive---------26-----------------------

风险价值、预期短缺和正态分布的风险

照片由编年史颜Unsplash

这里有一个虚构的故事,讲的是传奇金融家约翰·皮尔庞特·摩根的一个朋友把他所有的钱都投资到了股票市场。他的朋友神经极度紧张——他希望发大财,但又面临着失去一切的可能性。当他见到摩根时,他告诉他自己是多么担心自己的投资,这让他许多个夜晚都无法入睡。“我该怎么办?”他问。摩根简单地回答道:“卖出,直到你达到睡眠点。”

风险和回报

这项投资我会损失多少?每个投资者都问过这个问题。我们都直觉地理解摩根所暗示的风险和回报的权衡:像股票这样的高风险资产提供了更高回报和更高波动性的可能性。“更安全”的资产,如黄金和政府债券,波动性较低,但预期回报较低。考虑到这一点,我们如何计算我们投资的风险呢?

风险价值和预期短缺

风险价值【VaR】***和预期短缺**是理解金融风险的基础。VaR 回答了一个基本问题:*

对于给定的信心水平,我预计我的投资组合在一定时间范围内最大的损失是多少?

资产回报的假设分布,红线代表风险值

关于风险值的问题通常是这样的:“在 95%的置信水平下,我的投资组合的一天风险值是多少?”这表示 alpha 值为 0.05,但也经常使用其他 alpha 值,如 0.01 和 0.10。在分布的背景下,VaR 实际上指的是一个分位数。对于 0.05 的 alpha,我们感兴趣的是我们回报的 5%分位数——这意味着我们回报的 95%在 VaR 的右边,而 5%在左边。我们选择的 alpha 越低,分布就越靠左,我们的 VaR 就变得越负。

预期短缺回答了一个不同但相关的问题:

在最差 q%的情况下,我的投资组合的预期回报率是多少?

与 VaR 相反,VaR 在回报率分布中寻找对应于 alpha 的分位数,Expected Shortfall 取 VaR 左边所有回报率的平均值。如果我们计算 alpha 为 0.05(5%分位数)的风险值,相应的 ES 取该点左侧所有每日日志回报的平均值。ES 是一个比 VaR 更稳健的风险度量,因为它解释了左尾巴的重量。当两种方法一起使用时,我们可以感觉到我们的投资组合在任何一天、一月或一年的风险有多大。

获取数据

为了计算我们自己的 VaR 和 ES,我们将使用 Wilshire 5000 的数据,该股票市场指数被广泛认为是衡量美国股票价格的最广泛指标。我们可以使用quantmod从美联储经济数据库中导入我们的数据。我们还将使用ggplot2来可视化我们的数据。让我们加载我们的库,导入数据,并将我们的观察限制在 1980 年 1 月到 2020 年 6 月之间。然后我们可以将数据绘制成时间序列。

加载库,获取数据,并绘制成时间序列

威尔希尔 5000 性能,1980 年至 2020 年

计算日志回报

在计算 VaR 和 ES 时,我们将使用每日回报的自然对数,而不是传统的算术回报。使用对数回报有几个优点,最有用的是,与算术回报相比,对数回报的分布更对称,更接近正态分布(尽管,正如我们将看到的,对数回报正态分布的观点是一个非常有缺陷的假设)。

让我们计算每日日志回报、平均值和标准差,然后绘制分布图。

正态性检验

我们的回报分布在两个重要方面偏离了常态。首先,我们的分布有重尾——这就是所谓的轻子库分布。第二,我们的对数回报是不对称分布的:它们形成了一个左偏分布,这意味着极端负回报比极端正回报多。**

我们可以使用moments包中的三个函数来确认这些观察结果:kurtosis()skewness()jarque.bera()。峰度衡量尾部的重量(正态分布的峰度为 3),偏斜度衡量分布的对称程度(正态分布的偏斜度为零)。Jarque-Bera 是一种统计拟合优度测试,我们可以用来验证我们的分布的峰度和偏斜度是否不同于正态分布。

Jarque-Bera 的零假设是我们的分布是正态的。从统计学上,我们知道当 alpha 大于 p 值时,我们拒绝零假设。在这种情况下,我们拒绝零,并得出结论,我们的每日日志回报是非正常的。我们的 p 值基本为零(2.2e-16),因此我们可以在 99%的置信度下拒绝正态假设。

实际上,这意味着 Wilshire 5000 对数收益比我们基于正态分布的假设更加不稳定。忽视这一现实并使用正态分布会让我们意识不到,并且容易受到黑天鹅级别的负面事件的影响,因为我们低估了尾部风险。

方法 1:从经验分布中抽样

既然我们已经排除了使用正态分布来寻找 VaR 和 ES,我们可以用什么来代替呢?一种方法是直接根据我们的经验分布进行模拟,而不对其形状做任何假设。我们可以使用下面的代码,基于经验数据的模拟,在 95%的置信度下计算 1 天的 VaR 和 ES。

这告诉我们,在 95%的置信水平下,Wilshire 5000 的 1 天 VaR 为-1.64,ES 为-2.67%。换句话说,这意味着我们不应该期望在任何一个交易日 95%的时间里遭受比 1.64%更糟糕的下跌。我们的 ES 状态告诉我们,单日跌幅超过 2%是可能的,但可能性极小。

方法 2:从 student-t 分布中抽样

我们已经确定我们的回报不是正态分布的,但这并不意味着我们不能用另一种分布来拟合我们的回报。Student-t 分布是一大类分布,它包含正态分布,但具有较重的尾部。我们可以使用我们的平均值、标准差和自由度值来拟合“重新调整”的 Student-t 分布,以便它合理地接近我们的分布。我们可以使用MASSmetRology包来实现这一点,然后使用这个拟合的分布重新计算 VaR 和 es。

我们使用这种分布的结果意味着比我们的经验估计更少的风险。这一次,我们估计我们在 95%置信度下的 VaR 是-1.43%,而 ES 是-2.11。一种方法不一定比另一种更好,但对于保守的投资者来说,最好使用我们从经验分布中获得的结果,并假设最差的 VaR 和 ES。

应用我们的结果

假设我们向威尔希尔 5000 投资 1000 美元。我们如何将刚刚计算的 VaR 和 ES 应用到这个投资组合中?

最终,我们基于离散回报来衡量我们投资组合的变化,而不是对数回报。我们使用对数收益是因为它们方便的统计特性,但离散收益是通常使用和报告的。让我们将经验 VaR 和 ES 转换为离散回报,根据我们 1000 美元的投资组合计算它们,并解释结果。

我们的 VaR 告诉我们:我们不希望在任何一个交易日 95%的时间里损失超过 16.30 美元。我们的 ES 告诉我们,在最糟糕的 5%的情况下,我们预计损失约为 26.24 美元。

根据您的风险承受能力和时间跨度,这些指标可以应用于不同的环境。如果你是日内交易者,我们计算的 1 日 VaR 和 ES 将有助于显示你的交易策略的风险程度。如果你是一个长期投资者,我们可以对我们的日志回报使用apply.yearly()函数,并重新计算 VaR 和 ES,以确定我们在一年中可能会损失多少钱。

结论

我希望你喜欢这个教程,并了解了一些投资组合风险!您现在可以使用quantmod获得财务数据,计算对数回报,使用moments软件包分析回报分布,并以几种不同的方式测量 VaR 和 ES。还有更先进的方法来衡量金融风险,我希望在未来的帖子中涵盖它们。关于如何使用 R 分析金融数据的更多信息,请查看我之前的帖子, 在 R 中构建和测试股票投资组合。感谢阅读!

本文的代码和数据可以在我的Github找到。

关于我

我叫克里斯蒂安·金凯,在马里兰大学帕克分校学习金融和经济学。如果你喜欢这个帖子, 关注我 上媒!

测量投手隐藏投球的能力

原文:https://towardsdatascience.com/measuring-how-well-pitchers-hide-their-pitches-f61f076d91f4?source=collection_archive---------65-----------------------

使用机器学习来量化欺骗

何塞·莫拉莱斯在 Unsplash 上的照片

正如棒球界最近在 Astros 2017 作弊丑闻中看到的那样,知道投出了什么球给了击球手一个打破比赛的优势。然而,除非你有一个复杂的摄像头和垃圾桶系统,否则要知道要扔什么球是非常困难的。击球手只有不到一秒钟的时间来捕捉可能指示他们将要面对的投球类型的信号,处理和处理这些信息的时间甚至更少。指示投出哪一球的信号可能是投手的下意识反应,也可能是跑垒员向二垒看的信号。但这些要么是情境性的,要么是有经验的投手容易避免的。一个更难避免的投球指标是投手的释放点。

Sean Manaea 在 2018-2019 年投球的释放点

上图显示了奥克兰 A 队的投手 Sean Manaea 自 2018 年以来所有投球的释放点。正如我们从图中看到的,根据沥青的类型,释放点有相对明显的差异。对马奈来说,他倾向于释放比任何其他球都低的快速球,而他的变速球平均来说是在最高点释放的。观察力敏锐的击球手可以捕捉到这些信号并加以利用。不需要垃圾桶,只需要技巧。然而,并不是所有的投手在他们的释放点上都有如此明显的不同。以贾斯汀·韦兰德为例:

贾斯汀·韦兰德 2019 年的投球点数

看上面的图表,我们可以看到韦兰德的发布点更加统一。根据他的投球类型,他的释放点似乎没有很明显的不同。这使得击球手很难根据手臂位置的不同来预测韦兰德投出了什么球。

量化隐藏音高的能力:

既然我们已经看到了隐藏音高能力的差异,一个自然的问题是:我们如何量化这种差异?我决定量化这种能力的方法是使用一个分类模型。如果你不知道什么是分类模型,这里有一个快速总结。分类是一种机器学习模型,试图根据某些特征对数据进行分类。在这个特定的模型中,“类”是音高类型,特征是释放点的坐标和音高被投掷的计数。因此,该模型采用释放点坐标和计数,并根据该信息尽最大努力确定投掷的类型。

功能选择:

当然,如果我只是想准确地对投掷的球进行分类,我可以将旋转速度和球的运动度量作为特征包括进来,以建立一个更加准确的模型。但我想量化投手对击球手隐藏投球的程度,所以我只想要击球手在球从投手手中释放之前可以获得的信息。因此,在这个模型中,我们只有音高的释放坐标和它被扔进的计数作为特征。

评估模型:

一旦模型试图对给定的数据进行分类,我们需要一种方法来评估它对数据的分类程度。这就是我们如何衡量一个投手对击球手隐藏投球的能力。用于评估模型的度量标准称为精度分数。这实际上返回了被正确分类的音高的比例,所以它的范围是从 0 到 1。如果模型能够正确地对大部分投球进行分类(精确得分值更接近 1),这告诉我们投手在他的投球的释放点上具有更明显的差异,和/或他在某些计数中投掷的投球是非常可预测的。更接近 0 的精度分数表明模型不能有效地基于释放点和计数对音高类型进行分类,这告诉我们投手在从同一点释放音高方面要好得多,并且根据计数将它们混合得很好。需要记住的一件事是,拥有更多球场曲目的投手得分会更低,因为有更多的球场需要分类。为了抵消这一点,我将根据模型的表现比简单地随机分类音高好多少来衡量模型的表现。例如,如果一个投手有 4 个音高,你随机猜测音高类型,你会有 25%的正确率。因此,如果一个有 4 个音高的投手的精确得分是 0.5,那么它的调整后得分将是 2,因为它比随机猜测有效两倍。

成绩:

既然我们已经定义了模型和评估指标,让我们来看看结果。在这里,我从 2019 年随机挑选了 16 名投手,并通过模型运行他们的投球数据。

我们的“赢家”是 Blake Snell,他拥有最高的精确度分数和最高的调整分数。斯内尔的高分表明他有不同的释放点,让我们看看他的释放点图来验证这一点。

布莱克·斯内尔的释放点

上面的图表似乎符合 Snell 的高精度得分。斯内尔似乎有非常明显的区域,他释放他的变速球到较低的右边,他的曲球和快速球到较高的左边。

当与 Gerrit Cole 相比时,这种差异更加明显,Gerrit Cole 在我测试的球员中精度得分最低。

Gerrit Cole 的发布点

Gerrit Cole 的释放点更加混乱,他在哪里释放某些球没有明确的模式。这使得击球手更难捡起他手中的球。

应用:

虽然这个小实验更适合我,但我相信团队可以通过几种方式利用这些数据和模型。

第一个应用是让击球手找到释放点有明显差异的投手。然后,团队和击球手可以查看这些投手的释放点图,以找到不同投球的模式,并使用该信息来帮助根据投手的手臂位置计算出正在投掷的投球。当然,这说起来容易做起来难,但是有经验的玩家可以利用这些信息达到很好的效果。

第二个应用是投手。具有高精确度分数的投手可能想要尝试降低他们的精确度分数,无论投球如何,都从同一点持续投球,让击球手更难捡起被投出的球。

如果您对如何应用这些数据有任何想法,请随时告诉我!

模型和数据的代码可以在我的 GitHub 上找到。这是我第一次使用分类,所以任何提示或批评都非常感谢。

测量人工智能代理的对话质量

原文:https://towardsdatascience.com/measuring-quality-of-conversations-of-ai-agents-cccc642bb74d?source=collection_archive---------29-----------------------

人工智能(AI)代理无处不在。它们嵌入在你的智能手机(苹果 Siri,谷歌助手)中,它们在你的智能家居设备(亚马逊 Alexa,谷歌 home)中,你可能在与一家公司的客户服务部门交谈时与一些互动,它们嵌入在你访问的许多网站的聊天小工具中;你可能不止一次在与那个代理人交流时感到沮丧。但是为什么还是会这样呢?

来源:麻省理工科技评论

这种情况仍然发生有许多技术和数据相关的原因,我们现在不会深入探讨,但对改进人工智能代理至关重要的一个主题是测量。如果无法衡量,如何改进?

人工智能社区内部普遍存在测量和评估——毕竟他们是科学家,科学家需要证据来证明一些事情。但是如果测量标准不能准确描述实际问题呢?

AI 智能体从出现之日起就被测量过。被广泛接受的用来衡量人工智能代理质量的指标是真正重要的指标。其中一些测量如下:

  • 理解:机器学习的一个领域叫做自然语言理解,完全是让计算机理解用户在说什么。一些常用的指标是精度、回忆F1ROC 曲线来确定计算机理解用户的准确程度。这是一个好的开始,但并不完整。这只是衡量对话的一方(理解用户说了什么),而不是衡量双方的对话(对话)。
  • 满意度:另一种测量技术是直接询问用户对响应和/或体验的满意度。一个常用的衡量标准是客户满意度(CSAT) 。这一指标可能不准确,因为用户在回答调查时可能会考虑回答对他们的影响,而不是回答本身。例如,如果在 10 次令人沮丧的互动后,一个人工智能代理告诉我,我中了彩票,见鬼,是的,他们得到了 10/10 的分数。另一方面,如果一个人工智能代理告诉我,我已经超过了我的手机计划的数据限制,我很可能不会得到很好的分数。

正如你所看到的,在能够衡量人工智能代理的对话质量方面一直存在差距——直到本周。

本周早些时候,谷歌大脑团队发布了他们的研究,名为“迈向一个可以聊……任何事情的对话代理”,他们发布了一个聊天机器人 Meena ,它比其他开放域聊天机器人表现更好。虽然 Meena 产生了令人印象深刻的结果,但我发现更有趣的是谷歌如何测量结果。

谷歌推出了敏感度和特异性平均值(SSA) ,它从用户的角度(理应如此)衡量对话。

敏感性和特异性平均(SSA)指标是由 Google 开发的,因为现有的指标很复杂,并且没有在评论者中产生一致的结果。SSA 很简单,通过解决对话的两个基本问题“有意义吗”和“这具体吗”,可以产生更一致的结果。它是这样工作的:

  • 明智的:要求人类评估者判断计算机的反应是否有意义。如果有任何令人困惑、不合逻辑、断章取义或事实不正确的地方,回答将被标记为“没有意义”——否则,它将被标记为“有意义”,并根据下一个标准进行评估;
  • Specific :一旦人类评估者认为某个响应“有意义”,他们就会被要求判断该响应是否特定于给定的上下文。例如,如果用户说“我饿了”,而计算机回复“好的,酷”,则该响应不是特定的,因为相同的响应可以用于许多其他上下文。如果电脑回复“我也是,我们点些吃的吧”,那么这个回复就是具体的。

在评估了数百次对话和数千次来回互动后,可以通过查看标记为“合理”的响应比例和标记为“具体”的响应比例来确定 SSA 分数;这两者的平均值得出 SSA 分数。SSA 提供了对对话质量的更好理解,同时作为一种度量标准简单而优雅。

我已经在人工智能(AI)领域工作了很多年,去年专门构建了对话式 AI 代理。我以前就考虑过这个差距,因为我们现有的测量过程似乎不完整和/或不确定。我知道必须有一个好的方法来衡量整体的对话,但我一直没有找到什么东西。敏感度和特异性平均值(SSA)是一个优雅的指标,在保持简单的同时衡量正确的事情。有希望的是,随着 SSA 在学术界和商业应用中被更广泛地采用,我们将会看到用户与计算机对话的质量有所提高。

对人工智能系统的测量有更多的想法吗?在 Twitter LinkedIn上打我。

阿布舍克

新冠肺炎时代的社会距离测量

原文:https://towardsdatascience.com/measuring-social-distance-in-the-time-of-covid-19-da0503717a62?source=collection_archive---------27-----------------------

使用 TensorFlow 对象检测 API 来检测行人并计算他们之间的“社交距离”。

不幸的是,今天每个人都很熟悉这个术语、【社会距离】、。在一切恢复正常之前,我们将不得不忍受一段时间。在 免疫技术研究所 我们尝试使用 TensorFlow 对象检测 API 开发一个应用程序,用于识别和测量行人之间的社交距离。

等等…什么是 TensorFlow 物体检测 API?

TensorFlow 对象检测 API 是用于创建深度学习网络的框架,该网络解决对象检测问题。它包含一些在不同数据集上训练的预训练模型,可用于推理。

此外,我们可以使用该框架将迁移学习应用于之前在大型数据集上训练过的预训练模型,这使我们能够为特定任务定制这些模型。例如,我们可以应用迁移学习来训练一个识别一个人是否戴着面具的模型。

用于图像分类的迁移学习背后的直觉是,如果一个模型是在一个足够大且通用的数据集上训练的,那么这个模型将有效地充当视觉世界的通用模型。然后,您可以利用这些学习到的要素地图,而不必通过在大型数据集上训练大型模型来从头开始。

在这种情况下,我们不需要应用迁移学习,因为我们想要识别行人,并且已经有一些模型被训练来推断这一点。我们使用的模型SSD _ mobilenet _ v2 _ coco _ 2018 _ 03 _ 29已经针对这些对象进行了培训:

型号 ssd 的类别 _mobilenet_v2_coco_2018_03_29

对于这个用例,我们只需要识别和显示行人,因此我们将创建一个按标签过滤预测的函数,我们将只显示person (id=1)标签。

走吧…一些代码!

当我开发这段代码的时候, TensorFlow 对象检测 API 还没有完全支持 TensorFlow 2 ,但是 7 月 10 日 Google 发布了一个新版本,开发了对一些新功能的支持。在这种情况下,我使用了 TensorFlow 1TF 对象检测 APIr1.13.0 版本以及 Google Colab 的所有容量来进行这个实验。

你可以在我的 GitHub 里找到代码。

首先,我们需要在我们的驱动器中创建我们的工作目录Projects/Pedestrian_Detection,在那里我们将克隆 TensorFlow 对象检测 API 库。然后,我们将能够用 Google Colab 启动一个笔记本。

在项目/行人检测中创建一个 Google Colab

首先,我们需要将我们的驱动器安装到我们的笔记本电脑中,我们只需要按照说明进行操作。

在 Google Colab 中挂载驱动器映像

然后,我们将能够把path改变到我们的根文件夹Projects/Pedestrian_Detection

更改我们根文件夹的路径

现在,我们可以克隆 TF Object Detection 的库,在本例中是 releaser 1 . 13 . 0

我为什么要使用这个版本?😄基本上,因为我已经测试了一些其他版本,但我发现了一些错误,这是我测试的第一个版本,它工作得很好。

一旦你克隆了这个库,你会在目录Projects/Pedestrian_Detection中看到一个名为Models的文件夹。

现在有趣的部分开始了!!

来自 TensorFlow 的家伙都是非常好的人,他们为我们提供了一个笔记本,让我们带您了解使用预先训练的模型来检测图像中的对象的过程(您可以在这里找到:Projects/Pedestrian_Detection/models/research/object_detection/colab_tutorials))。但是,我们将创建自己的笔记本,因为我们将学习如何实现新的可视化功能。

转到 Drive 中的Projects/Pedestrian_Detection/models/research/object_detection,在这个目录中创建一个新的 Google Colab。

首先是将 TensorFlow 版本设置为 1.x.

正如我们之前所做的,我们应该将我们的驱动器映像装载到 Google Colab 中,并转到Projects/Pedestrian_Detection/models/research/

安装驱动

正在将路径更改为。/模型/研究

我们将需要安装一些库,如Cython, contextlib2, pillow, lxml, matplotlib, pycocotoolsprotocbuf compiler

安装库

现在我们应该运行protoc compiler,这是一个用于序列化结构数据的 Google 库,由 TensorFlow 使用,可以想象为 XML,但是更小、更快、更简单。

协议已经安装在 Google Colab 中,但是如果你正在使用你自己的机器,你必须遵循 这些说明。

运行协议库

等等……协议做了什么?基本上,protoc已经为/models/research/object_detection/protos中的每个文件生成了一个 python 脚本。

太好了!!我们离✌️.更近了一点下一步非常简单,因为我们需要设置PYTHONPATH并使用setup.py.安装包

设置环境变量和测试 TensorFlow

最后,您应该会看到类似这样的内容:

当您意识到一切都已正确安装时…

等一下……我们需要一个模特,对吗? Yeep!我们需要下载一个预先训练好的模型,在这种情况下我选择了这个:SSD _ mobilenet _ v2 _ coco _ 2018 _ 03 _ 29因为它速度快(在一个实时应用中很重要),而且准确性很高。但是,您可以探索其他型号的性能,并为您的应用选择正确的型号。

如果一切正常,您将能够使用 TensorFlow 对象检测 API。下一步是导入我们将要使用的库。

导入库

目前,我们能够加载我们预训练的模型,我们只需要定义PATH_TO_FROZEN_GRAPH,它是我们模型的路径,以及PATH_TO_LABELS,它是标签的路径。

装载图

标签索引映射到类别名称,这样当我们的卷积网络预测1时,我们就知道这对应的是person。这里我们使用内部实用函数,但是任何返回将整数映射到适当字符串标签的字典的函数都可以。

沉住气…最重要的功能!

函数run_inference_for_single_image将图像和我们的模型作为参数,为我们的图像运行推理。该函数返回一个字典output_dict,其中包含图像中检测到的每个对象的坐标和标签。

为单个图像运行我们的模型

正如我们之前说过的,我们的模型将要预测任何包含在category_index中的物体。但是,我们只想特别显示一个类别:person。因此,我们创建了一个函数,根据一个 min_score标签 idcategories来过滤我们的预测。在这种情况下,人员标签id1。(这个我们可以在category_index查一下)。

用于过滤预测的函数

测量盒子之间的距离!🖼️

我们已经有一个运行推理的模型,它返回一个带有预测的字典output_dict。我们想要测量这些预测对象之间的距离,但这不是一个简单的解决方案。因此,我们创建了一些函数来计算每个预测盒的质心之间的距离。这些是步骤:

  • 使用函数calculate_coord获取每个对象的坐标。
  • 计算每个盒子的质心— calculate_centr

质心之间的排列

  • 我们应该使用calculate_perm计算质心之间所有可能的排列。
  • 用此函数calculate_centr_distance计算每个质心之间的距离(如person Aperson B)。
  • 最后,我们计算每个线段的中点,以便在图像中以文本形式显示距离— midpointcalculate_slope

显示和计算社交距离的功能

让我们把所有的东西放在一起!

现在我们已经定义了这些函数,我们可以创建名为show_inference的主函数,它将运行图像预测并显示行人之间的方框和距离。

该函数的第一部分负责获取图像和运行推理。我们将得到一个字典output_dict,里面有模型已经预测到的盒子。

image = Image.open(image_path)# the array based representation of the image will be used later
image_np = load_image_into_numpy_array(image)# Expanding dimensions 
# Since the model expects images to have shape: [1, None, None, 3]
image_np_expanded = np.expand_dims(image_np, axis=0)# Actual detection.
output_dict = run_inference_for_single_image(image_np, detection_graph)

然后,我们将设置confidence_cutoff=0.5以避免显示低精度预测。同时,我们将得到我们的图像的大小,我们需要设置一个关系“像素-米”来正确计算距离。我检查了一些图像,我认为width — 150px = 7 meters是一个很好的关系。这一部分很复杂,因为我们没有考虑视角或相机角度,这是一个很难解决的问题,我鼓励你改进它,并与我们分享你的解决方案😄。

# Get boxes only for person
confidence_cutoff = 0.5boxes, scores, classes = filter_boxes(confidence_cutoff, output_dict['detection_boxes'], 
output_dict['detection_scores'], 
output_dict['detection_classes'], [1])# Get width and heigth
im = Image.fromarray(image_np)
width, height = im.size# Pixel per meters - THIS IS A REFERENCE, YOU HAVE TO ADAPT THIS FOR EACH IMAGE
# In this case, we are considering that (width - 150) approximately is 7 meters
average_px_meter = (width-150) / 7

最后,我们可以为我们的预测计算所有的质心,并生成排列。然后,我们将能够创建连接质心和显示距离的线dx,dy

# Calculate normalized coordinates for boxes
centroids = []
coordinates = []
for box in boxes:
    coord = calculate_coord(box, width, height)
    centr = calculate_centr(coord)
    centroids.append(centr)
    coordinates.append(coord)# Calculate all permutations
permutations = calculate_perm(centroids)# Display boxes and centroids
fig, ax = plt.subplots(figsize = (20,12), dpi = 90)
ax.imshow(image, interpolation='nearest')for coord, centr in zip(coordinates, centroids):
    ax.add_patch(patches.Rectangle((coord[0], coord[1]), coord[2],       coord[3], linewidth=2, edgecolor='y', facecolor='none', zorder=10))
    ax.add_patch(patches.Circle((centr[0], centr[1]), 3, color='yellow', zorder=20))# Display lines between centroids
for perm in permutations:
    dist = calculate_centr_distances(perm[0], perm[1])
    dist_m = dist/average_px_meter    print("M meters: ", dist_m)

    middle = midpoint(perm[0], perm[1])
    print("Middle point", middle)    x1 = perm[0][0]

    x2 = perm[1][0]
    y1 = perm[0][1]
    y2 = perm[1][1]        slope = calculate_slope(x1, y1, x2, y2)
    dy = math.sqrt(3**2/(slope**2+1))
    dx = -slope*dy

综上所述,这就是这个功能的最终状态。

显示推理和距离的功能

加油!!…让我们运行一些示例!

完成所有这些工作后,我们能够生成一些示例图像。我们只需要把我们的图片添加到这个文件夹:../Projects/Pedestrian_Detection/models/research/test_images

哇!它看起来很好,但如果我们能在视频中运行它,它会更酷。所以,我们走吧!

视频中的推理

在视频中运行模型的代码与图像相同,因为我们使用openCV将视频分割成帧,并将每一帧作为单独的图像进行处理。

视频功能

正如我们之前所做的,我们只需要将我们的视频复制到../Projects/Pedestrian_Detection/models/research/test_images中,并更新cap = cv2.VideoCapture(…)中的路径。此外,我们可以为FILE_OUTPUT设置一个名称。

干得好!!代码现在已经可以预测和测量社交距离了。

我们开发了这个应用程序,因为在 免疫技术研究所 我们尝试应用最先进的技术。我们喜欢分享知识,因为我们认为这是它变得强大的时候。

如果你想学习如何开发真实世界的应用程序,比如这个用于测量、的应用程序,你可能会对我们的 数据科学硕士 e. 感兴趣。这是一个针对寻求专攻数据科学、了解主要人工智能技术以及如何将它们应用到不同行业的专业人士的计划。

如果您对我们的工作和工作方式感兴趣,请加入我们的 实时会议 。请随意使用我们的代码并对其进行改进。与我们分享成果!😄

本文及代码由:亚历杭德罗·迪亚斯·桑多斯——(LinkedInGitHub )为免疫技术研究所撰写。

用基尼系数度量统计离差

原文:https://towardsdatascience.com/measuring-statistical-dispersion-with-the-gini-coefficient-22e4e63463af?source=collection_archive---------20-----------------------

视频教程

这篇文章对基尼系数进行了全面的数学解释,并对婴儿名字和医疗定价进行了一些非标准的应用。

如果你处理数据的时间足够长,你一定会发现数据集的平均值很少能告诉你完整的数据故事。举个简单的例子,以下每一组人的平均工资都是 100 美元:

  • 100 个每人挣 100 美元的人
  • 50 个人每人挣 150 美元,50 个人每人挣 50 美元
  • 1 个人挣 10,000 美元,99 个人什么也没挣

当然,主要的区别是钱在人们之间的分配方式,也称为统计离差。也许最流行的统计离差度量是标准差或方差;然而,你可以利用其他指标,如基尼系数,来获得一个新的视角。

基尼系数,也被称为基尼指数或基尼系数,是意大利统计学家和社会学家科拉多·基尼在 1912 年提出的。历史上,分析师用这个值来研究收入或财富分配;事实上,尽管基尼系数是在 100 多年前发展起来的,但联合国仍然在他们的年度国家排名中使用基尼系数来理解货币不平等。但是基尼系数的应用范围可能更广!在更彻底的数学解释之后,让我们将基尼系数应用于几个不涉及国际经济的非标准用例:婴儿名字和医疗保健定价。

照片由 Janko Ferlič on Unsplash 拍摄。由作者裁剪和修改。

定义基尼系数

理解基尼系数的第一步需要讨论洛伦兹曲线,这是一种由马克斯·洛伦兹开发的用于可视化收入或财富分布的图表。要描绘洛伦兹曲线,首先要获取一个群体的收入,并将其从最小到最大排序。然后构建一个线图,其中x-值表示目前为止看到的人的百分比,而y-值表示归属于这部分人的财富的累积比例。例如,如果最贫穷的 30%的人口拥有 10%的人口财富,则曲线应通过缩放后的( x,y )坐标(0.3,0.1)。还要注意的是,如果财富在人口中平均分配,洛伦兹曲线遵循一条直线, x=y 。请参见下图,了解假设的洛伦兹曲线以及等位线的图示。

基尼系数衡量人口的洛伦兹曲线偏离完全平等的程度,或者一组数据偏离相等值的程度。基尼系数通常在 0 到 1 之间,其中

  • 零代表完全平等(例如,每个人都有相等的数量)
  • 一个代表近乎完美的不平等(例如一个人拥有所有的钱)

对于介于两者之间的所有情况,基尼系数 G 定义为

其中 A 表示完全相等线和洛伦兹曲线之间的区域,如上图所示,而 A+B 表示三角形总面积。

基尼系数通常介于 0 和 1 之间,其中 0 代表完全平等,而在数据中,1 代表接近完全不平等。

在引言中讨论的三种情况中,每种情况平均每人产生 100 美元。然而,如下图所示,每种情况下的基尼系数差异很大。

Python 中的 Gini

要用 Python 计算一个数据集的基尼系数,你可以选择用类似于scipy求积例程来计算阴影区域。如果这种类型的数值积分被证明对于大规模应用来说太慢或太复杂,你可以利用另一种选择,基尼系数的等价定义。

基尼系数也可以表示为数据的相对平均绝对差的一半,即数据集中所有观察值对的平均绝对差的归一化形式。

如果数据仅包含正值,计算将进一步简化,因为没有必要评估所有可能的对。将数据点按升序排序并分配位置索引 i 产生

计算起来更快。

我所发现的基尼系数的最佳 Python 实现来自于 Olivia Guest 。在接下来的案例研究中,我将利用她的矢量化例程来计算基尼系数。

案例 1:婴儿的名字

到目前为止,我们主要是在基尼系数最初的经济学领域的背景下讨论基尼系数。然而,这种度量是一般化的,以便在统计离差扮演关键角色时提供洞察力。我现在将举例说明两个非典型的应用程序,以展示如何使用基尼系数扩大探索性数据分析的工作流程。

美国社会安全管理局(SSA)保存了出于研究目的给美国婴儿取名字的公共记录。综合这些 1950 年以后出生的孩子的数据,我发现前 20 个最受欢迎的名字中有 18 个更常与男孩联系在一起。那么雌性在哪里?

每年实际出生的男婴略多,在社会保障署登记的男婴当然也更多(53%为男性,47%为女性);尽管如此,在我的快速人气排行榜上看到如此大比例的男性名字,我还是很惊讶。进一步挖掘数据,我发现尽管数据中出现的女性越来越少,但每年都有更多独特的女性名字。

统计离差似乎起着重要的作用。从经济角度来说,一些男性名字,比如我列出的前 20 名,非常“富有”(最流行的名字“迈克尔”占 1950 年以来出生的所有男孩的 3%以上。)这些超受欢迎的男性名字可能会代代相传。另一方面,女婴在各种名字中分布更广,所以多出来的名字分享了女婴的“财富”。我们可以通过回归基尼系数来验证这一理论。

想想女孩是如何分散在每个名字中的。自 1950 年以来,数据集中的一些名字只占 5 个婴儿,而“詹妮弗”代表了近 150 万个个体。统计自 1950 年以来出生时每个名字都有的所有女性,并从最不流行的名字到最流行的名字排序,我们发现基尼系数为 0.96,这意味着最流行的名字与最独特的名字之间存在巨大差异。

男性名字显示出非常相似的洛伦茨曲线,但稍微偏一点,基尼系数为 0.97。男性和女性系数之间的差异似乎无关紧要,但考虑另一种观点。不要累计时间,而是计算每个性别的年度基尼系数。绘制自 1950 年以来每年的女性和男性基尼系数表明了一个清晰而持久的模式,其中男性系数始终较高。因此,男性名字比女性名字经历了更多的统计差异。同样值得注意的是,自 20 世纪 90 年代以来,男女的基尼值都有所下降,这表明人们倾向于更多样化的命名习惯。

最后看一下这个数据集,让我们检查一下单个名字随时间的流行趋势。现在利用基尼系数,将女性数据按姓名分组,并计算基尼系数,因为它与年度频率有关;也就是说,对于任何一个给定的名字,按照该名字最不受欢迎的年份对数据集的每一年进行排序,以便计算基尼系数。基尼系数较低的名字在整个时间跨度内表现出相似的受欢迎程度,而系数较高的名字则意味着受欢迎程度不均衡。下图比较了“Scarlett”和“Miriam”这两个名字的流行趋势这两个名字代表了数据集中大约 60,000 名女性婴儿;然而,取名为“Scarlett”的婴儿数量的急剧增加产生了很大的基尼系数,而“Miriam”的基尼系数很低,因为自 1950 年以来,每年大约有 1000 个婴儿被冠以这个名字。

案例 2:医疗保健价格

现在转到由美国联邦机构医疗保险和医疗补助服务中心主持的 2017 年医疗保健定价数据集。这些数据作为单个医院的平均程序进行汇总,包括 500 多个医疗保险患者单独住院程序的费用和最终付款。我应用基尼系数计算来确定哪些程序(如果有的话)需要更好的计费标准化。我的分析的根本基础可以归结为:基尼系数越高,不同医院对特定手术收费的差距就越大。基尼系数较大的程序可能需要监管或更透明的成本细节。

dataset⁴基尼系数最高的程序或诊断相关组(DRG)被标记为“酒精/药物滥用或依赖 w 康复治疗”考虑到康复疗法在治疗时间和疾病严重程度方面有很大的不同,这也许并不令人惊讶;我们可能预计各类医院的收费会有很大差异。事实上,所有基尼系数最大的诊断,如凝血障碍和精神病,其严重程度都各不相同。另一方面,显示各医院之间最一致的程序性收费,大多描述一次性心脏事件,如瓣膜置换、经皮手术或胸痛观察。

那么计费监管呢?我们是否需要更多的保护措施来确保医院对类似的手术收取类似的费用?嗯,更高的成本透明度当然没有坏处,特别是对于持续时间或强度不等的治疗,但让我们回到数据集。除了关于医院收费金额的信息,数据还包含医院实际收到的总付款。对收到的付款进行同样的分析得出的基尼值要低得多。事实上,对于的每一个手术,平均收入的基尼系数低于医院费用。这种奇怪的见解表明,医疗保险支付合同已经为缓和和规范医疗费用做了很多工作。⁵

结论

基尼系数在诞生 100 多年后仍能提供真知灼见。作为一个很好的通用的统计离差度量标准,基尼系数可以广泛地用于探索和理解几乎任何学科的数据。目前,理解数据分布的最流行的度量标准可能是标准差;然而,标准差和基尼系数之间有几个关键的区别。首先,标准差保留了数据的规模。你用美元报告美国收入的标准差,而你可能用摄氏度给出温度的标准差。然而,基尼系数没有测量单位,也称为标度不变性。第二,标准差是无限的,因为它可以是任何非负值,但基尼系数通常在零和一之间。基尼系数的标度不变性和严格的界限使得比较两个不同数据源的统计离差更加容易。最后,标准差和基尼系数通过不同的透镜判断统计离差。如果一个非负数据集包含一个正的,其余为零,则基尼达到其最大值。如果一半数据位于极值最大值,另一半数据位于极值最小值,则标准差达到最大值。

尽管基尼系数有很多好处,但它也有一定的局限性。与其他汇总统计数据一样,基尼系数压缩了信息,从而丢失了原始数据集的粒度。基尼系数也是多对一的,这意味着各种不同的分布映射到同一个系数。基尼系数被证明对异常值非常敏感,以至于一个单一的极端数据点(大或小)可以显著增加基尼系数。然而,经济学家也批评基尼系数对上层和下层的财富变化不够敏感。研究人员继续引入几个替代指标来研究收入不平等的不同方面,例如帕尔马比率,它明确捕捉了人口中最富有的 10%和最贫穷的 40%的金融波动。

无论您选择哪种度量来理解统计离差,建立数据直觉肯定不仅仅是简单地估计平均值或中值。基尼系数,长期以来在经济学领域很流行,不管你选择的学科领域是什么,它都提供了关于数据分布的极好的洞察力。正如本帖所展示的,基尼系数可以随着时间的推移而被追踪,可以针对特定的数据段进行计算,也可以用来检测需要更好的价格标准化的过程。它的应用是无限的,它可能只是你的 EDA 工具箱中缺少的组件。

原载于 2020 年 6 月 5 日【http://kimberlyfessel.com】

在 GitHub 上查看这段代码!

脚注

基尼系数严格来说是非负的, G ≥ 0 ,只要假设数据的均值为正。如果一些数据值为负,基尼系数理论上可能大于 1,如果一些人以债务的形式负贡献,这种情况就会发生在财富的背景下。

出于隐私原因,社会保障管理局不包括每个州每个性别少于 5 个婴儿的名字;因此,自 1950 年以来,一个女性名字对应五个孩子是绝对允许的最低限度。

年度数字中显示的基尼值小于总数,因为流行的名字往往会年复一年地流行,从而加剧了命名的不平等,增加了基尼系数。

⁴一些诊断相关组全年只在一家医院出现。我已经将数据集过滤到至少 50 家医院记录的程序中,以避免高差异问题。

⁵:医院收到的费用远远低于他们收取的费用。降低一个数据集的平均值,同时保持其标准偏差不变实际上会增加基尼系数。在这里,我们观察到正好相反的效果,所以统计分散必须在收到的付款中减少。

参考

[1] " 谁,什么,为什么:什么是基尼系数?BBC 新闻:杂志监测。 (2015 年 3 月 12 日)。

[2] " 基尼不平等系数"StatsDirect。

[3] O. Guest, gini.py 。GitHub。

[4] " 超越前 1000 名"社会保障局。于 2020 年 6 月 5 日访问。

[5] R. Harris,“为什么出生的男婴比女婴多?NPR。(2015 年 3 月 30 日)。

[6]“2017 财年住院费用数据医疗保险和医疗补助服务中心。于 2020 年 6 月 5 日访问。

[7] E. Lamb,“问基尼:如何衡量不平等”《科学美国人》(2012 年 11 月 12 日)。

[8] S. S. Lee,基尼系数的魔力对标准化考试成绩不起作用 (2018),在美国教育研究协会(AERA)年会上提交的工作文件。

衡量 NBA 选秀中的成功

原文:https://towardsdatascience.com/measuring-success-in-the-nba-draft-a7f67cfb7718?source=collection_archive---------29-----------------------

找出过去十年中最好的(和最差的)起草团队

图像来源

注: 此分析的最新版本可在此处 获得。

选秀是每支 NBA 球队比赛中最重要的部分之一。除了几个大牌球队之外,在自由球员中吸引超级明星是很困难的,而且这样高水平的球员很少被交易(当他们被交易时,他们通常会带着巨大的价格标签)。对于许多球队来说,选秀是引进超级巨星的唯一可能。

然而,我们对起草的评价也是有缺陷的,而且很大程度上是轶事。在这篇文章中,我将尝试定量地衡量过去十年中每个团队和高管的效率。如果你想要完整的结果和排名,那么跳到文章的结果部分。然而,如果你只是想要 cliff-notes 版本,那么它看起来如下:

  • 多伦多和丹佛是最高效的起草团队
  • 孟菲斯是迄今为止最差的选秀,菲尼克斯太阳是倒数第二
  • 最佳选秀前三名分别是卡尔-安东尼·唐斯(第一名)、鲁迪·戈贝尔(第 27 名)和尼古拉·约基奇(第 41 名)
  • 三个最差的选秀权分别是托马斯·罗宾逊(排名第五)、哈希姆·塔比特(排名第二)和凯文·诺克斯(排名第九)
  • 最佳选秀执行官(目前活跃的)是蒂姆·康纳利(丹佛掘金)、丹尼·安吉(波士顿凯尔特人)、加尔·福尔曼(芝加哥公牛)和马赛·乌吉里(多伦多猛龙)
  • 最差的选秀高管(目前活跃的)是唐尼·尼尔森(达拉斯小牛)、弗拉德·迪瓦茨(萨克拉门托国王)和杰夫·韦尔特曼(奥兰多魔术)

方法学

首先,我必须承认激发这个分析的原始帖子。虽然这种方法非常有趣,但我选择对这种方法进行重大修改。

在这个分析中,我将涵盖 NBA 选秀的十年,从 2018 年的选秀(我选择放弃 2019 年,因为这些球员在联盟中不到一年)到 2009 年的选秀。为了衡量每个玩家的成功,我选择了赢股指标。虽然任何指标都是不完美的,但 Win Shares 试图用一个数字来捕捉球员的影响,同时也衡量进攻和防守。

这种分析的指导原则是总经理只能选择当年在选秀位置上的球员。换句话说,在给定其他选择的情况下,每位总经理的表现如何?

例如,一个球队可能会先选中一个球员,这个球员对一个典型的第一选秀权的高期望感到失望。然而,前几年的第一次选秀权表现如何并不重要,更重要的是那支球队是否错过了更好的球员。

有些人会争辩说位置问题值得考虑(例如,警卫与警卫进行比较)。我不相信他们在大多数情况下;今天,NBA 的名单是如此的不稳定,以至于球队很少根据位置的需要进行选秀。大多数团队几乎只选择他们认为最优秀的人才。

考虑到这一点,这种方法将衡量每个被选中的球员和在他们之后被选中的球员的成功。这是因为在这个位置上,紧随其后的球员最有可能被认为是备选的选秀人选。球员被选中的位置越远,他们被给予的权重就越小,因为他们不太可能被认真考虑。

为了分配权重,我决定使用一个基本的指数函数:

e𝒹= k * w𝒹+₁+(1-k) e𝒹+₁*

在这个等式中, E 表示在𝒹.的草稿位置的预期 win 份额 K 是平滑因子,介于 0 和 1 之间。较高的 K 对较近的拔模位置赋予较大的权重。w 代表处于选秀位置𝒹 + 1 的玩家(该玩家直接在该玩家之后被选中)的实际获胜份额。

值为 1 的 K 会将整个权重分配给下一个被选中的玩家。首先,我将把 K 值指定为 0.5。在此平滑因子下,分配的权重计算如下:

为了形成选秀位置的预期获胜份额,直接在之后被选中的玩家将被加权 50%,在两个位置之后被选中的玩家将被加权 25%,等等。球员们选了 7 个位置,后来在选秀的底部贡献了 1.56%。

为了初始化指数函数,我给最后一个拔模位置(#60)分配了一个零值。虽然这种选择有些武断,但我相信这是很容易证明的。第二轮选秀权的期望值通常很低。自 2005 年联盟扩大到 60 支球队以来,已经有 15 名球员入选 60 强。其中七人从未在 NBA 打过球,而另外三人打了几场比赛,赢得 0.0 或以下的胜利份额(因为一名球员实际上有可能拥有负的胜利份额)。在剩下的五家公司中,有四家公司的股价在 0 到 2.4 韩元之间(伊塞亚·托马斯是一个巨大的例外)。零赢份额似乎大致代表了大多数第 60 次整体选择的表现。

总的来说,预期的盈利份额形成了一个反事实的场景,我们可以用它来比较实际的表现。

净评级=实际-预期

然后,如果实际表现超过预期表现(一个积极的净评级),那么草案选择是一个好的。如果净评分是负的,那么选秀就是一个糟糕的选择(因为更好的球员马上就可以得到)。

从这里开始,每个球员的净评分将除以该选秀年度的评分标准偏差,从而得出最终得分。完成这最后一步是为了防止较老的选秀选择获得更高的分数(因为他们有更多的时间赢得 Win Shares)。

得分=净评分/标准差

所有数据直接取自篮球参考。做了一些小改动;例如,当技术上起草他们的团队立即将他们交易走。在这项分析中,在选秀之夜结束时,球员被认为是被他们所属的球队选中的。

敏感性分析

该方法确实包括一个有点随意的值:T4 K T5 值(平滑因子)。如前所述,较高的 K 将较大的重量放在较近的镐上,反之亦然。因此,我进行了敏感性分析,以了解不同的K-值会如何影响结果。虽然该方法最初使用的值是 0.5,但是我也在 0.4 和 0.6 测试了 K。然后,我从这三个结果中取出每个团队的最大值和最小值,以确定它们之间的差异。如果差异很小,这表明他们的分数相对来说不受改变 K 的影响。如果差异很大,那么就给了我们更多不确定性的理由。

这些结果如下所示:

绿色表示受改变 K 影响最小的分数;这些是我们最有信心的分数。印第安纳、波特兰、华盛顿、新奥尔良等球队变化很小。红色表示对变化的 K 高度敏感的分数。这些是不确定性最大的分数。

在大多数情况下,差异较大的团队的分数会随着较低的 K 而提高。这可能表明他们做出了 1-2 的选择,在表现非常好的球员之后直接选择。波士顿是个例外——他们的分数在更高的 K(T21)时有所提高。这可能表明波士顿受益于紧随其后的表现不佳的球员。

平均相差 0.7 左右。与此同时,在下面的排名中,团队之间的平均差异约为 0.65——这意味着改变 K 值可能意味着大多数团队最多上升或下降 1-2 位(或者可能根本不变)。

虽然有几个团队有一些不确定性,但结果在很大程度上是稳健的。

方法论缺陷

这种方法的一个问题是,它可能对第二轮选秀权不太准确。高管们通常会在顶级选秀中找到大量的一致意见(例如,通常不超过几名球员被认为是潜在的第一选秀权)。

第二轮选秀权不太确定。对于一个分析师来说,一个球员在第 40 顺位被选中并不罕见,而另一个分析师认为他们将不会被选中。在另一种分析中,在后面的拔模位置(特别是在第二轮)使用较低的 K 可能是理想的。

结果

这项分析总共研究了 600 份草稿。

前五名选秀

根据这个分析,卡尔-安东尼-唐斯是最好的选择,尽管他是第一选秀权。这是最大的,因为他身后的两名球员(安杰洛·拉塞尔和贾利尔·奥卡福)的表现相对较差。

底部 5 个选秀权

前四选如预期;高彩票选秀权在 NBA 产生很少或没有价值。根据这一分析,最差的选择是托马斯·罗宾逊。年度最佳新秀和 5 次全明星达米恩·利拉德紧随其后被选中,这让罗宾逊很受伤。

一个反常的是梅尔文·弗雷泽,他在 2018 年被选为第 35 名。虽然弗雷泽在 NBA 打得很差(-0.1 胜),但这对于第二轮选秀权来说并不罕见。弗雷泽很受伤,因为米切尔·罗宾逊是在他之后被选中的。很可能在一个较低的 K 值下,这个选择看起来不会那么糟糕。2018 年草案相对较小的样本量也很有可能给出一些不寻常的结果,这些结果不会随着时间的推移而保持不变。

团队排名

按团队细分,结果如下:

丹佛掘金是最有效率的起草团队,多伦多猛龙紧随其后。与此同时,孟菲斯灰熊队以相对较大的优势成为最差的选秀球队。

高管排名

在所有高管(在职和不在职)中,最好的是蒂姆·康纳利(来自丹佛)。两位高管的表现比其他人差得多:底特律活塞队的杰夫·鲍尔和孟菲斯灰熊队的克里斯·华莱士。

在被分析的仅有的现任高管中,排名如下:

衡量各国对呼吸道病毒大流行的易感性

原文:https://towardsdatascience.com/measuring-susceptibility-to-respiratory-viral-pandemic-across-countries-d016d4099f9d?source=collection_archive---------52-----------------------

走向数据科学(现实世界中的数据科学)

Covid19 之前是否缺少准确的风险评分?

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

自文明出现以来,世界经历了许多流行病的爆发,往往因不健康的生活条件而加剧,这些条件允许通过病媒、空气、水、体液、粪便或不卫生的畜牧业进行广泛传播。虽然医疗保健的复杂性是这种流行病扩大的一个缓解因素,但世界的相互联系增加了它们成为疫情的可能性,从而大大放大了其风险。每一次疾病爆发都需要根据传播方式、受影响的身体部位和脆弱人群采取不同的应对措施。

自过去 150 年以来,已经发生了无数次呼吸道病毒疾病的大流行和爆发(1889 年、1918 年、1957 年(H2N2)、1968 年(H3N2)、2002 年(SARS)、2009 年(H1N1)、2012 年(MESR)等。在这项研究中,我们将通过考虑加剧社区传播的因素(疾病的传播率)来研究国家对呼吸道病毒疫情的易感性。(本文将引导您创建一个综合指数,以衡量国家对呼吸道病毒疫情的易感性,即该国面对这种疾病在其人口中快速传播的脆弱性)。想法是 1)能够将如此分析的易感性与目前处理新冠肺炎的国家的表现进行比较(当我们知道一些国家比其他国家更脆弱时,谨慎的做法是根据其风险评估其表现;有些国家已经能够控制病毒,可能是因为他们一开始接触的风险就很低);2)为进一步纳入参数提供参考,以便更准确地捕捉脆弱性,并纳入更多类型的流行病,其中传播方式和对健康的影响各不相同;3)能够尽可能研究增加风险的因素。

应当指出,早些时候已经尝试过制定疫情备灾指数。大多数此类指数本质上是一般性的(就流行病准备而言),集中于卫生管理的效率,包括官僚机构的效率和充足资金的可用性。在这项研究中,我们还将考虑使一些国家比另一些国家更容易受到影响的天气特征、连通性和人口特征。提出了一个月或一组月的滑动指数,以说明全年的可变性。

数据建模:

精确的数据建模需要一个完善的理论框架。正在创建的综合指数必须足够全面,以包括各种感兴趣的因素,同时排除那些会导致不准确或数据冗余的因素。由于我们在衡量一个国家对病毒性呼吸系统疫情的易感性,因此我们考虑了导致疾病传播的主要因素。

类别和指标

出于本研究的目的,建议的敏感性指数考虑了 5 个类别,每个类别都有一套指标。这五个类别是:

a)人口特征:人口密度被视为促成病毒流行病传播的因素。此外,重要的是家庭规模,可以加剧由于共享空间的事情。掌握该国的人口密度也是相关的——有多少人口生活在高密度地区,因此更容易受到社区传播。考虑到上述情况,这一类别的指标是:

-城市人口(占总人口的%)

-人口密度

-家庭规模

(数据取自世界银行数据库和联合国人口司-经济和社会事务部)

b)连接性:一个与全球不同地区相连的国家,病毒通过外国来源进入其边境的风险更高。此外,国内发达的交通系统增加了传播率。这些都是借助于以下指标来说明的。

-每个居民(该国总人口)到达(国际旅游)的人数

-贸易和运输相关基础设施的质量(物流绩效指数)

(数据来源于世界银行。要注意的是,理想的连通性应该已经通过分析空中交通数据而被捕获。由于这一数据不易获得,因此采用了一种更简单的衡量标准。)

c)天气特征:对流感和呼吸系统疾病的研究发现,它们与温度、湿度和温度的昼夜变化有关联。由于湿度数据很难获得,考虑到高度的相关性,降雨量在这里被用作一个近似的替代品(替代物)。

这一类别的指标是:

-平均温度(三月至五月)

-平均温度日较差(3 月至 5 月)

-平均降水量(3 月至 5 月)

为了收集天气数据,设计了一个刮刀,以获取所研究国家最大城市的温度和降雨量数据。(很难获得按月份分列的国家气象数据。最大的城市非常容易受到流行病的影响,这是一个很好的代表。)

数据取自每个国家最大城市的 https://en.climate-data.org/。python 中实现的 scraper 如下:

f1=open('CityNames.txt','r')
storeMessages=open('messages.txt','w')for line in f1 : 
        city=line.rstrip('\n')
        try:
              #Setting up Chrome webdriver Options
              chrome_options = webdriver.ChromeOptions()#creating Chrome webdriver instance with the set chrome_options
              driver = webdriver.Chrome(chrome_options=chrome_options)
              link = "[https://en.climate-data.org/](https://en.climate-data.org/)"
              driver.get(link)
              sleep(10)
#Click on the search bar, enter city name, press enter xpath0="//*[[@id](http://twitter.com/id)='search-form-header']"

              element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH,xpath0)))
#              element = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, xpath0)))
              sleep(10)
              element.click()
              sleep(5)#              driver.find_element_by_css_selector('#search-form-header').clear()
              driver.find_element_by_xpath('//*[[@id](http://twitter.com/id)="search-form-header"]/input').send_keys(city)
              driver.find_element_by_xpath('//*[[@id](http://twitter.com/id)="search-form-header"]/input').send_keys(Keys.RETURN)
              sleep(5) xpath2="//*[[@id](http://twitter.com/id)='article']/section[1]/ul/a/div/div[2]/span[1]"
              element = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH,xpath2)))
              element.click()
              sleep(5)
#Copy the weather table in a csv file with city as its name fileName=city+".csv"              
              f = open(fileName, "w",newline='')
              writer = csv.writer(f)
              table = driver.find_element_by_css_selector("#weather_table")
              with f as csvfile:
                       wr = csv.writer(csvfile)
                       for row in table.find_elements_by_css_selector('tr'):
                              wr.writerow([d.text for d in row.find_elements_by_css_selector('td')])

              f.close()
              driver.close() except NoSuchElementException:
              print("No element found for "+city) 
              driver.close()#compile all csv files into one file

d)医疗保健:一个拥有强大医疗保健系统的国家可能会更好地应对疫情恐慌。(当保健能力薄弱时,疾病的传播速度就会加快。)这种稳健性通过以下指标体现:

-人均国内一般政府卫生支出,购买力平价(当前国际美元)

医院床位(每 1,000 人)

-2007-2013 年医生(每万人)

数据取自世界银行和 WHO⁴.

e)治理的功效:治理的质量及其促进者将对与任何疾病传播相关的风险产生负面影响。使用了两个指标来帮助在疾病传播时政府沟通的有效性。在这一类别下,使用了以下指标。

  • effectiveness⁵政府
  • 移动电话用户(每 100 人)
  • 至少使用基本卫生服务的人(占人口的百分比)

缺失数据插补:

数据可能以随机或非随机的方式丢失。在这两种情况下,由于信息丢失和可变性降低,缺失数据可能会造成问题。在数据以非随机方式丢失的情况下,偏差可能会影响结果。

缺失数据的处理方法是要么完全删除案例,要么进行单次/多次插补,其中遵循一种算法来估计与缺失数据最接近的值,同时保持完整数据集的可靠性。(有用于输入缺失数据的数学软件包(如鼠标等)。))

这里,为了输入缺失的数据,采用了最近一年(十年期内)的数据,该数据适用于该国。例如

这是世界银行的入境人数数据。可以看出,在喀麦隆,由于没有 2018 年的数据,保留了 2017 年的数据。

作者图片:缺失数据插补

上面是用 excel 中的 as 数组公式完成的。(从左向右时,它保留第一个非空白单元格。)

{=INDEX(range,MATCH(FALSE,ISBLANK(range),0))}

当此类调查没有发现任何数据时,该国将被从研究中剔除(也称为完全案例分析)。这项工作后的数据集有 130 个国家。为了了解这 130 个国家是否有足够的多样性来建立一个综合指数,我们做了一个快速分析。为此,这些国家按照收入类型和地理位置进行了划分。总体来看,数据集足够多样化。

作者图片:国家概况

多变量分析和标准化:

为了开发一个综合指数,多变量分析对于研究指标之间的相互关系变得至关重要。由于该指数正在发展成为一个尺度,指标之间的相关性变得相关,因为高相关性将导致类似因素的权重更大,从而扭曲最终得分。

由于指标具有不同的度量单位和标度,因此进行标准化是为了确保指标具有相同的范围[0,1]。(如果有异常值会扭曲转换后的指标,就要小心了。)这里,考虑到指标与被调查风险的关系,对指标进行了标准化。对于反向相关的指标(如平均温度、卫生支出等。),Var 归一化=(varₘₐₓ−varᵢ)/(varₘₐₓ−varₘᵢₙ)被使用。这样做是为了当指标值以正权重汇总时,每个类别的风险都得到适当考虑。

相关分析在 r。

library("Hmisc")
library(dplyr)df<-read.csv("data.csv",header = T)my_data<-select(df, avg_temp:sanitation_level)
res2 <- rcorr(as.matrix(my_data))

相关矩阵如下:

作者图片:相关矩阵

进行了相关性检查,以确保指标没有强相关性(此处阈值为 0.9,在这种情况下,指标将被重新考虑或从研究中删除)。没有发现如此强的相关性。

还进行了主成分分析,以评估不同指标之间的关系。这在 r 中实现了。

library(dplyr)
df<-read.csv("normalizeddataPCA.csv",header = T)
my_data<-select(df, avg_temp:sanitation_level)
pca_all<-princomp(my_data,scores = TRUE, cor=TRUE)
loadings(pca_all)

作者图片:PCA 结果

各组成部分之间的差异比例相等,表明这是一套相当独立的指标。

重量测定:

存在许多加权技术(如因素分析、联合分析、层次分析法等)。).通常,权重是在与主题专家进行调查后确定的(参与式方法)。最终,这些都是价值判断。

通常的做法是采用平均加权方案。这就是这里所做的,但治理效率类别除外(原因是政府效率是主要指标,而移动电话和卫生水平是增强政府能力的辅助手段)。

加权方案如下:

作者图片:类别和指标的权重

(理想情况下,在这些步骤之后,进行敏感性和不确定性分析以评估模型误差。这是为另一篇文章保留的:-))

结果:

获得分数并标准化。世界地图上标出了国家对呼吸道病毒疫情的易感性。

作者图片:风险评分

通过网站https://www.endcoronavirus.org/countries,获得了各国截至 2020 年 5 月 31 日的表现,并绘制在世界地图上。

作者图片:新冠肺炎之后的国家表现

作者图片:风险最高和最低的前 20 个国家

用 R 创建地图的代码是:

library(ggmap)
mapData<-read.csv("CountryPerformance.csv", header = T)WorldData=map_data("world")combined_data<-WorldData[mapData$Country %in% mapData$Country, ]
combined_data$value<-mapData$Performance[match(combined_data$region,mapData$Country)]ggplot(combined_data, aes(x=long, y=lat, group=group,fill=factor(value)))+
  geom_polygon(colour="black")+
  scale_fill_manual(values = c("Orange","Red","Green"))+
  theme_bw() +
  labs(fill="Country Performance", x="",y="")+
  scale_y_continuous(breaks = c())+
  scale_x_continuous(breaks = c())+
  theme(panel.border=element_blank())

观察:

可以观察到,三个月后疫情疫情的易感性特征和表现并不完全相关(从某种意义上说,那些看似风险较低的国家被发现在努力遏制病毒)。可能的原因有:

  • 指标、类别及其权重需要进一步微调,以准确捕捉呼吸道病毒疫情的风险暴露。当在综合指数中考虑不同的维度时,这是一个问题。例如,更高的医疗保健和政府能力可能会超过对国家高度连通性的补偿(从而降低高收入经济体的风险。)[建议阅读:Munda & Nardo,2007 年,国家排名的非补偿/非线性综合指标:一个可辩护的设置]。综合指数也可能遗漏了戴面具等社会和文化习俗。会对脆弱性产生影响。
  • 此外,有可能一些国家尽管风险较低,但没有及时做出决定,如强制实施封锁,从而加剧了问题。

该研究旨在探索量化各国对特定类型病毒性疫情的易感性的可能性,并评估一个国家对其风险暴露的反应。还建议对每个国家不同类型灾害的风险状况进行分类(细分),以确定减少每种灾害风险所需的优先事项和努力规模。

参考资料:

1:奥本海和其他流行病:风险、影响和缓解(2017 年);2019 年全球健康安全指数

2:没有与主题专家讨论类别和指标。

3:中国马悦凌等 2020 年武汉气温变化和湿度对新冠肺炎死亡的影响

4:https://apps . who . int/iris/bitstream/handle/10665/170250/9789240694439 _ eng . pdf;jsessionid = 07 c 6d 43 dbb 1972 a3 b 7 a 98 CBA 7a 857 B1 d?sequence=1

5:了解对公共服务质量、公务员质量及其不受政治压力影响的程度、政策制定和执行的质量以及政府对此类政策承诺的可信度的看法。

ROC 曲线的力学

原文:https://towardsdatascience.com/mechanics-of-the-roc-curve-83b10ce3887f?source=collection_archive---------52-----------------------

研究 ROC 曲线如何工作的直观仪表板

里奇·卡拉瓦拉在 Unsplash 上的照片

基于手头的任务,预测模型可以分为两类,即分类器和回归器。回归模型旨在预测连续结果,而分类器旨在预测离散结果。

在回归模型中,如果结果的分布是偏斜的,它会抛弃一些模型。例如,使用线性回归来预测偏态分布会降低模型的性能。在线性回归的情况下,这种情况会发生,因为它违反了我们关于正态分布噪声的假设(您也可以考虑受一些“异常值”结果影响并阻碍学习过程的潜在损失函数;为了应对这种情况, Huber 回归可能会有所帮助,因为潜在损失不会受到偏斜度的太大影响。).处理这种现象的一种方法是使用不同的模型,如决策树,g 一般化线性模型等。本质上,结果分布在数据建模中起着重要的作用。

与连续结果情况类似,离散结果(分类)也有类似的不平衡结果计数问题。例如,假设我们试图对一个数据集建模,其结果是 1/0 的形式。例如,1 可能表示信用卡欺诈。大多数人不会犯欺诈罪,所以在这种情况下,计数会向 0 的方向倾斜。在这篇论文中,他们引入了 ROC 曲线,作为一种工具,用于比较不同分类器的相对性能。这个工具正是受处理不平衡数据集问题的启发。这篇论文是深入理解 ROC 曲线概念的有趣读物。

在这篇文章中,我将尝试进一步解构 ROC 曲线的概念,并希望给你一个关于这些东西如何工作的直觉。我将使用 PIMA 糖尿病数据集来研究 ROC 曲线。我将从描述问题开始,说明为什么使用简单的准确性度量是一个糟糕的选择,最后,介绍一个仪表板来查看运行中的 ROC 曲线。

问题是

该数据集包含以下预测因子:妊娠次数,血糖浓度。、血压、皮褶厚度、血清胰岛素、身体质量指数、糖尿病谱系函数值、年龄。这些是诊断测量,目的是建立一个预测模型,对患者是否患有(1)糖尿病(0)进行分类。在数据收集过程中,设置了几个约束条件。例如,数据集中的所有患者都是至少 21 岁的女性。由于这种限制,并基于各种预测值(就其物理意义而言),我们可能需要在将该数据集用于某些模型(如线性回归)之前进行一些预处理。此外,数据集也有一些缺失值。为了保持本文简洁,避免偏离讨论的主题,我不讨论数据预处理步骤。你可以在这里找到更多的信息。

假设我们进行了适当的预处理,让我们看看结果变量的计数。我们可以在图 1 中观察到,计数偏向于标签 0,即与糖尿病患者相比,没有糖尿病的患者数量要多得多。

图。1(左)。响应变量直方图。患者总数为 768 人;500 名患者没有糖尿病(0),268 名患者有糖尿病(1)。图。2(右)一个表格,描述了我们的预测模型中的分类可以达到的级别。

分类器的准确度被定义为它执行的所有分类中正确分类的数量。用技术术语来说,每当一个分类者进行分类时,它可以落在图 2 中四个框中的任何一个中。例如,这是我们如何读取单元格“FP”的表格:对于特定的分类,我们看到标签为 0,但分类器将其预测为 1,即预测模型预测一个没有糖尿病的人患有糖尿病,这解释了为什么它被称为假阳性(FP)。精确度定义为:

构建一个相当准确但完全无用的分类器非常容易。例如,我们可以使用数据集中的类频率构建一个随机分类器。真阴性(非糖尿病)的比例为 768 分之 500。在预测时,该随机分类器以 500/768 或 0.651 的概率预测一个人没有糖尿病。所以,这个分类器的准确率是 65.1%!但是,我们知道这在实际应用中完全没有用。显然,在我们对预测模型的准确性评估中,有一些缺失。直观地说,准确性关注的是模型能够捕捉的实际真值(即 TP 和 TN)。然而,在图 1 中,我们看到计数是偏斜的。因此,考虑到模型做出的错误预测(即 FP 和 FN)也是有意义的,因为错过更罕见事件的实际成本可能会高得多(随着计数偏斜度的增加,这可能会进一步增加)。

到目前为止,我们已经说服自己,评估预测分类模型的常用方法(即基于准确性)似乎不适用于不平衡的数据集。ROC 曲线是帮助我们做到这一点的一个工具。

ROC 曲线

ROC 曲线,顾名思义,是真阳性率(TPR)和假阳性率(FPR)之间的图形。这些被定义为,

让我们试着理解这些术语,然后看看为什么 ROC 曲线可能是一个好的选择。让我们从分母开始。注意,TPR 和 FPR 中的分母分别是实际正和实际负(正指标签 1,负指标签 0,类似于图 2)。例如,根据图 2(见上图),我们知道糖尿病患者可以通过模型预测为糖尿病患者(TP)或非糖尿病患者(FN)。因此,TPR 表示所有阳性标签中真正阳性(由模型预测)的比例。类似地,FPR 指出了假阳性(由模型预测)在所有阴性标签中的比例。这里要注意的关键点是,这两个量是在更细粒度的水平上看分类器的预测。我们也可以用类似的方式解释这两个量的补数。TPR 的补充将是 FNR(假阴性率),对于 FPR,它将是 TNR(真阴性率)。TPR 也叫灵敏度,1-FPR 叫选择性。所以,我们也可以说 ROC 曲线是灵敏度 v/S1-选择性的曲线图。

顺便提一下,灵敏度(TPR)和选择性(1-FPR)也可以解释为条件概率。例如,敏感度是将数据点(在 PIMA 数据集中带有正标签)分类为正的概率(请注意,分母 TP+FN 是真正标签为 1 的数据点,TP 是数据集中实际的正标签)。用数学术语来说,这就是灵敏度和选择性的定义,

这正是一个条件概率描述。这里,sₒ是一个阈值,其使用如下:如果我们的分类器的分数高于阈值(sₒ),那么它被分类为正标签(1),否则为负标签(0)。敏感性和特异性这两个术语在医学中被广泛使用,从疾病的角度思考这些定义会使它们更加直观:通过 PIMA 糖尿病数据集,我们的目标是建立分类模型,可以识别糖尿病患者和非糖尿病患者。因此,敏感度定义了我们的模型(/test)正确识别糖尿病患者的能力。类似地,特异性定义了我们的模型(/test)在检测非糖尿病患者方面的特异性(通常,在疾病的情况下,未患病的患者数量比患病的患者数量多得多)。

现在,让我们观察 ROC 曲线所在的平面,获得一些直觉。虚线表示随机分类器,其中 TPR = FPR。

图 3。ROC 曲线所在的平面。注意,根据 FPR 的定义,TPR ∈ [0,1]。

原因是基于先前(来自训练集)类别频率的随机分类器将在平均时获得相似的条件频率,因此等于 TPR 和 FPR。假设正标签和负标签的先验类别比例分别为α和 1- α。基于此的随机分类器将平均预测样本的α分数为糖尿病。这也意味着在所有糖尿病患者的样本中,它将平均预测α部分患者为糖尿病,这表示敏感性为α。使用类似的论证,我们可以说选择性是 1-α,这意味着 FPR 是α。因此,线 TPR=FPR 实际上代表一个随机分类器。

通过观察曲线中的极值点,我们可以获得一些进一步的直觉。左下方的绿点(FPR=0 且 TPR=0)表示具有 0 灵敏度和 1 选择性的分类器,即它在识别非糖尿病患者方面非常好,而在识别糖尿病患者方面非常差。另一方面,右上角(FPR=1 和 TPR=1)表示分类器确实擅长识别糖尿病患者,但不擅长识别非糖尿病患者。换句话说,分类器是超级敏感的,代价是没有选择性。最后,左上角(FPR=0 和 TPR=1)代表一个理想的分类器:它具有完美的灵敏度(=1)和完美的选择性(=1)。

用类似的方法,我们可以比较标记为红叉的两个分类器。与右侧相比,左侧具有更好的选择性和更差的灵敏度。一般来说,我们的目标是建立一个尽可能靠近左上角的分类器。

ROC 曲线仪表板

现在,我们可以看到真正的 ROC 曲线了。为了澄清我在敏感度和选择性的定义中提到的关于分数的任何混淆,在我们给预测分配标签之前,这些可以被认为是值。例如,在逻辑回归模型中,它是数据点的对数优势值。通常,使用 0.5(概率)的隐含阈值(在我们的头脑中,或在纸上)。在对数赔率的上下文中,这基本上意味着我们正在选择可能性更大的事件(记住,对数赔率是事件赔率的对数比)。就像我们之前看到的,有时候这个阈值 0.5 不是一个好主意(准确性),我们需要一个更好的阈值。ROC 曲线正好帮助我们做到了这一点。事不宜迟,这里有一个仪表板,您可以使用它,让这些事情变得更加直观。

你可以在这里找到这个仪表盘的 Jupyter 笔记本。运行笔记本中的所有单元格后,仪表板会弹出。dashboard 使用 Plotly 和 Python 小部件,这使得将它直接嵌入到 medium 上有点棘手。

在离开仪表板之前,让我说几句如何解释仪表板。在顶部,您可以找到两个阈值滑块,用于控制逻辑回归和随机森林的阈值(在灵敏度和选择性定义中定义)。左上角的图是使用逻辑回归模型生成的分数的逻辑分布。我已经将它包含在仪表板中,以使事情更加清晰。但是,在随机森林的情况下,分布的函数形式是未知的,这就是为什么省略随机森林情况下的分布。接下来,在它的右边,我们有一个模型和标记的 ROC 曲线图,显示了阈值的当前值。随着滑块的移动,标记在各自的 ROC 曲线上移动。

下面,我们有两个模型的条件概率分布,即以分类器知道预测的标签为条件。例如,假设分类器预测一个人是糖尿病患者,以 Pred=1 为条件的概率定义了一个人是糖尿病患者(TP)还是非糖尿病患者(FP)的概率。换句话说,底部的两个图给了我们一个互补的视角,当阈值变化时会发生什么。请注意,敏感度(和选择性)是条件概率,条件是知道数据点的真实标签是 C=1(或 C=0)。

这里您可以注意到的一个有趣的事情是,对于一个特定的模型(和超参数值),ROC 曲线是固定的,改变阈值有助于我们进一步调整模型,以更好地与手头的业务目标保持一致(考虑灵敏度和选择性)。通常,使用交叉验证来选择阈值。

数据集分析和准备

原文:https://towardsdatascience.com/medcat-dataset-analysis-and-preparation-be8bc910bd6d?source=collection_archive---------37-----------------------

来自 MIMIC-III 数据集的电子健康记录(EHR)的绘图、统计和预处理。

探索中的猫照片由克里斯蒂安·霍尔默 (CC 2)拍摄

在进行任何类型的机器学习时,最重要的步骤之一是理解数据集,并确保我们想要实现的目标实际上是可能的。因此,在继续我们分析年龄和疾病之间联系的主要目标之前,我们将首先在 MIMIC-III 数据集上显示一些基本的统计信息,并为接下来的步骤准备 EHR。

请注意:(1)要重现本教程中的结果(图像),您需要访问 MIMIC-III,但我知道这可能会很麻烦,我已经在资源库中创建了两个虚拟 CSV 文件。这两个 CSV 文件模拟了我们使用下面的 SQL 脚本从 MIMIC-III 获得的两个文件。这不是真实数据,只能用于测试 MedCAT 或学习如何使用它。(2)我将展示 MIMIC-III 数据集的图表和统计数据。

进入 MIMIC-III

获得 MIMIC-III 并不太难,你可以在这里提交申请通常几天后他们会批准你的申请。

一旦你进入 MIMIC-III,你就可以从他们的网站下载完整的数据集。最初,文件是 CSV 格式的,我决定将它们导入到 PostgreSQL 数据库中,以使探索阶段更容易一些(您可以直接从 CSV 文件中做任何事情)。Physionet 提供了如何将 MIMIC-III 导入 PostgreSQL 数据库的教程,链接。在我的例子中,我不得不稍微修改脚本来使它工作,并且在不使用 Makefiles 的情况下运行它们,这仍然是一个相当顺利的过程。

准备用于分析的数据

我们将所有内容导入 PostgreSQL 的原因是,我们可以更容易地从数据集中查看、过滤和选择需要的内容。 MIMIC-III 有大量的表格和信息,但我们感兴趣的只有两个:noteeventspatients

noteevents —包含患者 EHR 的书面部分有关noteevents表的更多信息可在 MIMIC-III 网站上找到。在这个表中,我们只对 4 列感兴趣: subject_id (患者标识符);chartdate(创建注释的日期);category(注释的类型,例如护理)和文本(注释的文本部分)。用于提取所需信息的 SQL 脚本如下(使用 save to CSV 选项,或使用 Python 创建 CSV):

**SELECT subject_id, chartdate, category, text FROM mimiciii.noteevents**

patients —包含患者的基本结构化信息。再次,更多关于 MIMIC-III 网站。从这里我们取三列: subject_id (患者标识符)性别(男或女) dob (出生日期)。SQL 脚本:

**SELECT subject_id, gender, dob FROM mimiciii.patients**

请注意:(1)MIMIC-III 中的日期被随机移至未来(好消息是,对于一名患者,所有日期都使用相同的随机数进行移动)。(2)MIMIC-III 中有大量的noteevents,CSV 约为 3.9GB。

数据集的基本统计数据

谷歌 Colab

患者表上的统计数据

图 1:MIMIC-III 患者的性别分布。

稍后,我们将根据性别对患者进行分组,以显示女性和男性之间的一些差异。因此,我们想检查我们的数据集是否平衡。在图 1 中,我们可以看到男性患者比女性患者多,但这并不重要(至少对于我们的用例来说不是)。从数字上看,共有 46520 名患者,其中 20399 名为女性,26121 名为男性。noteevents表中患者数量略有不同;不是所有的病人都有临床记录。

单独给出这个表无法做任何其他(有用的)事情,让我们首先检查noteevents表中的几件事情,然后我们将结合这两个表并绘制与年龄相关的统计数据。

noteevents 表上的统计信息

noteevents表中,我们想要检查临床记录的长度(字符数),这不是绝对必要的,但是知道我们在处理什么是很好的。图 2 的左侧显示了一些非常长的文档和一些接近 0 个字符的文档。为了清理一点,我们将根据长度(换句话说,最短和最长的音符)移除顶部和底部的异常值。清理并不是真正必要的,但是离群值会产生奇怪的结果,所以最好删除它们。图 2 的右侧显示了基于长度的文档的最终分布。

图 2:基于长度(字符数)的文档分布,左侧为清理前,右侧为删除 5%的最长和最短文档后。

接下来,我们要分析每位患者的文档数量(图 3)。由于这些是健康记录,更多的文件意味着情况可能对病人更糟。而一份文件通常意味着虚惊一场,病人马上就出院了。如上所述,我们将做一些清理和删除离群值,我们不希望患者有数千份文件,也不希望患者只有几份文件。

图 3:预处理前后每个患者的文档数量。

最后,我们还将显示每个类别的文档分布情况(图 4),这对于了解文档的来源非常有用。目前,我们不会根据类别进行任何过滤。

图 4:每个类别的文档数量(文档来源)。

将两个表结合起来—基于年龄的统计数据

请记住,一个患者的所有日期都被同一个随机数移位,这意味着我们可以使用患者的出生日期和文档的创建日期之间的差异来计算该文档撰写时患者的年龄。我们将在这里执行另一个清理步骤,删除年龄大于 89 岁或小于 16 岁的患者(此步骤删除的患者数量最多,约为 20%)。MIMIC-III 不包含关于儿童的信息,只包含新生儿和成人的信息,因此删除 16 岁以下的人意味着只删除新生儿。新生儿的年龄相关统计没有意义。对于 89 岁以上的人来说,这有点极端,MIMIC-III 中的数据对这个年龄组来说是混乱的。细节可以在 Jupyter 笔记本中看到,图 5 显示了结果图。

图 5:在过滤/预处理后,MIMIC-III 中患者的年龄分布。

图 5 与最近在 MIMIC-III 数据集上进行的研究中呈现的患者分布一致。

最后,表 1 显示了预处理前后数据集的统计数据。

表 1:预处理前后 MIMIC-III 数据集的基本信息。预处理之前的统计信息是在 noteevents 表上计算的。

结束了

如果你对更多关于 MedCAT 和电子健康记录的帖子感兴趣,请看这里的。

从电子健康记录中提取疾病

原文:https://towardsdatascience.com/medcat-extracting-diseases-from-electronic-health-records-f53c45b3d1c1?source=collection_archive---------21-----------------------

深入探究 MedCAT 库:从构建概念数据库到无监督训练和文档注释。

来自 Unsplash网络营销的照片。

这篇文章的重点完全是关于 MedCAT 以及如何使用它从 EHRs 中提取信息。典型的 MedCAT 工作流程:

  1. 建立一个概念数据库(CDB)和词汇(Vocab),或使用现有的模型。
  2. 对包含大量文档的目标域中的任何数据集进行无监督学习。
  3. 为在线/监督学习准备数据。
  4. 微调 NER+L 模型,并通过 MedCATtrainer 添加元注释。
  5. 将所有内容打包到一个 MedCAT 管道中,并注释文档(EHR)

这篇文章将涵盖步骤 1、2 和 3,而一篇关于监督培训的文章将经历步骤 4 和 5。

构建定制模型

谷歌 Colab

MedCAT 在其管道中使用两种主要模型:

  • 词汇表(Vocab) —词汇表用于拼写检查和单词嵌入。它可以使用任何类型的单词嵌入(从 Word2Vec 到 BERT)。如果数据集来自非常特定的领域,通常建议您创建嵌入。
  • 概念数据库(CDB) —概念数据库包含特定案例的所有相关概念。在医疗应用中,像 UMLS 或 SNOMED 这样的大型数据库是标准的,然后过滤出所需的概念。MedCAT 适用于任何类型的概念数据库,无论其规模有多大。

这篇文章的其余部分将展示如何从头开始构建这些模型。

建立新词汇

运行 MedCAT 时需要的两个模型中的第一个是词汇模型(Vocab)。该模型用于两件事:(1)拼写检查;以及(2)单词嵌入。

Vocab 非常简单,您可以从一个结构如下的文件中构建它:

<token>\t<word_count>\t<vector_embedding_separated_by_spaces>
  • 通常是一个字或子字,如果你使用字节对编码或类似的东西。
  • word_count这个词在你的数据集或任何大型数据集中的数量(维基百科也很好)。
  • vector_embedding_separated_by_spaces预先计算好的矢量嵌入,它可以是从 Word2Vec 到 BERT 的任何东西。

使用三维矢量嵌入构建词汇表的文件示例(这是一个没有标题的 TSV 文件):

house    34444     0.3232 0.123213 1.231231
dog    14444    0.76762 0.76767 1.45454
.
.
.

请注意,如果拼写很重要(或者如果您希望 MedCAT 稍后能够纠正拼写错误),词汇表中的所有单词都必须拼写正确。

现在,要构建 vocab:

from medcat.utils.vocab import Vocabvocab = Vocab()
vocab.add_words(path=<path_to_the_tsv_file>)
# Save the new Vocab
vocab.save_dict(<save_path>)

建立新概念数据库(CDB)

使用 MedCAT 时需要的第二个模型是概念数据库(CDB)。这个数据库包含了我们想要检测和链接的所有概念的列表。对于大量的医疗用例,我们将使用大型数据库,如 UMLS 或 SNOMED。但这不是一个要求,MedCAT 可以用于任何数据库,不管它有多大。

CSV 是构建 CDB 所必需的(下面显示的结构/标题是必需的,并且必须存在):

cui,str
1,kidney failure
7,CoVid 2
7,coronavirus

这是用于构建 CDB 的 CSV 文件的最基本版本:

*cui* -概念唯一标识符,这只是你数据库中的一个*ID*,可以是一个数字或一个字符串。

*str*——概念的串/名。为感兴趣的概念写下所有可能的名称和缩写是很重要的。如果您有一个具有多个不同名称的概念(就像上面 cui=7 的那个),您可以简单地添加多个具有相同概念 ID 的行,MedCAT 将在构建阶段合并这些行。

from medcat.utils.vocab import Vocab
from medcat.prepare_cdb import PrepareCDBvocab = Vocab()
vocab.load_dict(<path_to_a_vocab_model>)# Build the concept databse from a simple CSV
prep_cdb = PrepareCDB(vocab=vocab)# Crete an array for paths to CSV files that will be used to build
#our CDB
paths = [<path_to_our_csv_file>]
cdb = prep_cdb.prepare_csvs(paths)# Save the new model
cdb.save_dict(<save_path>)

要打印我们的 CDB 内容(当 CDB 非常大时,请小心使用此功能):

print(cdb.cui2original_names)#Output: {'1': {'kidney failure'}, '7': {'coronavirus', 'CoVid 2'}}

如您所见,MedCAT 用cui=7将这两个概念结合起来,并合并了不同的名称。

完整的 CSV 规格

CSV可以包含附加信息,所有可能的字段都在下面的示例中指定:

cui,str,onto,tty,tui,sty,desc,examples
1,Kidney Failure,SNOMED,PN,T047,Disease,Description of the concept,The patient was diagnosed with kidney failure
1,Failure of Kidneys|KF|K. Failure,,,,,,
.
.

这些字段都是可选的,可以包含在您的 CSV 中,也可以省略:

*onto* -源本体,如 HPO、SNOMED、HPC、...

*tty* -术语类型,如 PN -主要名称。主要姓名很重要,我建议在创建 CDB 时添加这些字段。

*tui* -语义类型标识符-如 T047(取自 UMLS )。

*sty* -语义类型-如疾病

*desc* -这一概念的描述

*examples* -这个概念在一个句子中的例子(使用简短的例子,而不是整个文档)。

只有一行需要有关于概念的完整信息。

从这个 CSV 构建 CDB 的代码与上面相同,唯一的不同是构建的 CDB 上的额外功能:

from medcat.utils.vocab import Vocab
from medcat.prepare_cdb import PrepareCDBvocab = Vocab()
vocab.load_dict(<path_to_a_vocab_model>)# Build the concept databse from a simple CSV
prep_cdb = PrepareCDB(vocab=vocab)# Crete an array for paths to CSV files that will be used to build
#our CDB
paths = [<path_to_our_csv_file>]
cdb = prep_cdb.prepare_csvs(paths)print(cdb.cui2original_names)
# Output: {'1': {'KF', 'Kidney Failure', 'failure of kidneys'}}print(cdb.tui2cuis)
# Output: {'T047': {'1'}}print(cdb.cui2tui)
# Output: {'1': 'T047'}print(cdb.cui2desc)
# Output: {'1': 'Description of the concept'}

UMLS 和斯诺梅德

如果你能接触到 UMLS 或 T2 的 SNOMED,你也可以建立大型的医疗 CDB。构建 CDB 仍然使用与上面相同的代码,您只需要将 UMLS/SNOMED 概念放入具有上述格式的 CSV 文件中。

很少有用例需要完整的 UMLS 数据库,我建议使用您的用例/领域所需的子集。构建一个包含完整 UMLS 数据库的 CDB 当然是可能的,但是请注意这个过程可能需要 36 个小时,并且需要大约 16Gb 的内存。

注意:对于 UMLS,我准备了创建 CSV 文件的脚本,因为我们在 PostgreSQL 数据库中有 UMLS。 MedCAT 论文中的附录 A。或者,如果您想构建 SNOMED,这里有一个存储库。

无监督训练

谷歌 Colab

我将使用的模型是从 UMLS 创建的;不幸的是,UMLS 是不公开的。您可以在这里请求访问 UMLS 并构建您的模型,如前一节所述。

对于那些想跟随教程,但不想去 UMLS 的人,我已经创建了使用 UMLS 的免费子集的模型。你可以在这里下载 CDB 模型,在这里下载词汇表,这些模型更小,但在许多用例中仍然有用(Google Colab 已经包含了下载模型的所有代码)。

首先,我们加载模型(如果您已经创建了模型,就可以使用它们):

from medcat.cat import CAT
from medcat.cdb import CDB
from medcat.utils.vocab import Vocab# Create and load the CDB (Concept Database)
cdb = CDB()
cdb.load_dict(cdb_path)# Create and load the Vocabulary
vocab = Vocab()
vocab.load_dict(vocab_path)# Create CAT - the main class from medcat used for concept annotation
cat = CAT(cdb=cdb, vocab=vocab)

然后,我们将设置几个参数(完整列表将在 github 上提供):

cat.spacy_cat.PREFER_FREQUENT = True # Frequent conceps are pref
cat.spacy_cat.PREFER_ICD10 = False # Useful only for clinical coding
cat.spacy_cat.WEIGHTED_AVG = True # The way context is calculated
cat.spacy_cat.MIN_CONCEPT_LENGTH = 3 # Ignore concepts <= 3 characters

我们现在准备运行无人监督的训练。我准备了一个小数据集,可以用来测试无监督训练,但请注意,像 MIMIC-III 这样的大数据集将产生更好的结果。如果您在本地运行(Google Colab 已经有了所有的东西),下面的代码块假设您已经从存储库中下载了数据(或者您已经有了 MIMIC-III):

DATA_DIR = "./data/"
data = pd.read_csv(DATA_DIR + "pt_notes.csv")# Enable the unsupervised training
cat.train = True# Print statistics on the CDB model before training
cat.cdb.print_stats()# Run the annotation procedure 
for i, text in enumerate(data['text'].values):
    # This will now run the training in the background 
    _ = cat(text)

    # So we know how things are moving
    if i % 100 == 0:
        print("Finished {} - text blocks".format(i))# Print statistics on the CDB after training
cat.cdb.print_stats()# Disable the training mode
cat.train = False

这就结束了无监督的训练,如果你看看print_stats函数的输出,你会看到我们有多少概念接受了训练。剩下的就是保存训练好的模型(只有 CDB 模型接受训练,vocab 始终保持不变):

cdb.save_dict(<save_path>)

注释文档

现在培训已经结束,我们可以继续文档注释了。

text = "He was diagnosed with Kidney failure"
doc = cat(text)print(doc.ents)
# out: (diagnosed, kidney failure)

仅此而已,没别的了。如果您愿意,也可以使用 displacy from spacy 查看带注释的文档(适用于 Jupyter 笔记本):

from spacy import displacydisplacy.render(doc, style='ent')

图 0。MedCAT 注释的显示输出。

底层的 CDB 模型是基于 UMLS 的(甚至是公开可用的 MedMentions 模型),这允许我们过滤注释,只获得我们感兴趣的概念(对于我们的用例是 T047——疾病或综合征;以及 T048——精神或行为障碍),完整列表此处

TUI_FILTER = ['T047', 'T048']
cat.spacy_cat.TUI_FILTER = TUI_FILTER# Annotating documents will now give only the concepts
#that have one of the two TUIs defined in the filter.text = "He was diagnosed with Kidney failure"
doc = cat(text)
#out: (kidney failure)

为 MedCATtrainer 准备数据

无监督学习非常有用,因为它不需要我们进行任何注释工作,但它可以学习一些奇怪的东西。为了修复缺失和错误,我们将通过 MedCATtrainer 使用在线/监督培训对模型进行微调。这样,大部分工作都由无监督学习来完成,我们只需要投入一点时间来完善它。

再次查看分析年龄和疾病之间关系的用例,我们可以仔细选择使用哪些文档来微调模型。目标是显示年龄和疾病之间联系的一般人口统计,这意味着最流行的疾病(精神和身体)是最重要的。对于微调,选择已经由 MedCAT 模型检测到的最常见疾病(无监督)并检查错误(或可能的改进)是有意义的。更正式地说,以下是必要的:

  • 用感兴趣的概念(T047 和 T048)的现有 MedCAT 模型注释所有文档。
  • 找出最常见的疾病和精神障碍。
  • 查找出现所选最频繁概念的文档。
  • 对于两组(T047 和 T048)中前 100 种疾病中的每一种,随机选择 N=2 份文件,用于验证 MedCAT 完成的检测。

这样,我们将只查看感兴趣的概念出现的文档,而不是可能没有提到相关概念的随机文档集。

为了注释数据集中的所有文档,我们将使用 MedCAT 中的multi_processing函数,它允许在多个处理器上更快地运行(如果我们有处理器的话)。在注释过程中,我们将记录每个 CUI 出现在哪个文档中。

# This will be a map from CUI to a list of documents where it appears: {"cui": [<doc_id>, <doc_id>, ...], ..}
cui_location = {}batch_size = 10000 
batch = []
cnt = 0
for id, row in data.iterrows():
    text = row['text']
    # Skip text if under 10 characters, not really necessary as we 
    # have filtered before, but I like to be sure.
    if len(text) > 10:
        batch.append((id, text))

    if len(batch) > batch_size or id == len(data) - 1:
        # Update the number of processors depending on your machine.
        #We are using the only_cui option, means the 
        #returned entities will only have a CUI (no other 
        #information, try both if interested).
        results = cat.multi_processing(batch, nproc=2,only_cui=True)

        for pair in results:
            row_id = pair[0]# Convert to set to get unique CUIs
            cui_list = set(pair[1]['entities']) 

            for cui in cui_list:
                if cui in cui_location:
                    cui_location[cui].append(row_id)
                else:
                    cui_location[cui] = [row_id]

        # Reset the batch
        batch = []

现在我们已经有了每个 CUI 出现的文档,我们还可以在我们的数据集中绘制最常见的 CUI(疾病)(下图)。更完整的代码库请参考笔记本

图一。按患者划分的 MIMIC-III 中前 30 种疾病/障碍的分布。请不要认为这张图表是理所当然的,它是基于检测疾病的提及,忽略它们是否被否定/历史/假设/与患者无关等。所有这些属性都是下面解释的元注释。

剩下的是选择最常见的疾病,并为每个疾病随机选择两个文档,并以 MedCATtrainer 要求的格式保存它们。这是一个简单的CSV 文件,结构如下:

name,text
<name of a document>,<text of a document>

梅德卡特雷纳

是一个基于 web 的界面,可用于改进(或训练新的)MedCAT 模型。完整的教程可以在资源库 + 博客文章中找到。培训师支持许多功能,但我们的重点是:

  1. 改善 NER+L,教练让我们看到由 MedCAT 检测到的概念,并为每一个说正确/不正确。如果遗漏了什么,我们还可以添加新的概念(注释)。在此过程中,模型会在后台进行更新和微调。
  2. 元注释,对于每个检测到的概念(在我们的例子中是一种疾病),我们将添加元注释来表示该概念的上下文相关属性。

元注释

对于许多用例来说,仅仅从 EHR 中提取医疗概念是不够的。通常需要提取每个检测到的概念的元注释(属性/特性)。一些可能的元注释是:

  • 否定:概念在文本中是否被否定(例如,患者患有癌症,而患者没有癌症)
  • 体验者:疾病是否会影响患者或其他人(例如,患者患有癌症,而患者的父母患有癌症)
  • 暂时性:该疾病目前影响患者还是过去影响患者(例如,患者发烧与患者两年前发烧)。
  • 不确定性:有时临床医生会在电子病历中写下假设的陈述(例如,这看起来像肾衰竭)
  • 有许多其他元注释可以提取,这完全取决于用例。

让我们看一个例子,在图 2 中,对于概念lung disease,有 2 个元注释告诉我们这个概念是否定的(意味着某人没有肺病),并且体验是耐心的(意味着某人是病人)。

图二。EHR 中的元注释示例。

MedCATtrainer 使我们能够训练模型,这些模型稍后将自动进行这些元注释。对于我们的用例,一个元注释就足够了:

  • 状态(已确认/其他):如果未被否定且当前影响患者,则标记为Confirmed,其他情况下标记为Other。请注意,我们的元注释实际上是否定、经验者、时间性和不确定性的结合。

结束了

如果你对更多关于 MedCAT 和电子健康记录的帖子感兴趣,请看这里的

MedCAT |简介—分析电子健康记录

原文:https://towardsdatascience.com/medcat-introduction-analyzing-electronic-health-records-e1c420afa13a?source=collection_archive---------16-----------------------

照片由 Hush Naidoo 在 Un spash上拍摄。

介绍如何使用 MedCAT 组织、构建和分析电子健康档案(EHRs)。例如,MedCAT 用于最近一项关于 ACE 抑制剂和 CoVid-2019 的研究。

电子病历是医疗信息的宝库;它们包含了令人难以置信的大量知识。提几个通常每个病人都有的数据点:(1)有症状的疾病;(2)药物治疗,通常伴有剂量说明、最终副作用和患者反馈;(3)治疗,有时有患者的反馈;(4)来自临床医生的风险、假设和意见;(5)病人的证词;(6)各种测量和实验室结果。

在处理 EHR 时,我们首先需要构建和组织它们。它们包含的信息通常以非结构化格式(自由文本)提供。对于医生来说,这个相对还可以;他们可以阅读文档并获得他们需要的信息。但是,如果我们想要使用数据进行统计分析或机器学习,没有结构是有挑战性的。

给定一个结构化的 EHR,一些可能的研究用例是(1)死亡率预测;(2)疾病风险计算;(3)临床编码;(4)疾病或患者的时间模型;(5)疾病/药物相互作用;(6)药物不良反应的检测;

当然,我并不是第一个理解电子病历中的可用数据对病人和医疗机构都有很大好处的人。最近,我们已经看到谷歌健康(数据聚合工具)、亚马逊(他们的理解医疗)和许多其他公司的大动作。虽然很高兴看到大公司了解 EHR 的价值,但他们需要很长时间才能完全访问医院数据(隐私问题)。最后,即使他们获得了访问权,它是否能促进研究项目或帮助病人也是值得怀疑的。

我在这里的目标是展示,使用像【MedCAT】这样的工具,我们可以在几个小时内在一台个人笔记本电脑上构建大型医院的电子病历,而不需要大型服务器和基础设施。有了这个,我们就有可能启动/进行能够改善医疗保健的研究项目。

这篇文章的其余部分组织如下。首先,我们将定义一个用于展示 MedCAT 的小项目。其次,我们将看看我们正在使用的数据集。第三,我们将检查环境设置。

请注意:(2)我不会分享任何医疗数据集,但会显示在哪里以及如何访问/获取它们;(3)一些统计学和机器学习的知识会有帮助,但不是必须的;(4)我们这里关注的是 EHR,同样的方法可以用于其他类型的文档,但是目前,该工具主要在生物医学文档上进行测试。

MedCAT 教程概述

本教程中的每一篇文章都是独立的文章,但仍然建立在同一个故事之上。随意跳转到你感兴趣的帖子,它应该很容易跟踪和理解(链接将随着教程的发布而更新)。

  1. 简介 —本岗位

  2. 从电子健康档案中提取疾病 —深入探究 Python 中的 MedCAT 库以及命名实体识别和医疗概念的链接。如果您只对如何使用 MedCAT 感兴趣,这很有用。

  3. 监督培训和完整的 MedCAT 管道 —探索 MedCAT 库的更高级部分,以及如何为 NER+L &元注释构建完整的管道。

  4. 分析结果 —这是我们从电子健康记录中提取出感兴趣的实体后可能实现的一个例子。

  5. med cat 库的其他工具和功能(ICD10 代码,SNOMED CT) &未来的期望

简介—项目定义

让我们看一个例子。假设我们访问了一家大型医院的数据库,该医院的每个患者都有一个包含大量自由文本的 EHR(下面的文档示例,您可以在 mtsamples 找到更多)。除此之外,每个 EHR 还包括几个结构化字段,如年龄、性别和种族。现在,假设我们的项目是展示疾病与年龄之间的关系(可以用来计算与年龄相关的疾病风险分值)。为了做到这一点,我们需要知道每个患者的年龄,以及在他的 EHR 中出现的疾病。提取年龄很容易,这是一个结构化的领域,但问题是疾病。它们只在自由文本中被提及,通常不会在其他地方出现。在继续之前,我们需要从每个 EHR 中提取疾病,并将它们保存在结构化数据库中。

请注意 : (1)疾病提取问题还有更多的内容,但我们会继续扩展。(2)疾病只是一个例子,我们可以用药物、症状、程序或任何其他东西来做同样的事情。

一个 EHR 的假例子,请注意,尽管这是自由文本,但它明显比真正的 EHR 更结构化,阅读/理解起来是一场灾难。

疾病提取问题的正式定义

我们想要实现的在自然语言处理(NLP)中被称为命名实体检测和链接(NER+L)。NER 意味着检测文本中的实体(例如医学术语,图 1 中的第二步)。而 L 意味着将被识别的实体链接到生物医学数据库中的概念(例如 UMLS ,图 1 中的第三步)。

链接部分是必不可少的,因为它允许我们标准化和组织被检测的实体,因为多个被识别的实体可以链接到生物医学数据库中的相同医学概念。例如,在 EHR 中,我们可以有:

  • 患者被诊断患有乳腺恶性肿瘤
  • 既往病史包括乳腺癌
  • 入院原因:乳腺癌

每一个粗体的概念都是相同的疾病,只是书写方式不同。如果我们不对检测到的实体进行标准化,将很难计算例如有多少患者患有乳腺癌的统计数据。

此外,如果我们将一个实体链接到一个生物医学数据库,我们就可以访问该数据库中的所有结构化字段(图 2)。

生物医学数据库的一小部分(UMLS)。

一旦我们检测到实体并将其链接到我们的生物医学数据库,我们就可以,例如,基于Semantic Type字段过滤实体,或者找到所有链接到 ID 为C0006142的生物医学概念的实体。在 UMLS 可以找到所有语义类型的概述这里(注意,其中一个语义类型是疾病,这正是我们需要的)。

请注意: (1)对于生物医学数据库,我们将使用 UMLS,因为它是最大的数据库,拥有超过 420 万个医学概念。还有许多其他生物医学数据库,但 UMLS 完全符合我们的需求,因为我们希望提取所有可能的疾病。

数据集——MIMIC-III

MIMIC-III 是一个公开可用的数据集,由麻省理工学院计算生理学实验室开发。它包括临床笔记,人口统计,生命体征,实验室测试等。

我选择了这个数据集,因为它是唯一公开的包含 EHR 的数据集之一。数据集不能直接下载,但需要先提交请求——通常会在几天内获得批准。

环境设置(如果在本地运行)

我们将使用 Python 作为主要编程语言,稍后,一些情节将使用 R 或在 JavaScript 的帮助下完成,但这主要是为了让它们更有趣。

我将使用 python 3.7 做任何事情,很可能 3.5 以上的版本会很好。

如果您正在本地机器上学习本教程,建议使用以下命令启动一个新的 Python 虚拟环境:

python3 -m venv medcat

一旦完成,您就可以克隆 MedCAT 存储库并进入tutorial目录。从那里运行(不要忘记激活medcat环境):

pip install -r requirements

由于 MedCAT 构建在 SpaCy/SciSpaCy 之上,您还需要使用以下命令下载语言模型:

pip install [https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.2.4/en_core_sci_md-0.2.4.tar.gz](https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.2.4/en_core_sci_md-0.2.4.tar.gz)

Google Colab

所有的代码也可以在 Google Colab 上找到,你可以在tutorial部分找到笔记本的链接。这是遵循本教程的最简单的方法,因为一切都已经配置好了。但是,请注意,Colabs 不会使用真实数据(MIMIC-III),而只会使用公开可用的数据集和生成的虚拟数据。

MedCATTrainer:用于检查、改进和定制 MedCAT 的工具

原文:https://towardsdatascience.com/medcattrainer-a-tool-for-inspecting-improving-and-customising-medcat-880a11297ebe?source=collection_archive---------44-----------------------

MedCAT 的配套工具:组织、构建和分析电子健康记录(EHRs)的管道。

概观

医学概念注释工具(MedCAT) ,是一个(命名实体识别+链接)NER+L 工具,用于识别临床文本概念并将其链接到现有的生物医学本体,如【UMLS】SNOMED-CT——这通常是从临床 EHR 中可用的大量非结构化纯文本中获得洞察力的第一步。

本文将介绍 MedCATTrainer,它是 MedCAT 的一个附带工具,可用于:

  1. inspect——可以直观地检查和审查由 MedCAT 识别和关联的概念,从而建立对 MedCAT 模型的信任。
  2. 改进——提供受监督的训练示例,允许人类注释者改进 MedCAT 模型。
  3. 定制——为训练项目/用例特定的模型收集更多的用例特定的注释。

这 3 项任务对于跨临床用例应用 MedCAT 非常重要。

安装/设置

MedCATTrainer 提供了注释接口、ReST API、中间层和数据库。所有的组件都已经被 dockerized,并且是可用的开源。下载、安装和运行需要 3 个命令

第一次运行应用程序时,下载 MedCAT 模型、示例数据集,并为已配置的示例用户创建许可的示例项目。

注释界面

该界面显示了一个文档摘要及其注释状态、当前正在审查的临床文本以及来自 MedCAT 的当前选择的概念细节。

一个易于使用、简单但功能丰富的 web 界面允许注释者:

  • 检查最初以灰色显示的 MedCAT 识别的实体,并在选择后突出显示其各自的状态。
  • 提高 MedCAT 的 NER+L 能力,通过选择合适的文本,右击‘添加注释’,然后从 MedCAT 中搜索并链接正确的术语。这可以提高 MedCATs 对其从未见过的首字母缩写词、拼写错误或术语缩写的识别能力。

项目配置中的一个可选设置允许人类注释者添加全新的概念。新概念可以通过类似于 UMLS 和 SNOMED-CT 根术语的语义类型进一步分组。这一特征与精神健康等领域尤其相关,这些领域通常没有 UMLS 和 SNOMED-CT 等标准化术语。

主动学习

MedCATTrainer 可用于主动训练已配置的 MedCAT 模型。在文档的每一次提交之后,每个正确的、不正确的和新添加的实体被用于进一步训练所配置的 MedCAT 模型。随着人类注释者处理更多的文档,“辅助”注释体验使得注释变得不那么困难。

下图显示了最近的一个项目,该项目在真实的临床文本中注释症状、发现和药物治疗概念,随着人类注释者的进行,他们遇到的手动添加的新 SNOMED-CT 实体越来越少。变化的峰值表明真实临床数据的可变性。MedCAT 模型的收敛证明了投资于人类注释的价值,并且可以被认为是模型“微调”的一种形式。

一旦“微调”到数据集或临床记录类型,双注释器就可以对 MedCAT 模型性能进行严格评估,而无需主动学习计算标准指标,如 IIA科恩的卡帕。MedCATTrainer 支持这个用例,它允许管理员轻松地克隆项目和权限注释器,然后下载报告度量性能

用例/项目特定的注释

在下游研究问题中使用临床文本通常不仅仅是简单地确定正确的文本跨度和与正确的术语概念相联系(UMLS/斯诺梅德-CT)。它还经常涉及对疾病或症状的进一步注释,以确保它们与患者相关,或者是当前的实例,而不仅仅是临床医生假设性地提及概念。然而,研究问题通常会有不同的解释,例如,时间性——“当前”和“历史”可能无法为所有研究问题提供适当的粒度级别。

MedCATTrainer 支持这些所谓的元注释的项目或用例特定集合的配置。管理员可以用特定的元注释配置注释项目,以便在项目之间重用或单独使用。每个配置的注释和相关值都出现在界面中。

一旦完成,管理员可以下载注释,并使用 MedCAT 库训练单个元注释模型。

概括起来

这个简短的介绍激发了 MedCATTrainer 与 MedCAT 工具的结合使用。全套文档可直接在 GitHub 上获得,此外还有编程 API 访问的全部细节、上述所有功能的详细配置以及用于组织、构建和分析 EHR 的常见用例的项目设计模式。

干预人力资源自动化!

原文:https://towardsdatascience.com/meddling-with-hr-automation-b331daf21858?source=collection_archive---------29-----------------------

利用数据科学改善人力资源招聘流程

供稿人: 林家辉
OOI 惠敏
PHOE CHUAN BIN
沈志安
吴彦祖 MENG 凯

行动纲要

设计一个系统,能够提取工作角色最重要的技能,并使用自然语言处理(NLP)将它的适用性与大量非结构化简历相匹配。该系统还能够在多个技能维度上对候选人进行评估和排名,以计算每个工作角色的每个候选人的总分。

接下来,我们研究了不同行业和职业的人格特征,以发现它们之间是否存在显著差异。在确立了这一意义后,我们开发了一个系统,使用文本分析来识别求职者的 MBTI 人格类型。这可以作为人力资源的指南,以确保所选申请人的个性符合他们申请的角色和团队。

最后,我们使用流失数据来识别某些个人信息,这些信息可能有助于选择不太可能离开公司的候选人。如果候选人拥有某些对预测人员流失非常重要的信息,这些信息可以作为一种标记机制,向人力资源人员发出警报。

如果您希望查看有关该报告的简明幻灯片,请前往https://medium . com/@ phoechuanbin/dumping-with-HR-automation-slides-4 db 88 eadb 99 c

介绍

如今,发送简历几乎不费吹灰之力。例如,谷歌,许多有抱负的计算机科学学生希望为之工作的四大科技公司之一,每周收到超过 2 万到创纪录的 7 万份简历。(埃迪·j,2014 年)

相反,人力资源的工作并不容易。他们有许多职责,如处理员工的工资,培训等。,其中一项包括翻看数千份这样的简历。更糟糕的是,在一家运转良好的公司中,人力资源可能也不太熟悉和熟悉各种职位和角色。

此外,一份工作的合适人选不应该仅仅是拥有最好的资格。性格和心理情绪特征通常非常能说明一名员工是否适合和有能力在一个组织的工作文化中茁壮成长。

最后,对于人力资源来说,留住员工是一个普遍而普遍的问题。员工类似于资源,失去员工就相当于失去了雇佣和培训员工的时间、资源和金钱。

因此,人力资源分析正在崛起,以解决这些问题,因为沟通。利用分析的能力可以通过对非结构化信息进行分类、排序和存储,显著释放人力资源资源,并以一种更少偏见、数据驱动的方式管理员工。

我们的团队设计了一个三阶段计划来处理获得合格人才的问题,通过心理情绪特征筛选最合适的候选人,最后通过找到流失率的重要变量来留住员工。

1.获得物ˌ获得

1.1 背景

使用传统的人工劳动对简历进行人工分类不仅耗费大量资源,而且容易受到人为偏见和错误的影响。Marianne 和 Sendhil 在 2003 年进行了一项著名的研究,研究了姓名为 Emily 和 Greg 或 Lakisha 和 Jamal 的候选人的就业能力。结果是“听起来像白人的名字”比“听起来像黑人的名字”多收到 50%的回复。

因此,我们的团队设计了一个 3 步数据驱动模型,我们相信它可以帮助人力资源部门根据简历对所申请职位的适合性,更客观地对简历进行排名。这可以作为不匹配简历的主要过滤器。图 1.1 描述了这个模型。

图 1.1:简历排名模型

首先,我们相信对于一个给定的工作角色来说,获得最重要的技能的最好方法是从“群众的智慧”中寻求。通过网上搜集各种组织的大量职位描述(JDs ),强调该角色的基本工作要求,我们将获得该行业普遍需要的最突出的技能。

其次,在获得数百个 JD 后,我们可以通过给定作业角色的令牌化来创建令牌数据库,并在执行 NLP 之前清理它。停用词被移除并且应用词袋(BOW)模型,因此词的顺序无关紧要。我们首先执行了一般的、非结构化的文本分析,随后是有针对性的分析。前者类似于无监督学习,因为我们试图在令牌数据集中寻找未知模式。后者旨在为其在每个预先确定的技能列表中的流行程度给出一个“分数”。

第三,通过应用具有先前设计的评分的排名算法,可以根据候选人的个人技能维度或作为整体与所申请的工作的相关性对候选人进行数字排名。

1.2 应用

1.2.1 网页抓取

我们的团队从 Indeed,一个与就业相关的工作列表搜索引擎,搜集了“数据科学家”(Ds)、“数据分析师”(DA)和“数据工程师”(DE)的 JDs。在他们的服务条款中,确实允许网络抓取。

由于原始文本是从网页上刮下来的,因此在进行任何分析之前都需要进行预处理。我们通过以下方式同等对待每个数据集:

  1. 转换为 UTF-8 到 ASCII 编码
  2. 删除换行符(" \r "和" \n ")和标点符号
  3. 转换为字母格式
  4. 修剪前导和尾随空白
  5. 转换为小写

数据清理

首先,我们将每个数据集标记为二元模型(2 个单词作为 1 个标记),因为这对“机器学习”、“人工智能”和“数据科学”等术语有意义。

在执行任何有意义的分析之前,必须进行数据清理。首先,我们将二元模型分成单个单词,同时保持其结构完整性。接下来,我们从“tidytext”包中过滤出常用的停用词。这些词在语言中经常被用来使句子流畅,但通常不是实质性的,很少增加意义。这一步见证了所有数据集中令牌大小最显著的减少,大约减少了三分之二。(附录 1A)

之后,我们删除了数据集中频率= 1 的单词。在我们的例子中,这些包括不太有意义的术语,如“aaa”,或者不正确解析的术语,如“abilitiesstrong”。因此,它们不是实质性的。

为了清除未正确处理的单词,我们通过反复试验过滤了具有高字符数的标记(例如“manufacturinglocationsingaporecontract”)。但是,我们知道这可能会损坏我们的数据。一旦大多数前 50 个字符计数标记被认为是有效的或可理解的,我们就停止该过程。

我们继续使用“textstem”包对我们的令牌进行符号化。与词干化相反,词干化的目的是返回单词的基本形式,而词干化是一个更粗糙的过程,只需砍掉单词的词尾。例如,如果遇到标记“ponies”,词汇化将返回“pony”,而词干化将返回“poni”。

1.2.3 一般文本分析

一个词在数据集中所占的比例越高,我们就可以假设一个令牌在特定工作角色中的相关性越大。

然而,我们意识到,DS 有许多技术术语,如“数据科学家”和“机器学习”,而 DA 有一些不太有用的术语,如“婚姻状况”和“性取向”(附录 1B)。因此,这种数值分析方法可能并不适用于市场中的所有工作角色,而应该仅用于数据探索。

这一观察可以通过使用潜在狄利克雷分配(LDA)模型的主题建模和聚类分析来验证。结果表明,单词可以分为技术行话或人口统计变量。分析可在附录 1C 至 1E 中找到。因此,使用我们的领域知识进行有针对性的分析以获得更好的洞察力是合乎逻辑的。

有针对性的分析

与一般的文本分析不同,目标分析利用特定工作所需技能的领域知识。在我们的案例中,我们确定了 4 个我们认为相关的独特技能维度。这些技能类别如下所示。

DS、DA、DE 的 4 个技能维度

  1. 编程语言
  2. 数据科学工具
  3. 技术
  4. 软技能

首先,我们的团队搜集了维基百科中大约 700 多种编程语言的列表,我们认为这是最全面的,尽管有一些不太流行。(附录 1F)。我们承认诸如“reason”、“basic”和“simple”这样的标记可能会被含糊地使用,而不是严格地用于编程语言。然而,由于这些是可行的编程语言,我们选择保持谨慎,在我们的分析中保留它们。

接下来,我们确定了一个“14 大数据科学工具”的列表,如“tableau”、“scikit-learn”和“excel”(data flair 团队,2019)。我们认为,尽管这超出了编程语言的范围,但它与编程语言是密切相关的,并且是 it 行业中必不可少的元素。同样,我们也注意到在分析具有多重定义的术语时会有歧义。例如,当“excel”带有优越的含义时,它可能被解释为数据科学工具。

然后,我们确定了与 IT 行业相关的 6 个广泛的技术技能,尽管选择了编程语言或使用的工具(Chandrasekaran,2018)。它们分别是“统计”、“回归”、“可视化”、“发现”、“分类”和“提取”。(附录 1H)。

最后,我们承认软技能对于所有行业的运营都是相关的。因此,我们策划了一个宽泛的术语列表,如“沟通”、“团队合作”、“领导力”等。其被设计成不那么模糊。我们的调查结果如附录 1I 所示。

1.3 简历排名模型

与 JDs 类似,我们的团队已经从 Indeed 合法地下载了 20 份简历。我们设计了一种算法,根据第 1.2.4 节中讨论的技能维度对这些简历进行排序。

排名算法

图 1.2:编程语言排名算法

首先,我们为特定的工作角色创建了一个文档术语矩阵。因此,简历(文档)以行的形式展示,而技能(令牌)以列的形式呈现。这给出了每个候选人所拥有的技能的一般和简要的反馈(附录 1J)。

我们建议利用对数函数的特性来计算分数。对数函数是指数函数的反函数,并且是广泛接受的和方便的表示大数的方式(Jon。, 2018).分数以递减的速率增加,以适应这样的事实,即具有较高的项计数不会线性地增加分数的值。例如,“python”的值为 1 对 2≈10 对 20。这也可以防止给那些垃圾相关关键词的简历过高的分数。

图 1.3:基于术语频率的得分图

图 1.3 显示了用于计算分数的两个等式。我们不能简单地使用对数方程,因为 log(0)趋向于-∞。

如果词频为 0,则相应的分数逻辑上为 0。否则,我们将使用

来计算分数。该图显示了得分如何随术语频率而变化。

对于不同的工作角色,每项技能都有不同的价值。例如,编程语言“python”在 Ds 的 JDs 中有 26.2%的显著提及比例,而在 DE 中只有 16.6%。因此,“python”在 Ds 的 JDs 中的高提及率应该比在 DE 中的高。因此,我们建议将步骤 2 中的分数乘以该关键字的相应提及率比例。

1.3.2 产出

我们对每个简历数据集(DS、DA、DE)的每个技能维度(“编程语言”、“数据科学工具”、“技术技能”、“软技能”)进行了分析和计算。通过这些评分,我们可以评估个人满足申请职位要求的整体能力。

此外,通过每个维度的得分,这增加了为什么一个候选人比另一个候选人更好的解释力。例如,两个候选人具有相同的总分,但是候选人 A 具有更高的“编程语言”分数,并且对于该工作,该维度是至关重要的。所以,候选人 A 更适合。

每个数据集最终结果的汇编见附录 1V,每个数据集各自维度的汇编见以下附录。

数据集

附录

DS: 1J,1K,1L,1M

大卫·爱登堡:1N,1O,1P,1Q

德:1R,1S,1T,1U

重要观察结果

我们观察到,我们预先定义的“技术技能”词汇在 DA 和 DE 简历数据集中没有广泛使用,因为计数范围在 0 到 1 之间。这可能意味着所确定的术语不够广泛,或者工作角色不需要这些技能。这也适用于数据集内。对于德除“责任”一词外的软技能,其整体提及率也较低。我们理解简历通常不包含这样的词,因此建议使用其他文件,如求职信。

其他值得注意的观察包括简历中的大量提及,特别是“Sazid Khan 的简历”,其中 89 次提到了数据科学工具技能术语“tableau”。经过进一步分析,他有一份长达 6 页的简历,其中提到了 Tableau 应用程序套件在他的各种工作中的使用。然而,对数函数和给定的较低权重分数缓和了他夸大的使用,他在 DE 数据集中的数据科学工具方面排名第五。

建议

在我们的最终分析中,我们假设每个技能维度都是同等重要的。但是,每个技能维度的权重可以通过部门主管的意见、专家意见等进行更改。同样,我们的模型目前没有能力评估其他相关因素,如教育水平、成就、以前的工作经验、课外活动或爱好等。目前。例如,为了跟踪教育水平,我们可以将诸如“A-Levels”和“Diploma”这样的术语分组为高中水平的教育,将诸如“学士”和“理学士”这样的术语分组为大学水平的教育。

1.4 结论

我们提出的模型为人力资源提供了一种资源友好的方法,将市场上几乎任何工作角色的非结构化简历转换为更结构化、更有组织性的数据集。这样,人力资源部门就能够使用数据驱动的方法来客观地评估候选人的各种技能领域,并更好地判断谁最符合给定角色的工作要求。

2.人格契合度

2.1 问题

获取人才和技能只是提高工作场所运营效率的一个方面,个人对工作环境的适应也很重要。研究表明,那些很好地融入公司文化、与同事和主管相处融洽的员工总体工作满意度更高,更有可能留在公司,并且更致力于实现卓越的工作绩效(Bouton,2015)。

有鉴于此,我们的团队旨在调查在给定的行业和/或部门中是否存在相同性格类型的趋势。如果是这样的话,我们将随后开发一个模型,筛选出适合特定行业和/或部门的具体个性特征。该模型可以在第 1 部分之后结合使用,在第 1 部分中,如果个人符合所申请工作的要求,将对其进行筛选。

使用不同行业和部门工作人员的 3600 份记录(personality.csv)和他们在五大性格测试(开放、尽责、外向、随和、神经质)中各自的分数(Gosling et al .,2003)的数据集,我们分析了部门和行业雇用具有相似性格的员工的假设。

2.1.1 跨部门/行业的平均人格特质得分是否存在差异?

首先,我们需要分析不同部门和行业的平均人格特质得分是否相同。方差分析用于对我们的数据集进行测试。以下是仅针对外向性得分的无效假设和替代假设(有关其他人格特征的结果,请参考附录 2A):

H0:不同部门/行业的外向性得分是一样的

H1:不同部门/行业的外向性得分不一样

图 2.1.1:跨部门外向性得分的方差分析结果

图 2.1.2:各行业外向性得分的方差分析结果

从图 2.1.1 和 2.1.2 所示的 ANOVA 结果中,我们可以看到跨部门和跨行业的外向性得分的 p 值都小于 0.05,具有统计学意义。这意味着我们拒绝零假设,并得出结论,不同部门或不同行业之间的平均外向性得分不同。

图 2.2.1:各行业外向性得分箱线图

图 2.2.2:跨部门外向性得分箱线图

此外,我们为了可视化的目的绘制了一个箱线图。从图 2.2.1 和图 2.2.2 可以看出,数据集的外向性得分在不同行业和部门之间存在显著差异。例如,在图 2.2.1 中,用红点表示的房地产的平均外向性得分明显高于其他行业,尤其是会计和 IT 行业。这可能是因为在房地产行业,员工将不得不更多地互动和社交,因此拥有高外向性得分将允许他们从周围的人那里获得能量,从而更有效地运作。这与会计和 IT 行业形成对比,在这两个行业中,员工与同行业其他人员之间的互动并不常见,因此外向性得分非常高的员工没有多少附加值。同图方差小,也可以解释为,同行业工作的人,大部分都有非常相似的外向性得分。附录 2B 还显示了所有行业和部门的其他性格特征的图表。

2.1.2 部门还是行业更有意义?

比较图 2.2.1 和图 2.2.2,可以看出每个部门内的外向性得分显示出比每个行业内更低的方差和更少的离群值。我们的方差分析结果可以进一步支持这一观点,如图 2.1.1 和图 2.1.2 所示,结果显示跨部门的 f 值(1859)显著高于跨行业的 f 值(670.7)。由于 f 值揭示了组内方差的均值与组内方差的均值之比,因此可以得出结论,部门间方差与每个部门方差之比低于行业间方差与每个行业方差之比。

这暗示着,在某个部门内部雇佣性格特征相似的员工,比在某个行业内部更重要,更准确。这样的观察是因为一个行业中的员工可以在不同的部门工作,不同的部门会决定他们的工作范围,因此需要一定的性格特征。行业并不是具有某些特质的员工的决定因素。因此,部门性格特征应该优先于基于行业的特征,尽管后者仍然很重要。

图 2.3:行业、部门和团队的关系

不要忘记,员工与其同事和主管的个性匹配同样重要,因为员工主要与上述人员互动。只有当这些方之间建立了良好的关系,运营效率才会最大化,因为关系满意度会很高。

2.2 方法

为了确保雇佣的人适合这个部门,我们必须首先能够确定申请人的性格类型。一种选择是让每个申请人都通过标准化的 MBTI 测试。然而,这可能是非常耗时和昂贵的,并且可能不适合所有的公司。此外,申请人可能会“玩弄”这些性格测试,以适应他们申请的角色,从而增加他们被雇用的机会。我们的目标是在不增加招聘流程复杂性的情况下,使用容易获得的文本数据(如求职信)来评估候选人的个性。

通过文本分析,我们将能够通过申请人申请工作时提交的求职信来确定他们的性格类型。这可作为确定它们是否适合特定部门的指南。

作为改进,我们可以使用相同的方法来分析用户的社交网络以获得更高的准确性,因为它是文本数据的不太正式的形式,并且申请人“玩弄”系统的能力也较低。我们将使用下面求职信中的文本数据。

图 2.4:文本分析步骤

我们将把 MBTI 分为四个维度,并开发一个与它们相对应的心理词汇。该词典用于检测求职信中与维度相关的单词的用法。

为了开发完整的心理词汇,必须对不同性格类型的人使用的词汇类型进行深入的心理学研究。为了简化我们的模型,我们将使用由申请人用来描述自己的简单描述性词语组成的心理词汇(例如,具有高度外向性的人使用“善于交际”来描述自己)。

当这些词在求职信中被发现时,术语频率的总和将被分配到我们的心理词典所规定的各个维度。使用列表分数,我们将能够确定申请人在 MBTI 的不同维度上是高还是低。

使用 1.3.1 中的相同对数函数来减少随函中关键字的重复使用,以准确反映术语每次出现的值。

2.2.1 文本分析结果

我们对 5 份不同的简历样本进行了文本分析,以找出申请人的不同性格类型。

图 2.5 文本分析结果

使用我们的模型,需要注意以下几点:

如果值为正,则表示各自列中的“内向(I)”、“直觉(N)”、“思考(T)”和“判断(J)”。

如果值为负,则在各自的列中表示“外向(E)”、“感知(S)”、“感觉(F)”和“感知(P)”。

根据上表中的结果,我们可以从 5 位不同申请者的简历中推断出他们的 MBTI 性格类型。据观察,CV_1 申请者的人格类型是 ENFJ,CV_2 是 ESTJ,CV_3 是 ENFJ,CV_4 是 ESTJ,CV_5 是 ESTP。使用这些 MBTI,招聘经理和人力资源人员可以使用它作为指导,以帮助他们的招聘过程。

例如,一个销售部门寻找具有 ESTJ 性格类型的申请人,因为他们认为他们需要一个直言不讳、对人有良好感觉、能够批判性思考并对事物有良好判断力的人来成为一名成功的销售人员。这种情况下,CV_2 和 CV_4 会更合适。

图 2.6:内向和外向的结果

接下来,销售部门可以进一步研究他们认为更重要的特征。他们可能会选择外向,因为销售人员需要全天会见许多客户,与客户建立融洽关系的能力至关重要。因此,他们可能会调查这两个简历的外向性得分。从上面的结果中,我们可以观察到使用 CV_4 的申请人具有最高的外向性得分,他的个性符合该部门的要求。

2.3 限制

然而,我们承认很难量化人格特质,更不用说对它们进行排名了,尤其是如果输入数据和使用的词汇不够强大和广泛的话。衍生的人格类型应该作为指南而不是分数。因此,我们建议使用社交网络数据,并为此开发一个广泛的词典。同样,这也可以进一步扩展到大五人格模型。

2.3.1.推荐

这个庞大的词汇应该考虑到变价词,即改变或强化极化词含义的词(开放数据科学,2018)。这包括否定词,如“不”。简单地将单词与心理词典进行匹配来计算个性过于简单化,因为它可能会删除或改变文本数据中的基本信息。

使用我们的文本挖掘模型,如果发现“不善于交际”,原始模型会将“善于交际”标记为外向性的积极术语。然而,随着变价词的出现,我们知道这个词的意思已经改变了,这个词应该被标记为一个否定词。心理词典可以被开发成包括“句子级”文本分析,因为当考虑到变价物的存在时,它将给出单词含义的更好表示。

2.4 结论

使用上述方法,我们能够使用容易获得的文本数据找到候选人的人格类型。然后,人力资源部可以通过查看申请人的特质来确保所选的申请人符合部门的要求,从而确保选择最合适的申请人。

3.保持

3.1 问题

雇佣新员工时,雇主可能会考虑的一个因素是他们留在公司的可能性。因此,我们报告的这一部分将重点关注员工的流失率。

自然减员指的是通过辞职和退休自愿减少雇员,并且没有人接替。对于一个高流失率的公司来说,有很多负面影响。首先,由于生产力的损失以及雇佣和培训费用的增加,这将对公司的盈利能力产生直接影响。高流失率还可能导致工作场所士气低落,因为现有员工可能会过度劳累,而新员工适应公司的难度会增加。这将导致员工生产率和公司收入下降(Markovich,2019)。因此,为了减少雇佣和培训费用的增加,以及减轻收入损失,雇佣自然减员可能性低的员工是很重要的。

减少员工流失有两大方法:留住现有员工和雇佣流失率较低的员工。第二种方法将在本分析中重点介绍。我们的目标是找到与自然减员相关的重要因素,并利用这些因素从申请人的简历中筛选出自然减员概率高的潜在员工。

3.2 数据探索和清理

这个分析使用了 IBM HR 数据集。数据集由 37 列 23532 行组成。由于存在大量变量,只有一个变量的列(如 Over18、StandardHours 和 EmployeeCount)将被删除。

图 3.1 公司总工作年限<年

发现 6 个数据点中,员工的总工作年数少于他在公司的年数。有可能是不真实的,因为总工作年数应该大于或等于在公司的年数。由于很难准确预测哪个值是正确的,这 6 个数据点将被丢弃。

图 3.2 在公司总工作年数>年但 NumCompaniesWorked = 0

2800 名员工被发现工作年数比在公司的年数多,尽管他们是在第一家公司(NumCompaniesWorked = 0)。这些很可能是不真实的,因为如果是员工的第一家公司,总工作年限和在该公司的工作年限应该是相同的。由于很难准确预测哪个值是正确的,所有这些数据点都将被丢弃。

图 3.3 薪资和职务级别相关数据的相关值

有 4 列与工人的工资相关:小时工资率、日工资率、月工资率和月收入。然而,它们彼此具有极低的相关值,这似乎是不合逻辑的。因此,由于 MonthlyIncome 与 JobLevel 的相关性最高,MonthlyIncome 将被保留,而其他 3 列将被删除。

最终清理的数据集由 20,683 行和 31 列组成。

3.3 方法概述

这种分析的最终结果是损耗。自然减员分为两类——当前员工和自愿辞职的员工。图 3.4 总结了我们的分析方法。

图 3.4 分析方法概述

首先,我们使用一个逻辑回归模型,以流失为输出,来确定预测流失的变量。在对产生的显著变量进行简要分析后,我们发现环境满意度、工作满意度和关系满意度是中间输出,可以解释其他一些变量。因此,我们使用分类和回归树(CART)来找出哪些变量在确定 3 个满意度测量中的每一个中是重要的。然后引入专家意见和领域知识来进一步探索重要变量。

3.4 逻辑回归结果

我们进行了逻辑回归分析,以了解哪些变量在预测减员方面具有重要意义。在排除非显著变量后,对模型进行了修正。调整后的逻辑回归模型的结果如下图 3.5 所示。

图 3.5 Logistic 回归结果

从结果来看,有 15 个变量具有统计显著性,p 值小于 0.05。

员工流失的一个可能原因是对公司的不满。根据 Statista 2019 年的数据,美国员工辞职的首要原因之一是对当前组织的不满(米勒托维奇,2019)。例如,如果员工对自己的工作环境不满意,他很可能会主动辞职。员工满意度主要有 3 个方面:工作满意度、环境满意度和关系满意度(Johnson,2017)。

如理论所述,环境满意度、工作满意度和关系满意度具有高度的统计学意义,p 值小于 0.001。这 3 个变量是中间输出变量,因为其他一些变量可以用这 3 个满意度来解释。例如,离家的距离可能是决定环境满意度的一个重要因素。因此,将进行进一步的分析,以确定哪些变量可以用这 3 种满意度来解释。

3.5 购物车结果

使用 CART 模型分析变量在预测环境满意度、工作满意度和关系满意度方面的显著性。

图 3.6 环境满意度购物车结果

环境满意度的 CART 模型得出的总体准确率为 0.845。图 3.6 显示了预测环境满意度的可变重要性的结果。

图 3.7 工作满意度购物车结果

工作满意度的 CART 模型得出的总体准确率为 0.959。图 3.7 显示了预测工作满意度的可变重要性的结果。

图 3.8 关系满意度购物车结果

关系满意度的 CART 模型产生了 0.966 的总体准确率。图 3.8 显示了预测关系满意度的可变重要性的结果。

3.6 重要因素分析

下表总结了各种变量及其在预测员工流失和员工满意度重要性方面的重要性。只有在 CART 模型中确定的前 10 个重要变量被认为是重要的。由于存在大量变量,因此仅显示了对预测损耗有意义的变量。

有多个变量对预测流失很重要,但也可以用环境满意度、工作满意度和关系满意度来解释。每一个满意度测量,以及在预测减员更重要,但没有任何满意度测量解释的变量,将进一步探讨。(红色边框区域)

  • 环境满意度

环境满意度是指员工对其物理工作环境的满意程度。根据我们的结果,它是由年龄、离家的距离、喜欢的百分比、年数和年数决定的。还有其他变量,如办公室美学,可能很重要,但不包括在数据集中,因此不会进一步讨论。由于变量很多,只有年龄和离家的距离将进一步探讨,因为这两个变量在申请人的简历中更相关。

不同年龄的上班族对工作环境有不同的偏好。老一辈的人更倾向于优先考虑建筑中的可持续性特征和联网可能性,而年轻一代则更喜欢支持团队工作、社交互动和创新的工作环境(Rothe 等人,未注明)。因此,根据公司的工作环境,最适合公司的年龄范围会因公司而异。然而,雇主不应该优先考虑按年龄筛选员工,以防止工作场所的年龄歧视。

对大多数人来说,浪费在上下班路上的时间是可以避免的。然而,长时间的通勤与缺勤和迟到的增加有关,也与对工作的怨恨增加有关,并且无法达到与那些住在工作场所附近的人相同的标准(Durhan,2019)。英国的研究人员发现,每天上下班额外 20 分钟的通勤时间与减薪 19%具有相同的负面影响(Loudenback,2017)。因此,毫不奇怪,离家的距离和环境满意度之间有很大的关系。因此,通勤时间越长,员工流失的可能性就越大。

因此,雇主在求职者身上寻找的一个可能因素是离家更近。然而,需要注意的是,这个问题还有其他解决方案,比如让工作时间更加灵活,因为按照员工离家的距离来排列员工可能不切实际,对公司也没有好处。此外,在新加坡这样一个拥有完善、高效公共交通系统的小国,雇员之间通勤时间的差异可能并不显著。

  • 工作满意度和关系满意度

工作满意度通常衡量员工对工作各个方面的满意程度,如工作的性质或范围。关系满意度衡量员工与同事和主管的关系。根据我们的结果,PercentSalaryHike、TrainingTimesLastYear、YearsInCurrentRole、YearsSinceLastPromotion 和 YearsWithCurrManager 是决定工作满意度和关系满意度的重要变量。也有其他变量没有包括在数据集中,但可能是重要的和有意义的,但不会进一步讨论。然而,这些变量中的大部分在雇用新员工时都是不相关的,因此不会进一步探讨。相反,公司可以利用这些变量来提高当前员工的工作和关系满意度,以提高当前员工的保留率。只有 YearsInCurrentRole 可能与简历有关。

担任当前职位的年限是一个变量,在确定所有 3 个满意度指标时非常重要。一个在当前职位上工作了很长一段时间的员工表明,他更有可能对当前的职位感到满意。因此,雇主可以筛选申请与他们以前工作相同职位的申请人,以了解他们在特定职位上的工作年限。工作年限较长的申请人可能会有较高的员工满意度,因此自然减员的可能性较低,因此雇主可以考虑优先考虑这些申请人。

  • 工作投入和工作生活平衡

工作投入是指一个人在心理和情感上参与到工作中的程度。工作生活平衡描述了一个人在工作和生活其他方面的平衡。这两个变量的结果偏离了我们的预期结果。这两个变量在决定工作满意度时被认为是重要的,但是我们的发现并不支持这一点。可以使用其他数据来源来进一步分析这种关系。尽管如此,它们在预测减员方面仍然很重要。然而,由于这些因素在简历中并不相关,公司可以利用它们来提高现有员工的保留率。

3.7 结论

雇主可以利用上面讨论的变量,根据员工流失的可能性对候选人进行排名。通过这些措施,可以降低公司的整体流失率,从而减少用于招聘和培训新员工的资源浪费,提高公司的整体盈利能力。

还有许多其他变量可能有助于雇主筛选出高流失率的申请人,这些变量没有包括在该数据集中,因此没有进行分析。可以进一步研究和评估这些外部因素在预测人员流失方面的重要性及其作为雇主筛选机制的实用性。

对这种分析的一种可能的改进是按部门划分数据集,并对每个部门分别进行分析,以便考虑不同部门之间可能出现的社会和文化差异。

减少员工流失的另一种方法是提高现有员工的留任率。上面提到的一些变量在预测自然减员方面很重要,但很难用来筛选申请人。相反,公司可以考虑利用这些因素来提高现有员工的保留率。可以对这些策略做进一步的分析和研究。通过实施这两种方法来提高现有员工的保留率和雇用流失率较低的新员工,公司更有可能看到员工流失率的大幅下降。

参考

Bertrand 和 s . Mullainathan(2003 年)。艾米丽和格雷格比拉基莎更适合工作吗

贾马尔呢。劳动力市场歧视的现场实验。doi: 10.3386/w9873

k . bouton(2015 年)。为文化契合而招聘。检索自

https://hbr.org/2015/07/recruiting-for-cultural-fit

钱德拉塞卡兰,S. (2018 年 1 月 14 日)。成为数据科学家—课程通过

都市地图。检索自

http://nirvacana . com/thinks/2013/07/08/成为一名数据科学家/

DataFlair 团队。(2019 年 5 月 23 日)。2019 年最常用的 14 种数据科学工具-基本数据

科学成分。检索自

https://data-flair.training/blogs/data-science-tools/

达勒姆,J. (2019,7 月 19 日)。上班通勤时间长的影响。检索于 11 月 6 日,

2019,来自http://www . safe workers . co . uk/effectsoflongcommutestwork . html

埃迪 J. (2014)。Google 一天收到多少份简历?检索自

http://eddiejackson.net/wp/? p = 2044 fqjcneir 3 wtgziryf 3 TD 7 vy 9-pIyvE-ig

高斯林,S. D .,伦特弗鲁,P. J .,,小斯旺,W. B. (2003)。一个非常简单的测量

大五人格领域。《人格研究杂志》, 37 (6),504–528。

r .约翰逊(2017 年 11 月 21 日)。员工满意度是由什么构成的?恢复

2019 年 11 月 6 日,来自

https://small business . chron . com/up-employee-satisfaction-22231 . html

约拿(2018 年 5 月 11 日)。数学帮助-对数定律。检索自

https://www.superprof.com.au/blog/rules-of-logarithms/

t . louden back(2017 年 10 月 23 日)。研究:上下班路上多花 20 分钟会让你

就像减薪 19%一样痛苦。检索自

https://www . Inc . com/business-insider/study-reveals-commune-time-impacts-job-satisf

action.html

马尔科维奇,M. (2019 年 2 月 4 日)。高离职率的负面影响。恢复

2019 年 11 月 6 日,来自

https://small business . chron . com/negative-impacts-high-over-rate-20269 . html

m .米勒托维奇(2019 年 9 月 9 日)。40 工作满意度统计:快乐的价值

工人。2019 年 11 月 6 日检索,来自

https://www . small biz genius . net/by-the-numbers/job-satisfaction-statistics/。

开放数据科学。(2018 年 11 月 2 日)。句子级情感导论

用 sentimentr 分析。检索自

https://medium . com/@ ODSC/an-introduction-to-sentence-level-analysis-wi

th-sentiment r-AC 556 BD 7 f 75 a

Rothe,p .,Lindholm,A.-L .,Hyvö nen,a .,& Nenonen,s .(未注明)。工作场所偏好–

年龄有影响吗?检索自

http://www.irbnet.de/daten/iconda/CIB21523.pdf

附录

附录 1A

每个清理阶段数据集的样本大小

之前

之后

删除停止字

数据科学家

数据分析师

数据工程师

移除频率 1 令牌

数据科学家

数据分析师

数据工程师

删除未正确处理的单词

数据科学家

数据分析师

数据工程师

通过单词词条清理

数据科学家

数据分析师

数据工程师

附录 1B

每个工作角色使用的前 10 个二元模型

文字云(DS)

Wordcloud (DA)

Wordcloud(德)

附录 1C

用图网络分析符号间的关系。例如,我们知道以单词“data”开头的二元结构非常常见,因为它与其他连接单词有许多关系,如“data science”和“data analyst”。

图网络关系(DS)

“数据”一词关系的放大网络(DS)

网络关系图(DA)

网络关系图(德)

附录 1D

主题建模也可以用模型来执行,例如潜在狄利克雷分配(LDA)模型是主题建模的一个例子。例如,单个文档可能有多个主题,这些主题可以被分类为“与猫相关”和“与狗相关”。LDA 识别固有的、不同的主题,并将单词分类到不同的类别中。在我们的例子中,我们将 DS、DA、DE 数据集合并在一起,并应用 LDA。我们的结果与我们的比例分析的结果相似,因为 LDA 模型已经识别出技术术语或不太有用的人口统计变量的不同主题。

3 个数据集的 LDA 模型

附录 1E

还可以对文本等非结构化数据执行聚类,以识别固有的主题或类别。在我们的例子中,尽管去除了稀疏项,但由于数据集中的大量标记,层次聚类树图是不可理解的。但是,通过使用“dendextend”包的“get_subdendrogram”函数,我们可以探索和构思这些子树状图。类似地,我们可以看到人口统计学术语,如“平等机会”、“种族肤色”,以及技术术语,如“数据科学家”、“机器学习”,被分组为不同的簇。

3 个数据集的子树状图矩阵

子树状图 1

子树状图 2

“技术术语”

“人口统计学术语”

附录 1F

十大编程语言(DS、DA、DE)

十大编程语言(DS)

十大编程语言(DA)

十大编程语言(德)

十大编程语言(DS、DA、DE)

所有编程语言(DS、DA、DE)的文档术语矩阵

附录 1G

十大数据科学工具(DS、DA、DE)

十大数据科学工具

十大数据科学工具(DA)

十大数据科学工具(DE)

十大数据科学工具(DS、DA、DE)

所有数据科学工具(DS、DA、DE)的文档术语矩阵

附录 1H

技术技能(DS,DA,DE)

技术技能(DS)

技术技能(DA)

技术技能(德)

技术技能(DS,DA,DE)

文档-术语-技术技能矩阵(DS,DA,DE)

附录 1I

软技能(DS,DA,DE)

软技能(DS)

软技能(DA)

软技能(德)

软技能(DS,DA,DE)

文档-术语-软技能矩阵(DS,DA,DE)

附录 1J

程序设计语言的文档-术语-矩阵(DS)

编程语言 DTM 的对数函数(DS)

重新计算提及的编程语言(DS)的比例

由于全部预定义列表中只有 8 种编程语言与数据科学家数据集相关,我们应该重新计算“总数”及其各自的“比例”,以便进行分析。

重新计算前

重新计算后

程序设计语言 DTM 加权评分(DS)

基于编程语言(DS)的每个候选人的总得分

附录 1K

数据科学工具的文档术语矩阵(DS)

用于数据科学工具(DS)的 DTM 对数函数

重新计算提及的数据科学工具(DS)的比例

由于整体预定义列表中只有 11 种数据科学工具与数据科学家数据集相关,因此我们应该重新计算“总数”及其各自在该分析中的“比例”。

重新计算前

重新计算后

数据科学工具(DS)DTM 加权评分

基于数据科学工具(DS)的每位候选人的总得分

附录 1L

文档-术语-技术技能矩阵(DS)

技术技能(DS)的 DTM 对数函数

提及技能的比例(DS)

DTM 技术技能加权评分(DS)

每个候选人基于技术技能的总得分(DS)

附录 1M

文档-术语-软技能矩阵(DS)

DTM 对数函数对于软技能(DS)

重新计算提及的软技能的比例

由于整个预定义列表中只有 4 项软技能与数据科学家数据集相关,因此我们应该重新计算“总数”及其各自的“比例”,以便进行分析。

重新计算前

重新计算后

软技能 DTM 加权评分(DS)

每位候选人基于软技能(DS)的总得分

附录 1N

程序设计语言的文档-术语-矩阵(DA)

用于编程语言的 DTM 对数函数(DA)

重新计算提及的编程语言的比例(DA)

由于全部预定义列表中只有 8 种编程语言与 Data Analyst 数据集相关,我们应该重新计算“总数”及其各自的“比例”,以便进行分析。

重新计算前

重新计算后

程序设计语言 DTM 的加权评分(DA)

基于编程语言(DA)的每个候选人的总得分

附录 1O

数据科学工具的文档-术语-矩阵(DA)

用于数据科学工具的 DTM 对数函数(DA)

重新计算提及的数据科学工具(DA)的比例

由于整体预定义列表中只有 4 种数据科学工具与 Data Analyst 数据集相关,因此我们应该重新计算该分析的“总数”及其各自的“比例”。

重新计算前

重新计算后

DTM 数据科学工具加权评分(DA)

基于数据科学工具(DA)的每位候选人的总得分

附录 1P

文档-术语-技能矩阵(DA)

技术技能 DTM 对数函数(DA)

重新计算提及的技能比例(DA)

由于整体预定义列表中只有 3 项技术技能与数据分析师数据集相关,我们应该重新计算“总数”及其各自的“比例”,以便进行分析。

重新计算前

重新计算后

DTM 技术技能加权评分(DA)

每个候选人基于技术技能的总得分(DA)

附录 1Q

文档-术语-软技能矩阵(DA)

DTM 对软技能的对数函数(DA)

重新计算提及的软技能的比例(DA)

重新计算前

重新计算后

软技能 DTM 加权评分(DA)

每位候选人基于软技能的总得分(DA)

附录 1R

程序设计语言的文档-术语-矩阵(DE)

DTM 编程语言的对数函数(德)

重新计算提及的编程语言的比例(DE)

由于全部预定义列表中只有 9 种编程语言与数据工程师数据集相关,因此我们应该重新计算“总数”及其各自的“比例”,以便进行分析。

重新计算前

重新计算后

编程语言 DTM 加权评分(DE)

基于编程语言的每个候选人的总得分(DE)

附录 1S

数据科学工具的文档术语矩阵

用于数据科学工具的 DTM 对数函数

提及数据科学工具的比例

数据科学工具 DTM 加权评分(DE)

基于数据科学工具(DE)的每位候选人的总得分

附录 1T

文档-术语-技能矩阵(德)

技术技能 DTM 对数函数(德)

重新计算提及的技能比例(DE)

重新计算前

重新计算后

DTM 技术技能加权评分(DE)

每个候选人基于技能的总得分(DE)

附录 1U

文档-术语-软技能矩阵(德)

DTM 对数函数为软技能(德)

重新计算提及的软技能(DE)的比例

重新计算前

重新计算后

软技能 DTM 加权评分(DE)

每个候选人基于软技能的总得分(DE)

附录 1V

假设每个类别的权重相等,我们相应地计算每个候选人的总计。但是,这可以通过部门负责人的意见进行更改,以更好地适应公司的需求。

DS 简历综合排名

大简历综合排名

德简历综合排名

附录 2A

跨部门尽责性得分方差分析结果

各行业尽责性得分方差分析结果

跨部门宜人性得分的方差分析结果

各行业宜人性得分的方差分析结果

跨部门公开性得分的方差分析结果

各行业开放度得分的方差分析结果

跨部门神经质得分的方差分析结果

各行业神经质得分的方差分析结果

附录 2B

各行业责任心得分箱线图

各部门责任心得分箱线图

各行业宜人性得分方框图

各部门宜人性得分方框图

各行业开放度得分箱线图

跨部门公开得分方框图

各行业神经质得分的箱线图

跨部门神经质得分箱线图

希望你喜欢这篇文章:-)我欢迎任何反馈,你可以在 LinkedIn 上找到我。

posted @ 2024-10-14 11:49  绝不原创的飞龙  阅读(246)  评论(0)    收藏  举报