TowardsDataScience-博客中文翻译-2019-二十七-

龙哥盟 / 2024-10-13 / 原文

TowardsDataScience 博客中文翻译 2019(二十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

足球:为什么赢家赢了,输家输了

原文:https://towardsdatascience.com/football-why-winners-win-and-losers-lose-56665e5be90e?source=collection_archive---------36-----------------------

Photo by Vienna Reyes on Unsplash

探索欧洲足球 5 年

介绍

在这本笔记本中,我们将探索现代足球指标(xG、xGA 和 xPTS)及其对体育分析的影响。

  • 预期目标(xG) —根据几个变量来衡量射门质量,如助攻类型、射门角度和与球门的距离,是否是头球射门以及是否被定义为大概率射门。
  • 预期助攻(xGA) —衡量给定传球成为进球助攻的可能性。它考虑了几个因素,包括传球类型、传球终点和传球长度。
  • 【xPTS】—衡量某场比赛给团队带来积分的可能性。

这些指标让我们更深入地观察足球统计数据,了解球员和球队的总体表现,并认识到运气和技巧在其中的作用。声明:它们都很重要。

这个 Kaggle 内核描述了这个笔记本的数据收集过程:网页抓取足球统计

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import collections
import warnings

from IPython.core.display import display, HTML

*# import plotly* 
import plotly
import plotly.figure_factory as ff
import plotly.graph_objs as go
import plotly.offline as py
from plotly.offline import iplot, init_notebook_mode
import plotly.tools as tls

*# configure things*
warnings.filterwarnings('ignore')

pd.options.display.float_format = '**{:,.2f}**'.format  
pd.options.display.max_columns = 999

py.init_notebook_mode(connected=True)

%load_ext autoreload
%autoreload 2

%matplotlib inline
sns.set()

*# !pip install plotly --upgrade*

导入数据和可视化 EDA

df = pd.read_csv('../input/understat.com.csv')
df = df.rename(index=int, columns={'Unnamed: 0': 'league', 'Unnamed: 1': 'year'}) 
df.head()

在下一个可视化中,我们将检查在过去 5 年中每个联盟有多少支球队排名前 4。它可以给我们一些关于不同国家顶尖球队稳定性的信息。

f = plt.figure(figsize=(25,12))
ax = f.add_subplot(2,3,1)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'Bundesliga') & (df['position'] <= 4)], ax=ax)
ax = f.add_subplot(2,3,2)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'EPL') & (df['position'] <= 4)], ax=ax)
ax = f.add_subplot(2,3,3)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'La_liga') & (df['position'] <= 4)], ax=ax)
ax = f.add_subplot(2,3,4)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'Serie_A') & (df['position'] <= 4)], ax=ax)
ax = f.add_subplot(2,3,5)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'Ligue_1') & (df['position'] <= 4)], ax=ax)
ax = f.add_subplot(2,3,6)
plt.xticks(rotation=45)
sns.barplot(x='team', y='pts', hue='year', data=df[(df['league'] == 'RFPL') & (df['position'] <= 4)], ax=ax)

正如我们从这些条形图中看到的,有些球队在过去 5 年中只进入过前 4 名,这意味着这并不常见,这意味着如果我们深入挖掘,我们会发现有一种运气因素可能对这些球队有利。这只是一个理论,所以让我们更接*那些离群值。

在过去的 5 个赛季中只有一次进入前 4 名的球队是:

  • 来自德甲的沃尔夫斯堡(2014)和沙尔克 04 (2017)
  • 来自 EPL 的莱斯特(2015)
  • 来自西甲的比利亚雷亚尔(2015)和塞维利亚(2016)
  • 来自意甲的拉齐奥(2014)和佛罗伦萨(2014)
  • 来自法甲的里尔(2018)和圣艾蒂安(2018)
  • 来自 RFPL 的罗斯托夫足球俱乐部(2015)和莫斯科迪纳摩足球俱乐部(2014)

让我们拯救这些队伍。

*# Removing unnecessary for our analysis columns* 
df_xg = df[['league', 'year', 'position', 'team', 'scored', 'xG', 'xG_diff', 'missed', 'xGA', 'xGA_diff', 'pts', 'xpts', 'xpts_diff']]

outlier_teams = ['Wolfsburg', 'Schalke 04', 'Leicester', 'Villareal', 'Sevilla', 'Lazio', 'Fiorentina', 'Lille', 'Saint-Etienne', 'FC Rostov', 'Dinamo Moscow']*# Checking if getting the first place requires fenomenal execution*
first_place = df_xg[df_xg['position'] == 1]

*# Get list of leagues*
leagues = df['league'].drop_duplicates()
leagues = leagues.tolist()

*# Get list of years*
years = df['year'].drop_duplicates()
years = years.tolist()

了解赢家如何获胜

在本节中,我们将尝试找到一些模式,这些模式可以帮助我们理解胜利之汤的一些成分:d .从德甲开始。

德甲联赛

first_place[first_place['league'] == 'Bundesliga']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'Bundesliga'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'Bundesliga'], name = 'Expected PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in Bundesliga",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

通过看表格和柱状图我们看到,拜仁每年都获得了比他们应该得到的更多的分数,他们的得分比预期的多,失误比预期的少(除了 2018 年,它没有打破他们赢得赛季的计划,但它给出了一些暗示,拜仁今年打得更差,尽管竞争对手没有利用这一点)。

*# and from this table we see that Bayern dominates here totally, even when they do not play well*
df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'Bundesliga')].sort_values(by=['year','xpts'], ascending=False)

西甲联赛

first_place[first_place['league'] == 'La_liga']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'La_liga'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'La_liga'], name = 'Expected PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in La Liga",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

从上面的图表中我们可以看到,在 2014 年和 2015 年,巴塞罗那创造了足够多的赢得冠军的时刻,而不是依靠个人技能或运气,从这些数字中我们可以实际上说球队正在那里比赛。

2016 年,马德里和巴塞罗那之间有很多竞争,最终,马德里在一场特定的比赛中变得更幸运/更有勇气(或者巴塞罗那变得不幸运/没有球),这是冠军的代价。我确信如果我们深入挖掘那个赛季,我们可以找到那场特殊的比赛。

2017 年和 2018 年,巴塞罗那的成功主要归功于莱昂内尔·梅西的行动,他在正常球员不会这样做的情况下得分或助攻。是什么导致 xPTS 差异如此之大。让我觉得(在这个赛季皇家马德里在转会市场上非常活跃的背景下)结果可能会很糟糕。只是基于数字和看巴萨比赛的主观看法。真希望我是错的。

*# comparing with runner-up*
df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'La_liga')].sort_values(by=['year','xpts'], ascending=False)

EPL

first_place[first_place['league'] == 'EPL']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'EPL'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'EPL'], name = 'Expected PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in EPL",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

在 EPL,我们看到一个明显的趋势,告诉你:“要想赢,你必须比统计数据更好”。有趣的案例是莱斯特在 2015 年的胜利故事:他们比他们应该得到的多了 12 分,同时阿森纳比预期少了 6 分!这就是我们热爱足球的原因,因为这样莫名其妙的事情发生了。我不是说这完全是运气,但它在这里发挥了作用。

另一件有趣的事是 2018 年的曼城——他们超级稳定!他们只比预期多进了一个球,少失了两个球,多得了 7 分,而利物浦打得很好,运气稍微好一点,但尽管比预期多了 13 分,还是没能赢。

Pep 正在完成制造毁灭机器。曼城根据技术创造和转换他们的时刻,而不是依靠运气——这使得他们在下一个赛季非常危险。

*# comparing with runner-ups* df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'EPL')].sort_values(by=['year','xpts'], ascending=False)

法甲联赛

first_place[first_place['league'] == 'Ligue_1']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'Ligue_1'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'Ligue_1'], name = 'Expected PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in Ligue 1",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

在法甲联赛中,我们继续看到这样的趋势:“要想赢,你必须付出 110%的努力,因为 100%是不够的”。在这里,巴黎圣日耳曼占据绝对优势。只有在 2016 年,我们在摩纳哥的比赛中遇到了一个异数,比预期多进了 30 个球!!!而且比预期多考了差不多 17 分!运气?相当不错的一部分。那一年 PSG 不错,但是摩纳哥非同一般。同样,我们不能说这是纯粹的运气或纯粹的技巧,而是两者在正确的时间和地点的完美结合。

*# comparing with runner-ups* df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'Ligue_1')].sort_values(by=['year','xpts'], ascending=False)

意甲联赛

first_place[first_place['league'] == 'Serie_A']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'Serie_A'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'Serie_A'], name = 'Expecetd PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in Serie A",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

在意大利甲级联赛中,尤文图斯已经连续 8 年称霸,尽管在冠军联赛中没有取得任何重大成功。我认为,通过检查这张图表和数字,我们可以了解到尤文在国内没有足够强的竞争,并获得了很多“幸运”的分数,这也源于多种因素,我们可以看到那不勒斯两次以 xPTS 超过尤文图斯,但这是现实生活,例如,在 2017 年,尤文疯狂地打进了额外的 26 个进球(或不知从哪里创造的进球),而那不勒斯比预期多错过了 3 个进球(由于守门员的错误或可能是一些球队在 1 或 2 场特定比赛中的出色表现)。就像皇马成为冠军时西甲联赛的情况一样,我确信我们可以找到那一年的一两场关键比赛。

足球中细节很重要。你看,这里一个错误,那里一个木制品,你就失去了冠军。

*# comparing to runner-ups* df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'Serie_A')].sort_values(by=['year','xpts'], ascending=False)

RFPL

first_place[first_place['league'] == 'RFPL']

pts = go.Bar(x = years, y = first_place['pts'][first_place['league'] == 'RFPL'], name = 'PTS')
xpts = go.Bar(x = years, y = first_place['xpts'][first_place['league'] == 'RFPL'], name = 'Expected PTS')

data = [pts, xpts]

layout = go.Layout(
    barmode='group',
    title="Comparing Actual and Expected Points for Winner Team in RFPL",
    xaxis={'title': 'Year'},
    yaxis={'title': "Points",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

我不关注俄罗斯超级联赛,所以仅仅通过冷眼看数据,我们就可以看到同样的模式,即从 2015 年到 2017 年,莫斯科中央陆军的得分超过了你应得的分数,这也是一个有趣的情况。在这些年里,这些人很优秀,但他们只转化了一次优势,其他两次——如果你不转化,你会受到惩罚,或者你的主要竞争对手只是转化得更好。

足球是没有公*可言的:d .虽然,我相信随着 VAR 的出现,接下来的几个赛季数字会变得更加稳定。因为那些额外的目标和分数的原因之一是仲裁人的错误。

*# comparing to runner-ups* df_xg[(df_xg['position'] <= 2) & (df_xg['league'] == 'RFPL')].sort_values(by=['year','xpts'], ascending=False)

统计概述

由于有 6 个联盟有不同的球队和统计数据,我决定集中在一个,在开始时,测试不同的方法,然后在其他 5 个上复制最终的分析模型。因为我主要看西甲联赛,所以我会从这场比赛开始,因为我对它了解最多。

*# Creating separate DataFrames per each league*
laliga = df_xg[df_xg['league'] == 'La_liga']
laliga.reset_index(inplace=True)
epl = df_xg[df_xg['league'] == 'EPL']
epl.reset_index(inplace=True)
bundesliga = df_xg[df_xg['league'] == 'Bundesliga']
bundesliga.reset_index(inplace=True)
seriea = df_xg[df_xg['league'] == 'Serie_A']
seriea.reset_index(inplace=True)
ligue1 = df_xg[df_xg['league'] == 'Ligue_1']
ligue1.reset_index(inplace=True)
rfpl = df_xg[df_xg['league'] == 'RFPL']
rfpl.reset_index(inplace=True)laliga.describe()

def print_records_antirecords(df):
  print('Presenting some records and antirecords: **n**')
  for col **in** df.describe().columns:
    if col **not** **in** ['index', 'year', 'position']:
      team_min = df['team'].loc[df[col] == df.describe().loc['min',col]].values[0]
      year_min = df['year'].loc[df[col] == df.describe().loc['min',col]].values[0]
      team_max = df['team'].loc[df[col] == df.describe().loc['max',col]].values[0]
      year_max = df['year'].loc[df[col] == df.describe().loc['max',col]].values[0]
      val_min = df.describe().loc['min',col]
      val_max = df.describe().loc['max',col]
      print('The lowest value of **{0}** had **{1}** in **{2}** and it is equal to **{3:.2f}**'.format(col.upper(), team_min, year_min, val_min))
      print('The highest value of **{0}** had **{1}** in **{2}** and it is equal to **{3:.2f}**'.format(col.upper(), team_max, year_max, val_max))
      print('='*100)

*# replace laliga with any league you want*
print_records_antirecords(laliga)***Presenting some records and antirecords:*** 

***The lowest value of SCORED had Cordoba in 2014 and it is equal to 22.00
The highest value of SCORED had Real Madrid in 2014 and it is equal to 118.00
================================================================
The lowest value of XG had Eibar in 2014 and it is equal to 29.56
The highest value of XG had Barcelona in 2015 and it is equal to 113.60
================================================================
The lowest value of XG_DIFF had Barcelona in 2016 and it is equal to -22.45
The highest value of XG_DIFF had Las Palmas in 2017 and it is equal to 13.88
================================================================
The lowest value of MISSED had Atletico Madrid in 2015 and it is equal to 18.00
The highest value of MISSED had Osasuna in 2016 and it is equal to 94.00
================================================================
The lowest value of XGA had Atletico Madrid in 2015 and it is equal to 27.80
The highest value of XGA had Levante in 2018 and it is equal to 78.86
================================================================
The lowest value of XGA_DIFF had Osasuna in 2016 and it is equal to -29.18
The highest value of XGA_DIFF had Valencia in 2015 and it is equal to 13.69
================================================================
The lowest value of PTS had Cordoba in 2014 and it is equal to 20.00
The highest value of PTS had Barcelona in 2014 and it is equal to 94.00
================================================================
The lowest value of XPTS had Granada in 2016 and it is equal to 26.50
The highest value of XPTS had Barcelona in 2015 and it is equal to 94.38
================================================================
The lowest value of XPTS_DIFF had Atletico Madrid in 2017 and it is equal to -17.40
The highest value of XPTS_DIFF had Deportivo La Coruna in 2017 and it is equal to 20.16***

现在让我们在图表上看看这些数字。

trace0 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2014], 
    y = laliga['xG_diff'][laliga['year'] == 2014],
    name = '2014',
    mode = 'lines+markers'
)

trace1 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2015], 
    y = laliga['xG_diff'][laliga['year'] == 2015],
    name='2015',
    mode = 'lines+markers'
)

trace2 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2016], 
    y = laliga['xG_diff'][laliga['year'] == 2016],
    name='2016',
    mode = 'lines+markers'
)

trace3 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2017], 
    y = laliga['xG_diff'][laliga['year'] == 2017],
    name='2017',
    mode = 'lines+markers'
)

trace4 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2018], 
    y = laliga['xG_diff'][laliga['year'] == 2018],
    name='2018',
    mode = 'lines+markers'
)

data = [trace0, trace1, trace2, trace3, trace4]

layout = go.Layout(
    title="Comparing xG gap between positions",
    xaxis={'title': 'Year'},
    yaxis={'title': "xG difference",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

trace0 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2014], 
    y = laliga['xGA_diff'][laliga['year'] == 2014],
    name = '2014',
    mode = 'lines+markers'
)

trace1 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2015], 
    y = laliga['xGA_diff'][laliga['year'] == 2015],
    name='2015',
    mode = 'lines+markers'
)

trace2 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2016], 
    y = laliga['xGA_diff'][laliga['year'] == 2016],
    name='2016',
    mode = 'lines+markers'
)

trace3 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2017], 
    y = laliga['xGA_diff'][laliga['year'] == 2017],
    name='2017',
    mode = 'lines+markers'
)

trace4 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2018], 
    y = laliga['xGA_diff'][laliga['year'] == 2018],
    name='2018',
    mode = 'lines+markers'
)

data = [trace0, trace1, trace2, trace3, trace4]

layout = go.Layout(
    title="Comparing xGA gap between positions",
    xaxis={'title': 'Year'},
    yaxis={'title': "xGA difference",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

trace0 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2014], 
    y = laliga['xpts_diff'][laliga['year'] == 2014],
    name = '2014',
    mode = 'lines+markers'
)

trace1 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2015], 
    y = laliga['xpts_diff'][laliga['year'] == 2015],
    name='2015',
    mode = 'lines+markers'
)

trace2 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2016], 
    y = laliga['xpts_diff'][laliga['year'] == 2016],
    name='2016',
    mode = 'lines+markers'
)

trace3 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2017], 
    y = laliga['xpts_diff'][laliga['year'] == 2017],
    name='2017',
    mode = 'lines+markers'
)

trace4 = go.Scatter(
    x = laliga['position'][laliga['year'] == 2018], 
    y = laliga['xpts_diff'][laliga['year'] == 2018],
    name='2018',
    mode = 'lines+markers'
)

data = [trace0, trace1, trace2, trace3, trace4]

layout = go.Layout(
    title="Comparing xPTS gap between positions",
    xaxis={'title': 'Position'},
    yaxis={'title': "xPTS difference",
    }
)

fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

从上面的图表中,我们可以清楚地看到,顶级球队得分更多,失球更少,获得的分数比预期的更多。这就是为什么这些球队都是顶级球队。和与外人完全相反的情况。中游球队的*均水*。完全符合逻辑,没有什么深刻的见解。

*# Check mean differences*
def get_diff_means(df):  
  dm = df.groupby('year')[['xG_diff', 'xGA_diff', 'xpts_diff']].mean()

  return dm

means = get_diff_means(laliga)
means

*# Check median differences*
def get_diff_medians(df):  
  dm = df.groupby('year')[['xG_diff', 'xGA_diff', 'xpts_diff']].median()

  return dm

medians = get_diff_medians(laliga)
medians

离群点检测

z 分数

z 得分是数据点相对于*均值的标准偏差数。假设|z-score| > 3 是异常值,我们可以使用它来查找数据集中的异常值。

*# Getting outliers for xG using zscore*
from scipy.stats import zscore
*# laliga[(np.abs(zscore(laliga[['xG_diff']])) > 2.0).all(axis=1)]*
df_xg[(np.abs(zscore(df_xg[['xG_diff']])) > 3.0).all(axis=1)]

*# outliers for xGA*
*# laliga[(np.abs(zscore(laliga[['xGA_diff']])) > 2.0).all(axis=1)]*
df_xg[(np.abs(zscore(df_xg[['xGA_diff']])) > 3.0).all(axis=1)]

*# Outliers for xPTS*
*# laliga[(np.abs(zscore(laliga[['xpts_diff']])) > 2.0).all(axis=1)]*
df_xg[(np.abs(zscore(df_xg[['xpts_diff']])) > 3.0).all(axis=1)]

zscore 总共检测到 12 个异常值。2016 年可怜的奥萨苏纳——* 30 个不该进的球。

正如我们从这个数据中看到的,处于异常空间顶端并不能让你赢得这个赛季。但是如果你错过了你的机会,或者在不该进球的地方进了球,而且进得太多——你应该降级。失败和*庸比胜利要容易得多。

四分位数间距(IQR)

IQR —是一组数据的第一个四分位数和第三个四分位数之间的差值。这是描述一组数据分布的一种方式。

一个常用的规则是,如果一个数据点高于第三个四分位数或低于第一个四分位数超过 1.5 个⋅ IQR,则该数据点是异常值。换句话说,低异常值低于 Q1 1.5⋅iqr,高异常值高于 Q3 + 1.5 ⋅ IQR。

我们去看看。

*# Trying different method of outliers detection* 
df_xg.describe()

*# using Interquartile Range Method to identify outliers*
*# xG_diff*
iqr_xG = (df_xg.describe().loc['75%','xG_diff'] - df_xg.describe().loc['25%','xG_diff']) * 1.5
upper_xG = df_xg.describe().loc['75%','xG_diff'] + iqr_xG
lower_xG = df_xg.describe().loc['25%','xG_diff'] - iqr_xG

print('IQR for xG_diff: **{:.2f}**'.format(iqr_xG))
print('Upper border for xG_diff: **{:.2f}**'.format(upper_xG))
print('Lower border for xG_diff: **{:.2f}**'.format(lower_xG))

outliers_xG = df_xg[(df_xg['xG_diff'] > upper_xG) | (df_xg['xG_diff'] < lower_xG)]
print('='*50)

*# xGA_diff*
iqr_xGA = (df_xg.describe().loc['75%','xGA_diff'] - df_xg.describe().loc['25%','xGA_diff']) * 1.5
upper_xGA = df_xg.describe().loc['75%','xGA_diff'] + iqr_xGA
lower_xGA = df_xg.describe().loc['25%','xGA_diff'] - iqr_xGA

print('IQR for xGA_diff: **{:.2f}**'.format(iqr_xGA))
print('Upper border for xGA_diff: **{:.2f}**'.format(upper_xGA))
print('Lower border for xGA_diff: **{:.2f}**'.format(lower_xGA))

outliers_xGA = df_xg[(df_xg['xGA_diff'] > upper_xGA) | (df_xg['xGA_diff'] < lower_xGA)]
print('='*50)

*# xpts_diff*
iqr_xpts = (df_xg.describe().loc['75%','xpts_diff'] - df_xg.describe().loc['25%','xpts_diff']) * 1.5
upper_xpts = df_xg.describe().loc['75%','xpts_diff'] + iqr_xpts
lower_xpts = df_xg.describe().loc['25%','xpts_diff'] - iqr_xpts

print('IQR for xPTS_diff: **{:.2f}**'.format(iqr_xpts))
print('Upper border for xPTS_diff: **{:.2f}**'.format(upper_xpts))
print('Lower border for xPTS_diff: **{:.2f}**'.format(lower_xpts))

outliers_xpts = df_xg[(df_xg['xpts_diff'] > upper_xpts) | (df_xg['xpts_diff'] < lower_xpts)]
print('='*50)

outliers_full = pd.concat([outliers_xG, outliers_xGA, outliers_xpts])
outliers_full = outliers_full.drop_duplicates()***IQR for xG_diff: 13.16
Upper border for xG_diff: 16.65
Lower border for xG_diff: -18.43
==================================================
IQR for xGA_diff: 13.95
Upper border for xGA_diff: 17.15
Lower border for xGA_diff: -20.05
==================================================
IQR for xPTS_diff: 13.93
Upper border for xPTS_diff: 18.73
Lower border for xPTS_diff: -18.41
==================================================****# Adding ratings bottom to up to find looser in each league (different amount of teams in every league so I can't do just n-20)*
max_position = df_xg.groupby('league')['position'].max()
df_xg['position_reverse'] = np.nan
outliers_full['position_reverse'] = np.nan

for i, row **in** df_xg.iterrows():
  df_xg.at[i, 'position_reverse'] = np.abs(row['position'] - max_position[row['league']])+1

for i, row **in** outliers_full.iterrows():
  outliers_full.at[i, 'position_reverse'] = np.abs(row['position'] - max_position[row['league']])+1total_count = df_xg[(df_xg['position'] <= 4) | (df_xg['position_reverse'] <= 3)].count()[0]
outlier_count = outliers_full[(outliers_full['position'] <= 4) | (outliers_full['position_reverse'] <= 3)].count()[0]
outlier_prob = outlier_count / total_count
print('Probability of outlier in top or bottom of the final table: **{:.2%}**'.format(outlier_prob))***Probability of outlier in top or bottom of the final table: 8.10%***

因此,我们可以说,很有可能每年在 6 个联赛中的一个联赛中,会有一支球队凭借他们出色的技术和运气获得冠军联赛或欧罗巴联赛的门票,或者有一支球队进入了乙级,因为他们不能转换他们的时刻。

*# 1-3 outliers among all leagues in a year*
data = pd.DataFrame(outliers_full.groupby('league')['year'].count()).reset_index()
data = data.rename(index=int, columns={'year': 'outliers'})
sns.barplot(x='league', y='outliers', data=data)
*# no outliers in Bundesliga*

我们表现出色和表现不佳的赢家和输家。

top_bottom = outliers_full[(outliers_full['position'] <= 4) | (outliers_full['position_reverse'] <= 3)].sort_values(by='league')
top_bottom

*# Let's get back to our list of teams that suddenly got into top. Was that because of unbeliavable mix of luck and skill?*
ot = [x for x  **in** outlier_teams if x **in** top_bottom['team'].drop_duplicates().tolist()]
ot
*# The answer is absolutely no. They just played well during 1 season. Sometimes that happen.*[]

结论

足球是一项低分的比赛,一个进球可以改变比赛的整个画面,甚至结束比赛结果。这就是为什么长期分析能让你对形势有更好的了解。

随着 xG 指标(以及由此衍生的其他指标)的引入,我们现在可以真正评估团队的长期表现,并了解顶级团队、中产阶级团队和绝对局外人之间的差异。

xG 为围绕足球的讨论带来了新的论点,这使得足球变得更加有趣。而同时,游戏又不失这种不确定的因素,以及疯狂的事情发生的可能性。其实现在,这些疯狂的事情有了解释的机会。

最终,我们发现,在某个联赛中,发生怪事的几率几乎是 100%。这将是一个多么史诗般的时刻,只是时间的问题。

带互动图表的原创作品可以在这里找到。

原载于 2019 年 9 月 11 日【http://sergilehkyi.com】

为了成功采用人工智能,我们需要更多的女性领导者

原文:https://towardsdatascience.com/for-the-successful-future-of-ai-women-have-to-take-the-lead-180f09be4e50?source=collection_archive---------14-----------------------

Why we need more women in AI

为什么女性拥有正确的品质来更成功地领导人工智能项目,并创造一个协作和包容的环境来构建现实世界的人工智能产品。

“21 世纪最激动人心的突破不会因为技术而出现,而是因为对人类意义的不断扩展的概念”

约翰·奈斯比特

第一部分:男女之间的差异

一个关于女性和男性如何以不同方式工作的故事

在我们深入探讨为什么更多女性应该领导人工智能团队之前,我想分享一个我从卢塞恩应用科学与艺术大学三年级学生 Tania Biland 那里听到的有趣故事。

塔尼亚讲述的故事:

上学期,为了给瑞士或德国品牌开发安全技术解决方案,我们班分成了三个不同的小组:

第一组: 仅限女性(我的组)

第二组: 仅限男性

第三组: 四女一男

经过 4 周的工作后,每个团队都要展示他们的作品。

第 1 组 ,仅由女性组成,在黑暗中为女性制定了安全解决方案。由于评审团只有男性,我们决定用角色、音乐和视频来讲述一个故事,以便让他们感受女性在日常生活中所经历的事情。我们还强调了这样一个事实,即每个人的生活中都有母亲、姐妹或妻子,他们可能不希望她/他们受苦。最终,我们的解决方案是相当简单的技术上的 :利用灯光提供安全但在情感上与观众 相连。

组 2 ,大多由男性组成,呈现了一个更具 高科技解决方案使用 AIGPS视频会议 。他们以 事实和数字 为论据,指出自己的 竞争优势 **

*****第 3 组,*4 女 1 男,结局好像还没完。小组中唯一的男性不同意被女性领导,因此他们花太多时间讨论小组动态,而不是工作。

这些小组不仅有不同的结果,而且处理问题的方式也不同。我所在的小组(小组 1)决定从定义彼此的工作偏好和风格开始,以便分配一些责任,并尽可能保持层级的扁*化。

另一方面,另外两个小组选出了一名组长。事实证明,这些“领导者”更像是独裁者,这导致了严重的冲突,团队花了几个小时讨论和争论,而我们的团队只是在工作和生产。

科学告诉我们性别差异

关于性别差异和对行为的影响的科学图景仍在发展,还没有为不同的行为提出一套清晰的科学解释。

通过汇总大部分研究,影响行为的主要因素有两个:

  1. 男女之间潜在的生理差异
  2. ****社会规范和压力形成不同的行为

在上面的故事中,正如 Tania 所讲述的,女性以一种协作的领导风格(【adhocracy culture】)开发了解决方案,以一种*乎扁*的层级结构根据任务调整领导地位。他们通过让所有利益相关者(在这种情况下,母亲和妻子=用户)参与进来,对他们的问题表示同情,从而得出他们的论点。他们看到了更广阔的前景,也构建了一个实际上已经完成的更简单的解决方案。

通过这个故事,我能够将为什么大多数人工智能项目最终都没有从原型阶段发展到现实应用的原因联系起来。

第二部分:让人工智能成功

为什么不采用 AI 产品?

根据我的经验,大多数人工智能和机器学习(ML)解决方案没有从原型阶段走向现实世界有三个主要原因:

  1. ****信任缺失:AI 或者 ML 产品最大的困难之一就是信任缺失。数百万美元已经花在原型上,但在现实世界的发射中几乎没有成功。本质上,做生意和为客户提供价值的最基本的价值观之一是信任,当涉及到道德问题和相关的信任问题时,人工智能是争论最激烈的技术。信任来自于在整个开发阶段涉及不同的选项和各方,这在原型阶段是做不到的。
  2. ****发布的复杂性:构建一个原型很容易,但在进入现实世界时,需要考虑数十个其他外部实体。除了技术挑战之外,还有其他需要与原型集成的领域(比如营销、设计和销售)。
  3. 人工智能产品通常不会考虑到所有的利益相关者:我听说过一个故事,在家庭暴力的情况下,Alexa 和 Google Home 被男性用来锁定他们的配偶。他们把音乐开得很大声,或者把他们锁在门外。在一个大多数男性工程师构建这些产品的环境中,可能没有人会考虑这种情况。此外,有许多例子表明人工智能和数据传感器可能带有偏见、性别歧视和种族主义[1]。

有趣的是,这三点都与技术挑战无关,所有这些都可以通过创建正确的团队来克服。

如何让 AI 更成功的被采用?

为了解决上述挑战并构建更成功的人工智能产品,我们需要专注于一种更加协作和社区驱动的方法

这考虑了不同利益攸关方的意见,特别是那些代表性不足的利益攸关方的意见。以下是实现这一目标的步骤:

第一步。让不同的团体参与进来。来自人才金字塔中间的女性

在技术领域,大多数公司都专注于雇佣人才金字塔顶端的人,主要由于历史原因,这里的女性较少。例如,大多数计算机科学班的女生不到 10%。然而,许多有才华的女性隐藏在金字塔的中间,通过在线课程自学却缺乏机会和鼓励。

Talent Pyramid

举个例子,我和极客女孩胡萝卜的主席聊过,这是一个在技术领域促进女性的组织。他们正在组织一个人工智能研讨会,有超过 125 名女性申请,但她们只有 25 个席位,所以自然地,她们不得不留下100 多名有才华的女性

想象一下,如果我们能让其他 100 名女性中的大多数参与进来,而不仅仅是高层。这将给更多女性提供在人工智能等新技术领域工作的机会。

第二步。与不同的利益相关者建立一个自下而上的公共协作团队

接下来,我们需要男性和女性以及不同利益相关者之间的更多合作,以便在真实市场中成功推出产品。这可以通过形成包容性的项目社区来实现,这些社区基于共同的价值观、信仰和更大的愿景来构建人工智能产品。

为了证明这一点,在过去的六个月里,我们召集了 50 多名男女学生来构建一个 ML 模型。在很短的时间内,成员们开始合作并互相帮助来建立模型。形成了四个小组,其中一个由两个女人领导,两个男人支持(数据标签)。其他组都是男性。在 4 个月的时间里,由两名女性和两名男性组成的小组建立了最精确的模型。从一开始,女性就比男性更愿意合作。然而,更有趣的是,我发现,由于团队中的其他女性,团队中的男性最终也表现得更加合作。这太迷人了!!

第三步。为协作创建正确的组织结构

如果我们可以创造不需要授权的组织结构和实践,因为从设计上来说,每个人都是强大的,没有人是无能为力的,那会怎么样?我已经看到,这可以通过连接内在和外在动机(与金钱无关)并创建一个没有竞争力的激励结构来实现。

在我的例子中,我建立了一个社区,其中导师位于金字塔的顶端,接着是社区经理,然后是致力于建立模型的工程师,最后是数据标记者。每个团队的成员都在努力向上爬,以达到下一个级别,这创造了一个外在的动机。然而,同一级别人员的货币补偿是相同的。这促进了合作。

在这种情况下,领导者的角色不是做老板,而是培养合作领导能力。这样的组织结构将减少控制人的需要,并提供共同学习和成长的机会[2]。

第三部分:连接第一部分和第二部分。

为什么女性应该领导人工智能团队

在一开始的故事中,女性小组遵循了一种更加协作的领导风格,表现出更多的顾客同理心和协作意愿。

考虑到 solar 项目中的有限实验,我们发现使用社区来构建产品的方法也有助于促进社区成员之间的协作和信任。

虽然上面提到的品质都不能一概而论,但下图旨在总结许多女性非常适合协作型领导的一些原因。

总之,我认为:

我们应该更全面地思考,尽最大努力创造合适的环境,让我们超越性别、种族和文化背景,专注于我们人类如何合作建设更美好的未来。

最后,我要感谢所有帮助我撰写这篇文章的人(包括男性和女性)——他们创造了体验和内容,也提炼了文本。

如果你想获得我们的人工智能挑战的更新,获得专家采访和提高你的人工智能技能的实用技巧,订阅我们的每月简讯。

我们也在脸书、 LinkedIn 和 Twitter 上。

预测 KPI:RMSE、梅伊、MAPE 和 Bias

原文:https://towardsdatascience.com/forecast-kpi-rmse-mae-mape-bias-cdc5703d242d?source=collection_archive---------0-----------------------

选择正确的预测指标并不简单。让我们回顾一下 RMSE、梅、MAPE 和偏见的利弊。剧透:MAPE 是最差的。不要用。

本文摘自我的著作 供应链预测的数据科学 。你可以在这里 阅读我的其他文章 。我也活跃在LinkedIn

Credit

衡量预测的准确性(或误差)并不是一件容易的事情,因为没有放之四海而皆准的指标。只有实验才能告诉你什么样的关键绩效指标(KPI)最适合你。正如你将看到的,每个指标将避免一些陷阱,但会倾向于其他。

我们要做的第一个区分是预测的精确度和它的偏差之间的区别:

  • 偏差代表历史*均误差。基本上,*均而言,你的预测是过高(即你超过需求)还是过低(即你低于需求)?这将给出错误的总体方向。
  • 精度衡量预测值和实际值之间的差距。预测的精度给出了误差大小的概念,但不是它们的总体方向。

当然,正如你在下图中看到的,我们想要的是一个既精确又公正的预测。

预测 KPI

错误

让我们首先将误差定义为预测减去需求。

请注意,如果根据此定义预测超出需求,误差将为正。如果预测低于需求,那么误差将为负。

偏见

偏差定义为*均误差:

其中 n 是既有预测又有需求的历史周期数。

由于一个项目上的正误差可以抵消另一个项目上的负误差,预测模型可以实现非常低的偏差,同时又不精确。显然,单凭偏差不足以评估你的预测精度。但是高度偏差的预测已经表明模型中有问题。

multidimensional assessment of philosophy of education 教育哲学的多维评价

*均绝对百分比误差(MAPE) 是衡量预测准确度最常用的 KPI 之一。

MAPE 是个体绝对误差的总和除以需求(每个时期分开)。它是百分比误差的*均值。

MAPE 是一个非常奇怪的预测 KPI。

尽管这是一个不太准确的指标,但它在企业经理中是众所周知的。正如你在公式中看到的,MAPE 将每个误差单独除以需求,所以它是偏斜的:低需求时期的高误差将显著影响 MAPE。因此,优化 MAPE 将导致一个奇怪的预测,很可能会低于需求。避开就好。

*均绝对误差

*均绝对误差(MAE) 是衡量预测准确性的一个非常好的 KPI。顾名思义,就是绝对误差的均值。

此 KPI 的首要问题之一是它没有根据*均需求进行调整。如果有人告诉你,某个特定项目的 MAE 是 10,你无法知道这是好是坏。如果你的*均需求是 1000,这当然是惊人的。尽管如此,如果*均需求是 1,这是一个非常差的精度。为了解决这个问题,通常将 MAE 除以*均需求得到一个百分比:

MAPE/梅混淆——似乎许多从业者使用梅公式,并将其称为 MAPE。这可能会造成很多混乱。当与某人讨论预测误差时,我总是建议你明确地展示你如何计算预测误差,以确保比较苹果和苹果。

均方根误差

均方根误差(RMSE) 是一个奇怪的 KPI,但是非常有用,我们将在后面讨论。它被定义为*均*方误差的*方根。

就像 MAE 一样,RMSE 也不能满足需求。我们可以这样定义 RMSE%,

实际上,许多算法(尤其是机器学习)都是基于均方误差(MSE) ,这与 RMSE 直接相关。

许多算法使用 MSE,因为它比 RMSE 计算更快,更容易操作。但是它没有被缩放到原始误差(因为误差是*方的),导致我们无法将 KPI 与原始需求缩放相关联。因此,我们不会用它来评估我们的统计预测模型。

误差加权的问题

与梅相比,RMSE 对每个错误都一视同仁。它更重视最重要的错误。这意味着一个大的错误就足以得到一个非常糟糕的 RMSE。

让我们用一个虚拟需求时间序列来做一个例子。

假设我们想要比较两个略有不同的预测。唯一的区别是对最新需求观察的预测:预测#1 比它少 7 个单位,而预测#2 只比 6 个单位。

如果我们查看这两个预测的 KPI,我们会发现:

有趣的是,通过将最后一个周期的误差改变一个单位,我们将总 RMSE 降低了 6.9% (2.86 到 2.66)。尽管如此,MAE 只减少了 3.6% (2.33 到 2.25),所以对 MAE 的影响低了*两倍。显然,RMSE 强调最重要的错误,而梅对每个错误都给予同等的重视。你可以自己尝试一下,减少一个最准确时期的误差,观察对梅和 RMSE 的影响。

剧透:对 RMSE 几乎没有影响。

稍后你会看到,RMSE 还有其他一些非常有趣的特性。

你想预测什么?

我们仔细检查了这些 KPI 的定义(bias、MAPE、MAE、RMSE),但是仍然不清楚使用一个 KPI 代替另一个 KPI 会对我们的模型产生什么影响。有人可能会认为,用 RMSE 代替梅或梅代替 MAPE 不会改变任何事情。但是没有什么是不真实的。

让我们做一个简单的例子来说明这一点。

让我们想象一下,一个产品的周需求量很低,而且相当*稳,但不时会有一个大订单(可能是由于促销或客户批量订购)。这是我们目前观察到的每周需求:

现在让我们设想我们对这种产品提出三种不同的预测。第一个预测 2 件/天,第二个预测 4 件,最后一个预测 6 件。让我们把我们观察到的需求和这些预测画出来。

让我们看看这些预测在历史时期的偏差、MAPE、梅伊和 RMSE 方面的表现:

这意味着,就 MAPE 而言,预测#1 是历史期间最好的,就*均月*均日而言,预测#2 是最好的。预测#3 在 RMSE 和偏差方面是最好的(但在梅和 MAPE 方面是最差的)。现在让我们来揭示这些预测是如何做出的:

  • 预测 1 只是一个很低的量。
  • 预测 2 是需求中位数:4。
  • 预测 3 是*均需求。

中位数与*均数—数学优化

在进一步讨论不同的预测 KPI 之前,让我们花一些时间来理解为什么中位数的预测会得到好的 MAE 和*均数的预测会得到好的 RMSE

前面有一点数学。如果你对这些等式不清楚,这不是问题,不要气馁。跳过它们,直接跳到 RMSE 和梅埃塔勒的结论。

RMSE

让我们从 RMSE 开始:

为了简化下面的代数,让我们使用一个简化版本:均方误差(MSE):

如果您将 MSE 设置为预测模型的目标,它会将其最小化。人们可以通过将一个数学函数的导数设为零来最小化它。让我们试试这个。

结论为了优化预测的 MSE,该模型必须以总预测等于总需求为目标。也就是说,优化 MSE 的目的是产生*均正确的预测,因此是无偏的。

现在让我们为梅做同样的事情。

或者,

这意味着

结论为了优化 MAE(即将其导数设置为 0),预测需要比需求高很多倍,因为它比需求低。换句话说,我们正在寻找一个将数据集分成两个相等部分的值。这是中位数的确切定义。

MAPE

不幸的是,MAPE 的衍生物不会显示一些优雅和简单的属性。我们可以简单地说,MAPE 提出了一个非常低的预测,因为当需求较低时,它为预测误差分配了较高的权重。

结论

正如我们上面看到的,在任何模型中,RMSE 的优化将寻求*均正确。相比之下,MAE 的优化将试图经常超过需求和低于需求,这意味着以需求中值为目标。我们必须明白,一个显著的区别在于梅和 RMSE 的数学根源。一个瞄准中位数,一个瞄准*均数。

梅和 RMSE——选择哪一个?

以需求的中间值或*均值为目标更糟糕吗?嗯,答案不是非黑即白的。每种技术都有一些好处和一些风险,我们将在下一页讨论。只有实验才能揭示哪种方法最适合数据集。你甚至可以选择同时使用 RMSE 和梅。

让我们花些时间来讨论选择 RMSE 或 MAE 对偏差、对异常值的敏感性和间歇性需求的影响。

偏见

对于许多产品,你会发现中间值与*均需求并不相同。需求很可能会在这里或那里出现一些峰值,这将导致一个偏斜的分布。这些不对称的需求分布在供应链中普遍存在,因为峰值可能是由于定期促销或客户批量订购造成的。这将导致需求中位数低于*均需求,如下所示。

这意味着最小化 MAE 的预测将导致偏差。相比之下,最小化 RMSE 的预测不会导致偏差(因为它的目标是*均值)。这绝对是 MAE 的主要弱点。

对异常值的敏感度

正如我们所讨论的,RMSE 更重视最高的错误。这是有代价的:对异常值的敏感性。让我们想象一个需求模式如下的物品。

中位数是 8.5,*均数是 9.5。我们已经观察到,如果我们做出最小化 MAE 的预测,我们将预测中位数(8.5),并且我们将*均低于需求 1 个单位(偏差= -1)。然后,您可能希望最小化 RMSE,并预测*均值(9.5)来避免这种情况。

然而,现在让我们假设我们有一个新的需求观察值 100。

中位数还是 8.5(没变!),但是现在*均是 18.1。在这种情况下,您可能不想预测*均值,而可能会恢复到预测中值。

一般来说,中位数比*均数对异常值更稳健。这在供应链环境中相当重要,因为由于编码错误或需求高峰(营销、促销、现货交易),我们可能会面临许多异常值。

对异常值的鲁棒性总是一件好事吗?号码

间歇需求

事实上,不幸的是,中位数对异常值的稳健性会对具有间歇性需求的项目产生非常恼人的影响。

让我们想象一下,我们把一个产品卖给一个客户。这是一种高利润的产品。不幸的是,我们独一无二的客户似乎每三周就下一次订单,没有任何规律可循。客户总是以 100 件为一批订购产品。然后,我们的*均周需求为 33 件,需求中位数为… 0。

我们必须填充该产品的每周预测。假设我们做了第一次预测,目标是*均需求(33 件)。从长期来看,我们将获得 6,667 的总*方误差(RMSE 为 47)和 133 的总绝对误差(*均误差为 44)。

现在,如果我们预测需求中位数(0),我们会得到 100 的总绝对误差(MAE 为 33)和 10.000 的总*方误差(RMSE 为 58)。

正如我们所看到的,MAE 对于间歇性需求来说是一个不好的 KPI。一旦有超过一半的期间没有需求,最佳预测就是… 0!

结论

梅保护离群值,而 RMSE 向我们保证得到一个无偏见的预测。您应该使用哪个指标?不幸的是,没有明确的答案。作为一名供应链数据科学家,您应该进行试验:如果使用 MAE 作为 KPI 会导致高偏差,您可能会想要使用 RMSE。如果数据集包含许多异常值,导致预测不准确,您可能需要使用 MAE。

请注意,您可以选择用一个或多个 KPI(通常是 MAE 和 bias)报告预测误差,并使用另一个 KPI(RMSE?)来优化你的模型。

针对低需求项目使用的最后一个技巧是将需求汇总到更高的时间范围。例如,如果每周的需求很低,您可以测试月度预测甚至季度预测。您总是可以通过简单的划分将预测分解回原始时段。这种技术可以让您将 MAE 用作 KPI,同时*滑需求峰值。

关于作者

在 LinkedIn 上关注我!

[## Nicolas vande put——顾问,创始人——供应链| LinkedIn

查看 Nicolas Vandeput 在世界上最大的职业社区 LinkedIn 上的个人资料。尼古拉斯有 7 份工作列在…

www.linkedin.com](https://www.linkedin.com/in/vandeputnicolas/)

icolas Vandeput 是一名供应链数据科学家,擅长需求预测和库存优化。他在 2016 年创立了自己的咨询公司 SupChains ,并在 2018 年共同创立了 SKU 科学——一个快速、简单、实惠的需求预测*台。尼古拉斯对教育充满热情,他既是一个狂热的学习者,也喜欢在大学教学:自 2014 年以来,他一直在比利时布鲁塞尔为硕士学生教授预测和库存优化。自 2020 年以来,他还在法国巴黎的 CentraleSupelec 教授这两个科目。他于 2018 年出版了 供应链预测的数据科学(2021 年第 2 版)和 2020 年出版了 库存优化:模型与模拟

先知中使用附加回归器的预测模型调整

原文:https://towardsdatascience.com/forecast-model-tuning-with-additional-regressors-in-prophet-ffcbf1777dda?source=collection_archive---------3-----------------------

关于如何在先知模型中添加回归因子以提高预测精度的说明

Use case — bike rental (picture source: Pixabay)

我将把我的实验结果分享给预言家附加回归器。我的目标是检查额外的回归将如何影响先知计算的预测。

使用来自 Kaggle 的数据集— 华盛顿州的自行车共享数据集。数据附带了每天自行车租金和天气情况的数字。我创建并比较了三个模型:

  1. 带有自行车租赁日期和数量的时间序列先知模型
  2. 带有附加回归器的模型——天气温度
  3. 带有附加回归器 s 的模型——天气温度和状态(下雨、晴天等)。)

我们应该看到回归的效果,并比较这三个模型。

预测是为未来 10 天计算的。数据集中的最后一天是 2012 年 12 月 31 日,这意味着预测从 2013 年 1 月 1 日开始。

A .无附加回归器的模型

从 2013 年 1 月 1 日开始的自行车租赁预测值:

Bike rentals forecast for the next ten days

B .带附加回归器的模型-天气温度

回归器的值必须在过去和将来都是已知的,这是它如何帮助先知调整预测的。未来值必须是预定义的和已知的(例如,在特定日期发生的特定事件),或者应该在其他地方预测。就我们的情况而言,我们使用的是天气温度预报,可以从天气频道获得。

回归器的值必须与时间序列数据位于同一数据框中。我复制了一个要定义为索引列的日期列:

df = pd.read_csv('weather_day.csv')
df = df[['dteday', 'cnt', 'temp']].dropna()d_df['date_index'] = d_df['dteday']
d_df['date_index'] = pd.to_datetime(d_df['date_index'])
d_df = d_df.set_index('date_index')

我们需要构建未来十天的数据框架——从 2013 年 1 月 1 日到 2001 年 10 天创建熊猫数据框架,并使用温度预测(标准化值)初始化每个元素:

t = 13
min_t = -8
max_t = 39
n_t = (t - min_t)/(max_t - min_t)
print(n_t)future_range = pd.date_range('2013-01-01', periods=10, freq='D')
future_temp_df = pd.DataFrame({ 'future_date': future_range, 'future_temp' : 0})future_temp_df['future_date'] = pd.to_datetime(future_temp_df['future_date'])
future_temp_df = future_temp_df.set_index('future_date')future_temp_df.at['2013-01-01', 'future_temp'] = 0.319148
future_temp_df.at['2013-01-02', 'future_temp'] = 0.255319
future_temp_df.at['2013-01-03', 'future_temp'] = 0.234042
future_temp_df.at['2013-01-04', 'future_temp'] = 0.319148
future_temp_df.at['2013-01-05', 'future_temp'] = 0.340425
future_temp_df.at['2013-01-06', 'future_temp'] = 0.404255
future_temp_df.at['2013-01-07', 'future_temp'] = 0.361702
future_temp_df.at['2013-01-08', 'future_temp'] = 0.404255
future_temp_df.at['2013-01-09', 'future_temp'] = 0.425531
future_temp_df.at['2013-01-10', 'future_temp'] = 0.446808future_temp_df.tail(10)

在下面的代码中,我添加了天气温度的回归器。如果日期属于训练集,则从训练集返回温度,否则从未来预测数据框(上面构建的数据框)返回温度。未来十天的期限已经设定。先知模型是用拟合函数构建的,调用预测函数来计算预测:

def weather_temp(ds):
    date = (pd.to_datetime(ds)).date()

    if d_df[date:].empty:
        return future_temp_df[date:]['future_temp'].values[0]
    else:
        return (d_df[date:]['temp']).values[0]

    return 0m = Prophet()
m.add_regressor('temp')
m.fit(d_df)future = m.make_future_dataframe(periods=10)
future['temp'] = future['ds'].apply(weather_temp)forecast = m.predict(future)
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(15)

从 2013 年 1 月 1 日开始,自行车租赁的预测值,以及附加的温度回归器。天气预报显示气温良好,预计 1 月份天气温暖,这有助于将自行车租赁数量调整到更高水*(如果天气温度良好,自然会有更多的租赁):

Bike rentals forecast for the next ten days, with temperature regressor

C .具有两个附加回归因子的模型-天气温度和条件

数据集包含相当多的描述天气的属性,使用更多的这些属性将有助于计算更准确的自行车租赁预测。我将展示增加一个回归变量如何改变预测。

def weather_temp(ds):
    date = (pd.to_datetime(ds)).date()

    if d_df[date:].empty:
        return future_temp_df[date:]['future_temp'].values[0]
    else:
        return (d_df[date:]['temp']).values[0]

    return 0def weather_condition(ds):
    date = (pd.to_datetime(ds)).date()

    if d_df[date:].empty:
        return future_temp_df[date:]['future_weathersit'].values[0]
    else:
        return (d_df[date:]['weathersit']).values[0]

    return 0m = Prophet()
m.add_regressor('temp')
m.add_regressor('weathersit')
m.fit(d_df)future = m.make_future_dataframe(periods=10)
future['temp'] = future['ds'].apply(weather_temp)
future['weathersit'] = future['ds'].apply(weather_condition)forecast = m.predict(future)
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(15)

使用上述代码添加了额外的回归变量—天气条件(数据集中的 check weathersit 属性)以及天气温度回归变量。出于测试的目的,我将未来十天的天气条件设置为 4(这意味着天气不好)。即使一月份的天气温度在上升(这对自行车租赁来说是好事),整体天气还是很糟糕(这应该会减少自行车租赁的数量)。

使用第二个回归变量(指向预期的坏天气),Prophet 返回较小的预期自行车租赁数量:

Bike rentals forecast for the next ten days, with temperature regressor and weather condition

总结:在 Prophet 中,附加回归量功能对于精确预测计算非常重要。它有助于调整预测的构建方式,并使预测过程更加透明。回归量必须是过去已知的变量,并且是已知的(或对未来单独预测的)。

资源:

  • GitHub 回购与源代码
  • 我以前的一篇关于同一主题的文章— 用烧瓶为先知模型服务—预测未来

用机器学习预测收入惊喜

原文:https://towardsdatascience.com/forecasting-earning-surprises-with-machine-learning-68b2f2318936?source=collection_archive---------16-----------------------

如何预测哪些公司将超过或低于分析师的收益预期

上市公司发布季度收益报告,当结果偏离分析师的估计时,会引起重大的价格波动。这是因为根据有效市场假说,资产价格完全反映了所有可获得的信息,因此会成为共识估计的一个因素。在本文中,我们将了解如何使用机器学习来预测一家公司是否会超出或低于其预期。

数据

我们考虑来自汤姆森路透 I/B/E/S 估计数据库的每股收益分析师估计,并从 Sentieo 下载。该数据库收集并汇编了分析师对 20 多项指标的估计。对于每家公司,我们给出了估计值的*均值、估计数、低值、高值和实际值,如下所示:

不幸的是,对于这个数据库,我们每个公司只有 70 个数据点,这不足以根据以前公布的结果和他们的 Beat/Miss vs 估计来预测一个公司的收益,但我们可以重新构建问题以增加数据点的数量。

不要问我们自己一个公司是否会超出或错过估计,我们可以问估计值是否会高于或低于实际值。

然后,我们将对这些值进行归一化,以便对它们进行聚合。在这种情况下,我们将为我们的模型考虑的特征是:

  • 估计值

  • 低/*均百分比
  • 高/*均百分比
  • 实际/*均百分比

然后,我们决定按部门汇总估计值,以检验分析师准确预测收益的能力与公司性质相关的假设。在这项研究中,我们将重点关注医疗保健股。

然后,我们对以下 117 家公司进行了 6000 次评估:

AAC ',' ABT ',' ABBV ',' ACHC ',' XLRN ',' ACOR ',' AERI ',' AGIO ',' AIMT ',' AKCA ',' AKBA'
,' AKRX ',' ALXN ',' ALGN ',' AGN ',' ALNY ',' AMRN ',' AMGN'
,' FOLD ',' ARRY ',' ASND ',' AZN ',' ATRC ',' AVNS'
,' BHC ',' BAX ',' BDX ',' BCRX ',' BMRN ',' TECH ',' BEAT ',' BLUE' 【T7 ',' BSX ',' BMY ','

处理数据

我们将数据上传到 AuDaS ,这是一个由 Mind Foundry 为分析师打造的数据科学和教育*台。为了提高模型的准确性,我们创建了一个新列来表示实际值是高于(1)还是低于(-1)实际值(相对于 a %)。

我们还可以通过自动生成的直方图来可视化数据,并查看节拍/缺失如何跨其他特征分布。

构建我们的机器学习模型

由于我们预测节拍/缺失列,因此我们将构建一个分类器,同时排除实际/*均列。我们还将坚持由 AuDaS 自动选择的推荐训练配置,以防止过度拟合(10 倍交叉验证和 10%坚持验证)。

然后,AuDaS 将开始使用 Mind Foundry 的专有优化器 OPTaaS 搜索最佳机器学习模型,该优化器已迅速成为量化基金行业最受欢迎的快速全局优化和超参数调整工具。

在不到一分钟的时间里,AuDaS 已经尝试了 37 种不同的机器学习模型,找到的最佳解决方案是一个简单的梯度提升分类器。将鼠标悬停在模型上可显示其参数值:

该模型的相对特征相关性表明低/均值、高/均值比率包含最多的信息。

测试模型

然后,我们可以在 10%的保留率上测试模型:

AuDaS 实现了 69.4%的分类准确度,并且最终的模型健康建议是好的。

结论和延伸

凭借相对较少的功能,AuDaS 能够建立一个准确的预测模型,支持投资分析师对 IBES 估值的评估。这可以使他们预测重大的价格变动。

这项研究的延伸将是使用 AuDaS 的聚类功能对多个部门的估计值进行分组。这将使我们能够检验这样一个假设,即公司治理等其他因素将比行业更能影响预测的成功/失败比率。

如果您有兴趣了解我们的 Quant 和基本面对冲基金客户如何使用澳元进行风险分析和投资管理,请不要犹豫,通过电子邮件或 LinkedIn 联系我。您还可以阅读以下更多案例研究:

[## 集群风险管理

如何揭开表面下的结构

towardsdatascience.com](/risk-management-with-clustering-fd594e064806) [## 机器学习的价值投资

你最喜欢的持有期不一定是永远…

towardsdatascience.com](/value-investing-with-machine-learning-e41867156108) [## 用数据科学充实投资分析师

基本面投资如何受益于机器学习

towardsdatascience.com](/augmenting-investment-analysts-with-data-science-98297cb1ccb0)

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

更新:我开了一家科技公司。你可以在这里找到更多的

团队和资源

Mind Foundry 是牛津大学的一个分支,由斯蒂芬·罗伯茨和迈克尔·奥斯本教授创立,他们在数据分析领域已经工作了 35 年。Mind Foundry 团队由 30 多名世界级的机器学习研究人员和精英软件工程师组成,其中许多人曾是牛津大学的博士后。此外,Mind Foundry 通过其分拆地位,拥有超过 30 名牛津大学机器学习博士的特权。Mind Foundry 是牛津大学的投资组合公司,其投资者包括牛津科学创新、牛津技术与创新基金、牛津大学创新基金和 Parkwalk Advisors 。

利用历史数据预测加密货币的未来价格

原文:https://towardsdatascience.com/forecasting-future-prices-of-cryptocurrency-using-historical-data-83604e72bc68?source=collection_archive---------10-----------------------

加密货币(cryptocurrency)这个词已经席卷了金融界,然而目前还缺乏对数字资产数据的正式和公开的研究。这篇博文旨在建立在这篇 文章 中进行的探索性数据分析的基础上。我们将在这里使用可用的数据集来预测不同加密货币的未来价格。

在 EDA 之后,预测是下一步,你需要预测价格的未来值。对于有兴趣投资这些加密货币的人来说,这可能具有巨大的商业价值。

我们将尝试通过使用 closing_price 特性来预测比特币的未来价格。

用什么型号?

为了进行预测,我们需要一个机器学习模型。大多数人想预测值的时候都会想到多元线性回归。但是对于时间序列数据,这不是一个好主意。不选择时间序列数据回归的主要原因是我们对预测未来感兴趣,这将是线性回归的外推(预测数据范围之外)。我们知道,在线性回归中,任何形式的外推都是不可取的。

对于时间序列数据,最好使用自回归综合移动*均ARIMA 模型。

ARIMA

ARIMA 实际上是一类模型,它基于给定的时间序列的过去值来“解释”给定的时间序列,即其自身的滞后和滞后预测误差,因此该方程可用于预测未来值。任何“非季节性”的时间序列显示模式,不是一个随机的白噪声可以用 ARIMA 模型建模。如下所述,假设检验表明价格不是季节性的,因此我们可以使用 ARIMA 模型。在我们的 EDA 阶段,我们还发现任何加密货币都没有系统模式。

Non-Seasonal Trend of Omisego’s Prices

要创建 ARIMA 模型,我们需要 3 个参数:

  • p;自回归项的阶
  • ;移动*均项的阶
  • d;使时间序列*稳所需的差分次数

确定*稳性

我们将需要时间序列数据是*稳的,因为术语自动回归在 ARIMA 意味着它是一个线性回归模型,使用它自己的滞后作为预测器。如你所知,当预测因子不相关且相互独立时,线性回归模型效果最佳。

为了实现*稳性,我们需要执行差分:从当前值中减去前一个值。有时,根据系列的复杂程度,可能需要一个以上的差异。在我们这样做之前,我们需要检查我们的数据是否已经是稳定的。为此,我们将使用 增强的 Dickey Fuller 测试。这是一个假设检验,假设零假设为“自回归模型中存在单位根”。单位根检验时间序列变量是否是非*稳的,是否有单位根。如果一个数列有一个单位根,它就显示出一个系统的模式。在这种情况下,另一个假设是“没有单位根存在”,这意味着时间序列是*稳的。

result = adfuller(df["Close]).dropna())

测试返回一个为 0.002114P 值。这远低于我们设定的 0.05 的显著性水*,因此我们拒绝零假设,并得出数据是*稳的结论。

由于数据是静态的,我们不需要执行任何差分。因此,参数 d 的值将为 0。

确定 AR 项的阶数

p自回归 (AR)项的顺序。它是指用作预测值的 Y 的滞后数。我们可以通过查看偏相关 函数 (PACF)图来找出所需的 AR 项数。在排除中间滞后的贡献后,部分自相关可以被想象为序列和它的滞后之间的相关性。**

我们可以观察到,PACF 滞后 1 是唯一一个非常显著的值,与其他值相比,它远远高于显著性线。因此,我们可以安全地将 p 设置为 1。

确定 MA 术语的顺序

q移动*均线 (MA)项的顺序。它是指应该进入 ARIMA 模型的滞后预测误差的数量。MA 术语在技术上是滞后预测的误差。**

就像我们看 PACF 图中 AR 项的数量一样,你也可以看 ACF 图中 MA 项的数量。ACF 告诉我们需要多少 MA 项来消除*稳序列中的任何自相关。

计算显著线以上的滞后数。所以,我们暂定 q 为 8。

构建模型

既然我们已经有了所有需要的参数,现在我们将构建模型。

model = ARIMA(df["Close"], order=(1,0,8))
model_fit = model.fit(disp=0)
print(model_fit.summary())

ARIMA MODEL FOR p=1, d=0, q=8

我们可以注意到,MA 项的 P > |z|中的 P 值远小于 0.05。因此,我们可以理想地去掉一些 MA 项并重建模型。由于三项显著高于显著性水*,我们将 q 设为 3。

model = ARIMA(df["Close"], order=(1,0,3))

ARIMA Model for revised parameters

评估模型

既然模型已经被拟合,我们现在将测试我们的 ARIMA 模型。为此,我们现在将数据集分为两部分:

  • 训练数据(原始数据集的 80%)
  • 测试数据(原始数据集的 20%)
X = bit_df["Close"].values
train_size = int(len(X) * 0.80)
predictions = model_fit.predict(train_size,len(X)-1)
test = X[train_size:len(X)]
error = mean_squared_error(test, predictions)

model_fit.predict()获取测试数据的开始和结束索引。然后,通过计算均方误差,将结果与测试数据集的目标值进行比较。

均方差的值出来是~ 575.24 。当我们看到数据跨越了 5 年的每日条目时,这个误差并不大。然而,仅仅是均方误差值并不能让我们清楚地知道我们的模型有多精确。因此,我们将可视化测试数据的预测值和实际值的比较。

Actual closing values VS Predicted closing values

查看图表,我们可以看到收盘价的预测值和实际值非常接*。

那都是乡亲们!祝你有愉快的一天。

预测:如何检测异常值?

原文:https://towardsdatascience.com/forecasting-how-to-detect-outliers-cb65faafcd97?source=collection_archive---------5-----------------------

对于需求计划者来说,异常值可能是一个痛苦。让我们来看看是什么导致了它们,以及标记它们的 3 种技术。

下面这篇文章摘自我的《供应链预测的数据科学》一书,这里有。你可以在这里* 找到我的其他出版物 。我也活跃在LinkedIn*。

“今天我不想进一步尝试去定义这种材料(……),也许我永远也不能明白地做到这一点。但我一看就知道了。”
波特·斯图尔特

1964 年,波特·斯图尔特是美国最高法院法官。他不是在讨论局外人,而是在讨论电影《情人》是否淫秽。

当您进行预测时,您会注意到您的数据集会有异常值。尽管当我看到它时我就知道它可能是唯一实用的定义,但这些离群值对供应链构成了真正的威胁。这些高点(或低点)将导致你的预测或安全库存的过度反应,最终导致(最好的情况下)人工修正或(最坏的情况下)死库存、损失和严重的牛鞭效应。实际上,当你查看博客、书籍、文章或预测软件时,异常值检测的问题经常被回避。这是一个遗憾。离群点检测是一件严肃的事情。

这些异常值在现代供应链中无时无刻不在出现。它们主要是由于两个主要原因:

错误&错误这些都是明显的离群值。如果您发现了此类错误或编码错误,就需要流程改进来防止这些错误再次发生。
异常需求尽管一些需求观察是真实的,但这并不意味着它们不是
异常并且不应该被清理或*滑。这种非凡的销售在供应链中其实并不罕见。想想促销、营销、奇怪的客户行为或减少库存。通常情况下,您可能不想在预测中考虑去年为处理几乎过时的旧库存而实现的 80%的特殊销售额。

如果你能发现异常值并消除它们,你就能做出更好的预测。我见过许多例子,仅仅由于异常值清理,预测误差就减少了百分之几。实际上,数据集越大,自动检测和清理就越重要。让我们看看我们如何能做到这一点。

在这篇文章中,我们将讨论三个半想法来找出这些异常值,并把它们放回到一个合理的水*。

想法 1——Winsorization

正如我们所说,异常值是异常高或异常低的值。基于这个简单的定义,检测异常值的第一个想法是简单地删除数据集的前 x 个最高点和最低点。让我们看看这将如何在下表中的两个(虚拟)数据集上工作。

**

第一种方法只是将历史需求的上/下 x%值降低到第 x 个百分点的极限。

第 x 百分位是一个值,低于该值,一个组中的 x%的观察值将下降。例如,一个产品 99%的需求观察值将低于它的第 99 个百分位数。

这种简单地将需求缩减到特定百分比的技术被称为 winsorization 。这个名字来自 20 世纪上半叶的统计学家查尔斯·p·温索尔。

如果我们查看上面两个虚拟数据集的第 1 和第 99 个百分位数,我们会得到以下结果:

在该表中,我们看到在两个数据集中,所有低值都将增加到 4.4。你可以在下图中看到,这剪切了我们数据集的一部分。对于没有异常值的数据集,高值将降至 16.6(见图 10.1),对于有异常值的数据集,高值将降至 70.9(见图 10.2)。

你可能已经注意到,winsorization 没有给我们 4 或 5 这样的整数结果,但是我们得到了 4.4。实际上,由于我们没有一个精确的值可以将数据集削减 99%,所以我们基于两个最接*的值进行线性*似。这就是我们如何得到这些数字而不是整数的。

**

那么,我们对这种技术满意吗?不,我们不是。
-我们在没有异常值的数据集上发现了假异常值。
-在有离群值的数据集上,我们没有充分减少离群值(它从 100 降到了 70.9)。

当然,可以简单地提议将 winsorization 的上限从 99%降低到 95%,以进一步减少数据集#2 上的离群值。然而,不幸的是,这也会影响数据集#1。这不是一个好的解决办法。也可以提议取消这个下限,这样我们就不会将需求增加到 4.4。但是,如果我们有需求缺失的时期呢?如果有的话,我们不应该也清理一下吗?

自己动手
Excel 使用公式=PERCENTILE 可以快速得到 Excel 中某一范围单元格的不同百分位数。INC(范围,极限)。当然,您必须对上限(值大约为 0.95-0.99)使用一次该公式,对下限(值大约为 0.01-0.05)使用一次。多亏了 NumPy,我们可以轻松地用 Python 编写数据集。借助函数 np.percentile(array,percentile) ,我们可以计算数组的不同百分位数。

*import numpy as np
higher_limit = np.percentile(array, 99)
lower_limit = np.percentile(array, 1)*

请注意, percentile 函数采用表示为 0 到 100 之间的值的百分点,而不是像 Excel 中那样的比率(即 0 到 1 之间的值)。

由于函数 np.clip(array,min,max) ,我们可以简单地将数组剪切到这些下限和上限:

*array = np.clip(array,a_min=lower_limit,a_max=higher_limit)*

想法 2 标准偏差

正如我们刚刚看到的,winsorization 并不是排除异常值的完美方法,因为它会取出数据集的高值和低值,即使它们并不异常。

另一种方法是查看历史*均值周围的需求变化,并排除异常地远离该*均值的值。
让我们将需求标准差定义为:

其中 n 是我们拥有的需求观察的数量。

如果我们假设我们的数据正态分布在历史*均值附*,我们可以计算需求在两个阈值之间的概率。这里涉及的精确数学超出了本文的范围,不幸的是,通常情况下,正态性假设并没有得到严格的尊重。这两个阈值将以需求*均值(μ)为中心,在两个方向上的分布为 x 乘以标准差(σ)。需求越混乱(即σ越重要),阈值就越宽。

**

例如,我们有 98%的概率处于范围:需求*均值+/- 2.33 倍标准差(如上图所示)。因此,如果我们想要移除高值和低值的前 1%,我们会将需求限制在μ +/-2.33 σ。

请注意,这意味着我们有 99%的概率比μ + 2.33 σ低。并且有 99%的概率比μ-2.33σ高 T25。

如果我们将此应用于我们的示例数据集(参见前两个表),我们将得到这些限制:

让我们看看这些新的普通限制与 winsorization 限制相比表现如何。**

这已经比我们用 winsorization 得到的结果好太多了:
——在没有离群值的数据集上(见图 10.4),我们不改变任何需求观察(完美!—正如我们所愿)。
-在有异常值的数据集上,我们不改变低需求点,只改变实际的异常值(见图 10.5)。

尽管如此,即使我们将离群值减少到比 winsorization (70.9)更易管理的数量(47.9),这可能还不够。

那么,我们现在幸福吗?
还不完全是。

你可能还记得,我们假设误差在历史*均值左右。这对于需求*淡的产品来说没什么问题,但是当你有一个有趋势或季节性的产品时,实际的限制就会出现。例如,在下面的季节表中,最高点(或最低点)不再是您想要移除的异常值。

在下图中,您可以看到 winsorization 和 normalization 如何影响季节性需求。

这根本没有意义:这两种技术都将季节峰值标记为异常值,并且它们跳过了真正的异常值,即 Y2 M11。

我们将用下一项技术来解决这个问题。

自己动手
Excel 借助公式 =STDEV,你可以计算一系列单元格的标准差。p(范围)。和往常一样,你可以通过 =AVERAGE(range) 来计算*均值。一旦你有了这两个,你就可以通过 =NORM 来计算上限和下限。INV(百分位数、*均值、标准偏差)。通常,您会希望上百分位在 0.99 左右,下百分位在 0.01 左右。
Python 你可以通过 np.std(array) 计算一个类似数组的(例如,一个列表,一个数据帧等)的标准差。)或直接通过
方法获取数据帧。std()
* 。因此,如果您有一个数据帧 df,您可以简单地键入:***

***m = df.mean()
s = df.std()***

然后我们将再次使用 SciPy 库来计算正态概率。然后我们将使用。在我们的数据帧上剪辑方法来限制它。**

***from scipy.stats import norm
#Print the probabilities of each demand observation
print(norm.cdf(df.values, m, s).round(2))limit_high = norm.ppf(0.99,m,s)
limit_low = norm.ppf(0.01,m,s)
df = df.clip(lower=limit_low, upper=limit_high)***

想法 3 误差标准偏差

我们必须标记异常值的第二个想法是将每个观察值与需求的*均值进行比较。我们看到,如果我们有一个趋势或季节性,这是没有意义的,因为观察值和历史*均值之间的差异是不相关的。

好了,让我们回到离群值的定义:离群值是你没有预料到的值,就像《巨蟒之灾》里的西班牙宗教裁判所显示的那样。也就是说离群值是一个远离你的预测(即你的预测)的值。因此,为了发现异常值,我们将分析预测误差,并查看哪些时段异常错误。为此,我们将使用之前使用的标准差方法。**

让我们拿回上面做的季节性例子。我们将历史需求与我们对它的简单(但季节性的)预测进行比较。

如果我们计算这种预测的误差(它只是历史需求的*均值),我们将获得 0.4 的*均误差和 3.2 的标准偏差(这当然受到 Y2 M11 误差的严重影响)。如果我们在这个*均值附*取 99%的置信区间,我们会将预测误差缩小到-0.4+/-2.33 x 3.2 =-8.7。您可以在下图中看到预测的这些限制是如何完美地符合季节性需求的。

我们现在可以纠正 Y2 M11 的异常值。该期间的需求为 19,但预测为 5。可接受的最大值为 5 + 7 = 12。这意味着我们可以用这个新值(12)替换 Y2 M11 (19)的异常值。**

结论如上图所示,标准化和 winsorization 无法为季节性需求带来任何有意义的结果。

这个方法的微调,你应该取多少个标准差作为极限?当然,这是留给你去试验的……**

自己动手
Python 如果您有一个 pandas DataFrame ,其中一列为预测,另一列为需求(我们的指数*滑模型的典型输出),我们可以使用以下代码:

***df[“Error”] = df[“Forecast”] — df[“Demand”]
m = df[“Error”].mean()
s = df[“Error”].std()
from scipy.stats import normlimit_high = norm.ppf(0.99,m,s)+df[“Forecast”]
limit_low = norm.ppf(0.01,m,s)+df[“Forecast”]
df[“Updated”] = df[“Demand”].clip(lower=limit_low,upper=limit_high)
print(df)***

多走一步!

如果你回想一下我们分析预测误差并设定可接受误差阈值的想法,我们实际上还有一个小问题。我们计算的阈值基于数据集,包括离群值。这种异常值驱使误差向上变化,使得可接受的阈值被偏置和高估。为了纠正这一点,可以不将异常值缩小到基于原始需求数据集计算的阈值,而是缩小到基于没有该特定异常值的数据集计算的限制。食谱如下:**

  1. 根据历史需求填充第一个预测。
  2. 计算误差、误差均值和误差标准差
  3. 计算可接受的下限和上限阈值(基于误差*均值和标准偏差)。
  4. 如前所述,识别异常值。
  5. 重新计算误差*均值和标准偏差,但排除异常值。
  6. 基于这些新值更新可接受的下限和上限阈值。
  7. 基于新的阈值更新异常值。

如果我们回到上面的季节性例子,我们最初的预测误差*均值为 0.4,标准偏差为 3.22。如果我们去掉点 Y2 M11,我们得到的误差*均值为-0.1,标准偏差为 2.3。这意味着现在预测的阈值是-5.3,5.2。然后,我们在 Y2 M11 中的异常值将被更新为 10(而不是我们之前技术中的 12)。

自己动手
我们将从之前的想法中收回代码,并添加一个新步骤来更新误差均值和标准偏差值。

***df[“Error”] = df[“Forecast”] — df[“Demand”]
m = df[“Error”].mean()
s = df[“Error”].std()from scipy.stats import norm
prob = norm.cdf(df[“Error”], m, s)
outliers = (prob > 0.99) | (prob < 0.01)m2 = df[“Error”][~outliers].mean()
s2 = df[“Error”][~outliers].std()limit_high = norm.ppf(0.99,m2,s2)+df[“Forecast”]
limit_low = norm.ppf(0.01,m2,s2)+df[“Forecast”]
df[“Updated”] = df[“Demand”].clip(lower=limit_low,upper=limit_high)
print(df)***

关于作者

*** [## Nicolas vande put——顾问,创始人——供应链| LinkedIn

查看 Nicolas Vandeput 在世界上最大的职业社区 LinkedIn 上的个人资料。尼古拉斯有 7 份工作列在…

www.linkedin.com](https://www.linkedin.com/in/vandeputnicolas/)

N icolas Vandeput 是一名供应链数据科学家,擅长需求预测和库存优化。他在 2016 年创立了他的咨询公司 SupChains ,并在 2018 年共同创立了 SKU 科学——一个快速、简单、实惠的需求预测*台。尼古拉斯对教育充满热情,他既是一个狂热的学习者,也喜欢在大学教学:自 2014 年以来,他一直在比利时布鲁塞尔为硕士学生教授预测和库存优化。自 2020 年以来,他还在法国巴黎的 CentraleSupelec 教授这两个科目。2018 年出版了 【供应链预测的数据科学】(2021 年第 2 版),2020 年出版了 库存优化:模型与模拟

***

用 Python 预测脸书预言家

原文:https://towardsdatascience.com/forecasting-in-python-with-facebook-prophet-29810eb57e66?source=collection_archive---------2-----------------------

如何使用领域知识调整和优化 Prophet,以便更好地控制您的预测。

我写了一本关于脸书先知的书,已经由 Packt 出版社出版了!这本书在亚马逊上有售。

这本书涵盖了使用 Prophet 的每个细节,从安装到模型评估和调整。十几个数据集已经可用,并用于演示 Prophet 功能,从简单到高级,代码完全可用。如果你喜欢这篇中帖,请考虑在这里订购:【https://amzn.to/373oIcf】T4!在超过 250 页的篇幅中,它涵盖的内容远远超过了媒体所能教授的内容!

非常感谢你支持我的书!

被困在付费墙后面?点击此处阅读完整故事,并附上好友链接!

我是 Greg Rafferty,湾区的数据科学家。这个项目的代码可以在我的 GitHub 上找到。

在这篇文章中,我将解释如何使用脸书的先知进行预测,并演示一些通过使用领域知识来处理趋势不一致的高级技术。网上有很多 Prophet 教程,但是没有一个深入到调整 Prophet 模型,或者整合分析师知识来帮助模型导航数据。我打算在这篇文章中做到这两点。

https://www.instagram.com/p/BaKEnIPFUq-/

在之前一个关于 Tableau 中预测的故事中,我使用了一个 ARIMA 算法的修改版来预测美国商业航班的乘客数量。ARIMA 方法在处理静态数据和预测短期框架时表现不错,但脸书的工程师已经为 ARIMA 无法处理的情况开发了一个工具。Prophet 的后端是 STAN,一种概率编码语言。这使得 Prophet 拥有贝叶斯统计提供的许多优势,包括季节性、包含领域知识和置信区间,以添加数据驱动的风险估计。

我将从三个数据来源来说明如何使用 Prophet,以及它的一些优点。如果你想跟着做,你首先需要安装 Prophet脸书的文档提供了简单的说明。我在本文中使用的笔记本提供了构建所讨论模型的完整代码。

飞机乘客

让我们从简单的开始。同样的航空乘客数据来自我的上一篇文章。Prophet 要求时间序列数据至少有两列:ds是时间戳,y是值。加载数据后,我们需要将其格式化为:

passengers = pd.read_csv('data/AirPassengers.csv')df = pd.DataFrame()
df['ds'] = pd.to_datetime(passengers['Month'])
df['y'] = passengers['#Passengers']

只需几行代码,Prophet 就可以制作一个和我之前制作的 ARIMA 模型一样复杂的预测模型。在这里,我打电话给 Prophet 做一个 6 年的预测(频率是每月,周期是 12 个月/年乘以 6 年):

prophet = Prophet()
prophet.fit(df)
future = prophet.make_future_dataframe(periods=12 * 6, freq='M')
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)

Number of passengers (in the thousands) on commercial airlines in the US

Prophet 将原始数据作为黑点,蓝线是预测模型。浅蓝色区域是置信区间。使用add_changepoints_to_plot功能添加红线;垂直的虚线是预测趋势变化的变化点,红色实线是去除所有季节性因素后的趋势。我将在本文中使用这种绘图格式。

这个简单的例子结束后,让我们继续讨论更复杂的数据。

Divvy 自行车共享

Divvy 是芝加哥的一家自行车共享服务公司。我以前做过一个项目,在那里我分析了他们的数据,并把它与从地下天气搜集的天气信息联系起来。我知道这个数据表现出很强的季节性,所以我认为这将是一个伟大的先知的能力展示。

Divvy 数据是基于每次乘坐的级别,因此为了对 Prophet 的数据进行格式化,我聚合到了每日级别,并为每天的“事件”列的模式(即天气条件:'not_clear', 'rain or snow', ‘clear', ‘cloudy', ‘tstorms', ‘unknown')、乘坐次数和*均温度创建了列。

格式化后,让我们看看每天的乘车次数:

因此,这些数据显然有季节性,而且趋势似乎是随着时间的推移而增加。有了这个数据集,我想演示如何添加额外的回归量,在这个例子中是天气和温度。让我们来看看温度:

它看起来很像之前的图表,但没有增加的趋势。这种相似性是有道理的,因为当天气晴朗温暖时,骑自行车的人会骑得更频繁,所以这两个图应该一前一后地上升和下降。

为了通过添加另一个回归量来创建预测,该额外的回归量必须具有预测期的数据。出于这个原因,我将 Divvy 数据缩短为一年,这样我就可以用天气信息来预测那一年。您可以看到,我还添加了美国的先知默认假期:

prophet = Prophet()
prophet.add_country_holidays(country_name='US')
prophet.fit(df[d['date'] < pd.to_datetime('2017-01-01')])
future = prophet.make_future_dataframe(periods=365, freq='d')
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

上述代码块创建了趋势图,如前面的航空乘客部分所述:

Divvy trend plot

和组件图:

Divvy component plot

组件图由 3 部分组成:趋势、假日和季节性。事实上,这三个部分的总和构成了模型的整体。如果你减去所有其他成分,趋势就是数据显示的。假日图显示了模型中包含的所有假日的影响。在 Prophet 中实现的假日可以被认为是不自然的事件,当趋势偏离基线,但一旦事件结束又会返回。正如我们将在下面探讨的,额外的回归变量就像假日一样,它们导致趋势偏离基线,只是趋势在事件发生后会保持变化。在这种情况下,假期都会导致乘客减少,如果我们意识到很多乘客都是通勤者,这也是有道理的。每周季节性因素显示,乘客量在一周内相当稳定,但在周末会急剧下降。这是支持大多数乘客都是通勤者这一理论的证据。我要注意的最后一点是,每年的季节性曲线是相当波动的。这些图是用傅立叶变换创建的,本质上是叠加的正弦波。显然,这种情况下的默认有太多的自由度。为了*滑曲线,我接下来将创建一个 Prophet 模型,关闭年度季节性,并添加一个额外的回归变量来解释它,但自由度更少。我还将继续在此模型中添加这些天气回归因素:

prophet = Prophet(growth='linear',
                  yearly_seasonality=False,
                  weekly_seasonality=True,
                  daily_seasonality=False,
                  holidays=None,
                  seasonality_mode='multiplicative',
                  seasonality_prior_scale=10,
                  holidays_prior_scale=10,
                  changepoint_prior_scale=.05,
                  mcmc_samples=0
                 ).add_seasonality(name='yearly',
                                    period=365.25,
                                    fourier_order=3,
                                    prior_scale=10,
                                    mode='additive')prophet.add_country_holidays(country_name='US')
prophet.add_regressor('temp')
prophet.add_regressor('cloudy')
prophet.add_regressor('not clear')
prophet.add_regressor('rain or snow')
prophet.fit(df[df['ds'] < pd.to_datetime('2017')])
future = prophet.make_future_dataframe(periods=365, freq='D')
future['temp'] = df['temp']
future['cloudy'] = df['cloudy']
future['not clear'] = df['not clear']
future['rain or snow'] = df['rain or snow']
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

趋势图看起来非常相似,所以我只分享组件图:

Divvy component plot with smooth annual seasonality and weather regressors

去年的趋势是向上的,而不是向下的!这是因为去年的数据显示*均气温较低,这使得乘客人数比预期的要少。我们还看到年度曲线变得*滑,还有一个额外的图:extra_regressors_multiplicative图。这显示了天气的影响。我们所看到的是意料之中的:乘客量在夏季增加,冬季减少,这种变化很大程度上是由天气造成的。我想再看一样东西,只是为了演示一下。我再次运行了上述模型,但这次只包括了rain or snow的回归变量。这是组件图:

Divvy component plot of just the effect of rain or snow

这表明,下雨或下雪时,每天的乘车次数会比其他时候少 1400 次。很酷,对吧!?

最后,我想按小时聚合这个数据集,以创建另一个分量图,即每日季节性。这个图看起来是这样的:

Divvy component plot for daily seasonality

正如 T2·里维斯指出的,凌晨 4 点是最不适合醒来的时间。显然,芝加哥的自行车骑手同意这一点。不过,当地在上午 8 点过后出现了一个高峰:早上的通勤者;下午 6 点左右是全球高峰:傍晚时分。我还看到午夜过后有一个小高峰:我喜欢认为这是人们从酒吧回家的路。Divvy 数据到此为止!让我们继续看 Instagram。

照片墙

脸书开发了 Prophet 来分析自己的数据。因此,在合适的数据集上测试 Prophet 似乎是公*的。我在 Instagram 上搜索了几个展现出我想探究的有趣趋势的账户,然后我从服务中搜集了三个账户的所有数据: @natgeo 、 @kosh_dp 和 @jamesrodriguez10 。

国家地理

https://www.instagram.com/p/B5G_U_IgVKv/

2017 年,我正在进行一个项目,在那里我注意到国家地理 Instagram 账户中的一个异常。对于 2016 年 8 月这一个月,每张照片的点赞数突然莫名其妙地急剧增加,但随后一个月过去就又回到了基线。我想把这个峰值建模为这个月的一次营销活动,以增加喜欢,然后看看我是否可以预测未来营销活动的效果。

以下是 Natgeo 每个帖子的点赞数。这种趋势明显在增加,而且随着时间的推移,差异也在增加。有许多异常值具有极高的喜欢度,但在 2016 年 8 月出现了一个高峰,在那个月发布的所有照片的喜欢度都远远高于周围的帖子:

我不想猜测为什么会这样,但是为了这个模型,让我们假设 Natgeo 的营销部门进行了一些为期一个月的活动,旨在增加喜欢。首先,让我们建立一个忽略这一事实的模型,这样我们就有了一个可以比较的基线:

Natgeo likes per photo over time

预言家似乎被那道钉弄糊涂了。它正试图将其添加到年度季节性成分中,从每年八月的峰值中的蓝色实线可以看出这一点。先知希望这是一个重复发生的事件。为了告诉 Prophet 2016 年发生了一些其他年份不会重复的特殊事情,让我们为这个月创造一个节日:

promo = pd.DataFrame({'holiday': "Promo event",
                      'ds' : pd.to_datetime(['2016-08-01']),
                      'lower_window': 0,
                      'upper_window': 31})
future_promo = pd.DataFrame({'holiday': "Promo event",
                      'ds' : pd.to_datetime(['2020-08-01']),
                      'lower_window': 0,
                      'upper_window': 31})promos_hypothetical = pd.concat([promo, future_promo])

promo数据帧仅包含 2016 年 8 月的活动,而promos_hypothetical数据帧包含 Natgeo 假设考虑在 2020 年 8 月推出的额外宣传片。当添加假日时,Prophet 允许有一个较低的窗口和一个较高的窗口,基本上是假日事件包含的天数,例如,如果您想将黑色星期五与感恩节一起包含,或者将*安夜与圣诞节一起包含。我在“假期”后添加了 31 天,将整个月都包含在事件中。下面是代码和新的趋势图。注意,我只是在调用先知对象时发送holidays=promo:

prophet = Prophet(holidays=promo)
prophet.add_country_holidays(country_name='US')
prophet.fit(df)
future = prophet.make_future_dataframe(periods=365, freq='D')
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

Natgeo likes per photo over time, with a marketing campaign in August 2016

太棒了。现在 Prophet 并没有增加每年 8 月份的愚蠢涨幅,而是在 2016 年出现了不错的涨幅。现在让我们再次运行这个模型,但是使用那个promos_hypothetical数据框架,来估计如果 Natgeo 在 2020 年运行一个相同的活动会发生什么:

Natgeo likes per photo over time with a hypothetical marketing campaign upcoming in 2020

这演示了在添加非自然事件时如何预测行为。例如,计划的商品销售可以是今年的模型。现在让我们转到下一个账户。

阿纳斯塔西娅·科什

https://www.instagram.com/p/BfZG2QCgL37/

Anastasia Kosh 是一名俄罗斯摄影师,她在自己的 Instagram 上发布古怪的自拍照,并为 YouTube 制作音乐视频。几年前我住在莫斯科时,我们是同一条街上的邻居;当时她在 Instagram 上有大约 1 万名粉丝,但在 2017 年,她的 YouTube 账户在俄罗斯迅速走红,她已经成为莫斯科青少年中的名人。她的 Instagram 账户呈指数级增长,很快接* 100 万粉丝。这种指数式增长对 Prophet 来说似乎是一个很好的挑战。

这是我们要建模的数据:

这是乐观增长的经典曲棍球棒形状,除了在这种情况下它是真实的!用线性增长对其建模,就像我们对上述其他数据建模一样,会导致不切实际的预测:

Anastasia Kosh likes per photo over time, with linear growth

这条曲线会一直延伸到无穷大。显然,一张照片在 Instagram 上获得的赞数是有上限的。理论上,这将等于服务上的唯一帐户的数量。但实际上,并不是每个客户都会看到或喜欢这张照片。这就是分析师的一点领域知识派上用场的地方。我决定用逻辑增长来建模,这需要先知被告知一个上限(先知称之为cap)和一个下限:

cap = 200000
floor = 0
df['cap'] = cap
df['floor'] = floor

通过我自己对 Instagram 的了解和一点点试错,我决定了 20 万个赞的上限和 0 个赞的下限。值得注意的是,Prophet 确实允许这些值被定义为时间的函数,所以它们不必是常数。在这种情况下,常量值正是我所需要的:

prophet = Prophet(growth='logistic',
                  changepoint_range=0.95,
                  yearly_seasonality=False,
                  weekly_seasonality=False,
                  daily_seasonality=False,
                  seasonality_prior_scale=10,
                  changepoint_prior_scale=.01)
prophet.add_country_holidays(country_name='RU')
prophet.fit(df)
future = prophet.make_future_dataframe(periods=1460, freq='D')
future['cap'] = cap
future['floor'] = floor
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

我将增长定义为逻辑增长,关闭所有季节性(在我的图中似乎没有太多季节性),并调整了一些调整参数。我还添加了俄罗斯的默认假日,因为大多数 Anastasia 的追随者都在那里。当在df上调用.fit方法时,Prophet 看到了capfloor列,并知道将它们包含在模型中。非常重要的是,当您创建预测数据框架时,您要将这些列添加到其中(这就是上面代码块中的future数据框架)。我们将在下一节再次讨论这个问题。但是现在我们的趋势图看起来真实多了!

Anastasia Kosh likes per photo over time, with logistic growth

最后,让我们看看我们的最后一个例子。

哈梅斯·罗德里格斯

https://www.instagram.com/p/BySl8I7HOWa/

哈梅斯·罗德里格斯是一名哥伦比亚足球运动员,在 2014 年和 2018 年世界杯上都有出色表现。他的 Instagram 账号从一开始就有稳定的增长;但是在研究之前的分析时,我注意到在两届世界杯期间,他的账户出现了突然而持久的粉丝激增。与国家地理杂志(National Geographic)账户中可以被建模为假期的峰值相反,罗德里格斯的增长在两场比赛后没有回到基线,而是重新定义了一个新的基线。这是完全不同的行为,需要不同的建模方法来捕捉它。

这是整个帐户生命周期中哈梅斯·罗德里格斯的每张照片的喜欢数:

仅用我们在本教程中使用的技术很难清晰地建模。他在 2014 年夏天的第一届世界杯期间经历了趋势基线的上升,然后在 2018 年夏天的第二届世界杯期间经历了峰值,并可能改变了基线。用默认模型来模拟这种行为并不十分有效:

James Rodríguez likes per photo over time

不是可怕的车型;它只是没有很好地模拟这两场世界杯比赛的行为。如果我们像上面对 Anastasia Kosh 的数据所做的那样,将这些比赛建模为假期,我们确实会看到模型的改进:

wc_2014 = pd.DataFrame({'holiday': "World Cup 2014",
                      'ds' : pd.to_datetime(['2014-06-12']),
                      'lower_window': 0,
                      'upper_window': 40})
wc_2018 = pd.DataFrame({'holiday': "World Cup 2018",
                      'ds' : pd.to_datetime(['2018-06-14']),
                      'lower_window': 0,
                      'upper_window': 40})world_cup = pd.concat([wc_2014, wc_2018])prophet = Prophet(yearly_seasonality=False,
                  weekly_seasonality=False,
                  daily_seasonality=False,
                  holidays=world_cup,
                  changepoint_prior_scale=.1)
prophet.fit(df)
future = prophet.make_future_dataframe(periods=365, freq='D')
forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

James Rodríguez likes per photo over time, with holidays added for the World Cups

我仍然不喜欢模型适应变化趋势线的速度太慢,尤其是在 2014 年世界杯前后。这只是一个过于*稳的过渡。不过,通过添加额外的回归变量,我们可以迫使 Prophet 考虑一个突然的变化。

在这种情况下,我为每场锦标赛定义了两个时间段,赛中和赛后。以这种方式建模假设在锦标赛之前,将会有一个特定的趋势线,在锦标赛期间,该趋势线将会有一个线性变化,在锦标赛之后,将会有另一个变化。我将这些周期定义为 0 或 1,开或关,并让 Prophet 根据数据训练自己来学习幅度:

df['during_world_cup_2014'] = 0
df.loc[(df['ds'] >= pd.to_datetime('2014-05-02')) & (df['ds'] <= pd.to_datetime('2014-08-25')), 'during_world_cup_2014'] = 1
df['after_world_cup_2014'] = 0
df.loc[(df['ds'] >= pd.to_datetime('2014-08-25')), 'after_world_cup_2014'] = 1df['during_world_cup_2018'] = 0
df.loc[(df['ds'] >= pd.to_datetime('2018-06-04')) & (df['ds'] <= pd.to_datetime('2018-07-03')), 'during_world_cup_2018'] = 1
df['after_world_cup_2018'] = 0
df.loc[(df['ds'] >= pd.to_datetime('2018-07-03')), 'after_world_cup_2018'] = 1

请注意,我正在更新future数据帧,以包含以下这些“假日”事件:

prophet = Prophet(yearly_seasonality=False,
                  weekly_seasonality=False,
                  daily_seasonality=False,
                  holidays=world_cup,
                  changepoint_prior_scale=.1)prophet.add_regressor('during_world_cup_2014', mode='additive')
prophet.add_regressor('after_world_cup_2014', mode='additive')
prophet.add_regressor('during_world_cup_2018', mode='additive')
prophet.add_regressor('after_world_cup_2018', mode='additive')prophet.fit(df)
future = prophet.make_future_dataframe(periods=365)future['during_world_cup_2014'] = 0
future.loc[(future['ds'] >= pd.to_datetime('2014-05-02')) & (future['ds'] <= pd.to_datetime('2014-08-25')), 'during_world_cup_2014'] = 1
future['after_world_cup_2014'] = 0
future.loc[(future['ds'] >= pd.to_datetime('2014-08-25')), 'after_world_cup_2014'] = 1future['during_world_cup_2018'] = 0
future.loc[(future['ds'] >= pd.to_datetime('2018-06-04')) & (future['ds'] <= pd.to_datetime('2018-07-03')), 'during_world_cup_2018'] = 1
future['after_world_cup_2018'] = 0
future.loc[(future['ds'] >= pd.to_datetime('2018-07-03')), 'after_world_cup_2018'] = 1forecast = prophet.predict(future)
fig = prophet.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), prophet, forecast)
plt.show()
fig2 = prophet.plot_components(forecast)
plt.show()

James Rodríguez likes per photo over time, with additional regressors

在这里,蓝线是我们应该关注的。红线显示的只是趋势,减去了额外的回归因素和假期的影响。看看蓝色趋势线在世界杯期间是如何急剧跳跃的。这正是我们的领域知识告诉我们会发生的行为!在罗德里格斯打入他在世界杯上的第一个进球后,突然有成千上万的新粉丝来到了他的账户上。让我们看一下分量图,看看这些额外的回归量有什么具体的影响:

James Rodríguez component plot for the World Cup regressors

这告诉我们,在 2013 年和 2014 年初,世界杯对罗德里格斯每张照片的点赞没有影响。在 2014 年世界杯期间,他的*均每张照片点赞数大幅上升,并在比赛结束后继续上升(这可以解释为他在赛事期间获得了如此多的活跃粉丝)。2018 年世界杯期间也发生了类似的事件,但没有那么引人注目,大概是因为此时已经没有多少足球迷发现他的账户并关注他了。

感谢你一直关注这篇文章!我希望你现在明白如何使用假期,线性与逻辑增长率,以及额外的回归变量来丰富你的预言家预测。脸书用 Prophet 构建了一个非常有价值的工具,将曾经非常困难的概率预测变成了一组简单的参数,并且有很大的调整余地。祝你预测好运!

预测未来许多天的价格

原文:https://towardsdatascience.com/forecasting-prices-for-5-days-ahead-2460406c4ea2?source=collection_archive---------10-----------------------

在这篇文章中,我将提出一些想法来预测未来 5 天冰糖的价格。

Forecasted values (orange) against real values (green)

在公司内部,有几个风险因素需要考虑和管理。例如,价格变化时,经理必须决定卖出的最佳时机;产品需求预测改善库存管理。评估的另一个重要因素是对经常性费用的预测,因为表达性价值会影响公司的营运资本。

通常是对价格、需求、费用等的预测。考虑到经理的领域知识以及影响决策的特定主题的基本信息。

使用预测模型时,数据在训练集和测试集之间分离,系数在训练数据中生成,并且通常在测试集中逐步测试。因此,只预测一个时间段,然后用真实值更新,依此类推,直到测试集结束。

在这篇文章中,将会创建一个 ARIMA 模型,在这个模型中,从训练集中获得的系数将以稍微不同的方式进行测试。将对连续 5 天进行预测,并用实际数据更新该系列(连续 5 天),同样,将为 5 个周期创建新的预测,直到测试数据结束。

这种方法对于那些希望创建具有多个提前期的预测模型的人来说很有意思,因为它可以很容易地用于将预测的外推与真实数据进行比较,从而验证模型的主要特征是什么以及哪些方面可以改进。

该模型的主要目的是预测 Esalq 通知的 50 公斤冰糖未来 5 天的每日价格,数据可在此处下载****(请从巴西网站下载数据,英文版没有巴西雷亚尔(BRL)、的价格,所有代码的 Jupyter 笔记本可在我的 GitHub 中找到)。

从现在开始,我们将使用从我的帖子中摘录的以下步骤: 创建时间序列预测的基本原则 (如果您还不熟悉创建这些预测的基础,我强烈建议您阅读一下):

  • 将系列分为训练集和测试集,
  • 将系列转换成静态的,
  • 搜索相关的滞后,
  • 创建模型,
  • 在训练集上绘制比较图,
  • 评估模型和测试集中的错误,
  • 对模型提出可能的改进建议。

创建培训和测试集

我们有大约 16 年的价格历史,我将保留最后 250 个工作日(大约 1 年)来测试模型。在预测值和当前值之间将有 50 个 5 天的比较。请注意,所有以前的数据都将用于训练模型:

*稳性检验和验证相关滞后

为了创建时间序列预测,序列必须是*稳的。所以,它必须具备以下相对恒定的条件:均值、方差和自相关。

下面我将使用函数来绘制序列,它的分布,自相关,偏自相关。此外, Dickey Fuller 统计测试将用于检查*稳性:

#creating a function to plot the graph and show the test result:
def check_stationarity(y, lags_plots=48, figsize=(22,8)):
 “Use Series as parameter”

 y = pd.Series(y)
 fig = plt.figure()ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=2)
 ax2 = plt.subplot2grid((3, 3), (1, 0))
 ax3 = plt.subplot2grid((3, 3), (1, 1))
 ax4 = plt.subplot2grid((3, 3), (2, 0), colspan=2)y.plot(ax=ax1, figsize=figsize, color=’teal’)
 ax1.set_title(‘Crystal Sugar Price’)
 plot_acf(y, lags=lags_plots, zero=False, ax=ax2, color=’teal’);
 plot_pacf(y, lags=lags_plots, zero=False, ax=ax3, method=’ols’, color=’teal’);
 sns.distplot(y, bins=int(sqrt(len(y))), ax=ax4, color=’teal’)
 ax4.set_title(‘Price Distribution’)plt.tight_layout()

 print(‘Dickey-Fuller test results:’)
 adfinput = adfuller(y)
 adftest = pd.Series(adfinput[0:4], index=[‘Statistical Test’,’P-Value’,’Used Lags’,’Observations Number’])
 adftest = round(adftest,4)

 for key, value in adfinput[4].items():
 adftest[“Critical Values (%s)”%key] = value.round(4)

 print(adftest)

为了验证训练数据上的值是否是*稳的,我们将使用 5%的 P 值作为基础,如果该测试的 P 值小于 5%,我们可以认为序列是*稳的:

当我们分析图形时,注意到价格有轻微的上升趋势,分布图显示数据不符合高斯正态分布,并且自相关的特征显示所有滞后都有显著的相关性(这是具有某种趋势的系列的标志),最终统计值显示 P 值为 8.7%。

因此,这一系列不符合被认为是稳定的标准。

我将做第一个改变,以消除趋势,只关注每天的变化:

Dickey Fuller 测试在 P 值上返回零,这意味着该序列变得稳定。除此之外,在价格图中,趋势已经消失,价格相对稳定。****

在自相关图中,值逐渐减小,与没有第一差异的图不同。

部分自相关下降得更突然,表明前三个值对当前值有更大的影响。显然,在预测中没有显著的季节相关性需要考虑。

沿着这些思路,我们可以考虑差分序列中具有前 3 个滞后的自回归模型,因此我们将对该模型使用以下术语: ARIMA (3,1,0)

创建模型

最初,将基于训练数据创建模型,因此将生成 3 个自相关滞后的系数,并将用于测试测试集中连续 5 天的外推。

有几种方法可以推断未来,主要的有:

  • 为要预测的每个特定日期创建一个模型,然后在最终模型中添加所有内容,
  • 递归,预测第一天并以此值为基础预测第二天。

我们将使用本例中的最后一个模型,在这种情况下,我们将预测未来 5 天,与真实数据进行比较,将后者添加到模型中,以便进行新的外推,然后我们将计算模型的误差,并分析预测的相关事实。

训练模型

# Training the model
model = ARIMA(train, order=(3,1,0)).fit()
train_pred = model.predict()

现在模型已经定型,让我们比较下图中的实际数据和预测数据:

在训练集中,模型设法捕捉市场的主要时刻。唯一一次预测不能捕捉到变化的时候是当有更大的变化时。分析误差,RMSE 为 BRL 4.967/袋。

获取系数

训练模型后,我们可以获得差值的乘法系数以及模型的常数,这些值将作为外推未来 5 天预测的基础。

# Taking the constant and the coefficients of the lags to use in the test base:
const, l1, l2, l3 = model.paramsprint(f'Constant value {round(const, 4)}')
print(f'Cofficients of Lag 1: {round(l1,4)}, Lag 2: {round(l2,4)} and Lag 3: {round(l3,4)}')**Constant value 0.0063
Cofficients of Lag 1: 0.2332, Lag 2: 0.2297 and Lag 3: 0.2309**

下一步是使用这些乘法系数来测试测试集中的外推。为了更好地可视化,我们使用了一个函数将每个五天的预测与真实数据进行了比较。虽然我们可以在下面的图表中看到,这种预测的主要特点是它遵循正在协商的最新趋势。仍然有改进的余地,因为模型本身不能预测趋势的可能变化。

在我们的测试集上分析 RMSE:

¬test_error = sqrt(mean_squared_error(test['Crystal'], test['Crystal Pred']))
print(f'The RMSE on the test set was BRL {round(test_error,4)}/bag')**The RMSE on the test set was BRL 1.1522/bag**

下一部分将详细分析错误:

分析错误

将分别分析每一步的*均误差。通常,由于不确定性,误差(在本例中为 RMSE)会随着外推周期而增加:

The RMSE for each step is:
[0.48524694 0.69167404 0.81373202 1.00020173 1.12683735]

正如预测的那样,在每一步,RMSE 都会增加,这是由于未来的不确定性,而且从第二步开始的预测是基于预测值而不是真实值。

以下是一些有助于提高模型准确性的想法:

  • 创建各种模型的合奏(LSTM,Garch,MLP,TBATS,CNN 等)。)并制定一个*均价格,
  • 有些模型可能对某些特定步骤有更好的预测,您可以使用每个步骤中误差最小的模型,这样可以得到每个步骤都有不同模型且误差较小的最终模型。
  • 分析不同的误差指标,如*均误差、偏差等。为了验证每种度量的具体特征,
  • 测试可能的季节性滞后以预测周期性运动,
  • 每周对数据重新取样,
  • 添加相关的外部数据,
  • 将数据标准化,
  • 对数变换或使用 Box-Cox 变换。

用简单的模型,甚至人工智能技术来预测未来几个时期,无疑是一种极其重要的工具。

面对竞争日益激烈的市场,创建一个具有良好准确性的模型对公司来说可能是一项优势,因为它可以捕捉可能的市场运动,这对管理员的决策可能是必不可少的。

像这样的模型可以用作创造现金流、管理生产和库存以及识别市场机会的重要工具。

我希望你喜欢这篇文章!如果您有任何问题或需要更多信息,请随时联系我。下面是在 LinkedIn 上与我联系的链接。

来源:

** [## 基于机器学习的用电量多步时间序列预测

鉴于智能电表的兴起和太阳能等发电技术的广泛采用…

machinelearningmastery.com](https://machinelearningmastery.com/multi-step-time-series-forecasting-with-machine-learning-models-for-household-electricity-consumption/) [## 多步时间序列预测的 4 种策略

时间序列预测通常在只需要一步预测的情况下进行讨论。当你需要的时候…

machinelearningmastery.com](https://machinelearningmastery.com/multi-step-time-series-forecasting/)**

利用社交媒体预测股价波动

原文:https://towardsdatascience.com/forecasting-stock-price-swings-with-social-media-a32d742507be?source=collection_archive---------22-----------------------

Instagram 评论比你想象的更重要

如今,消费者比以往任何时候都更能够通过社交媒体联系和表达他们对自己喜爱品牌的看法。因此,一个品牌的声誉可以根据他们的在线战略来建立或破坏。杜嘉班纳的没落和在 instagram 上设计好看的衣服(比如大 logos)就是这种新趋势的例子。这篇短文的目的是看看我们能否用社交媒体数据预测价格波动。

数据

我们将考虑来自 Instagram、Google trends、Twitter 和从 Sentieo 下载的网站流量的百事可乐的社交媒体指标数据。

总的来说,我们有 36 个输入指标来跟踪百事和 Sodastream 在这些社交网络上的赞数、评论数和访问量。我们将关注每周的变化,以了解它们如何影响百事公司的股价。

处理数据

将数据上传到 AuDaS 数据科学*台后,我们将每周价格变动分为 3 类:

  • -1 :价格变动< -2%
  • 0 :价格在-2%和 2%之间波动
  • 1 :价格变动> 2%

这允许我们将问题框架为分类任务,这对于主要对股票的大幅价格波动感兴趣的长期投资者更有帮助。该分析可以很容易地应用于更长的时间范围(月、年)和更多的篮子,取决于数据的可用性。

构建模型

我们的目标变量是价格变动的分栏,我们的输入是 36 个社交媒体指标。然后,AuDaS 自动开始搜索最佳的机器学习模型,并向用户提供模型的特征相关性和得分度量。

经过几次迭代后,我们的 3 类预测问题的 F1 值达到了 0.417,比随机值(0.33)要好。

这表明社交媒体数据确实具有一定的预测能力,特别是百事公司 Twitter 提及率的每周变化,以及随后的 instagram 评论和网站触及率。

解释和扩展

这项研究中的数据衡量了百事公司的社交媒体和在线流量,但没有提供消费者与该品牌互动的情绪。包含情感可以帮助模型预测消费者是在赞美品牌还是在发泄他们的不满。

另一项分析可以关注百事公司与其追随者之间的具体交流,即他们如何回答客户的问题和要求,回答的速度有多快?

另一个扩展可以是观察百事可乐的流量与可口可乐和/或联合利华的流量相比如何,以及相对表现如何影响它们的价格波动。

这种机器学习模型可能不包含足够的 alpha 来制定系统策略,因为社交媒体情绪已经被广泛使用,信号衰减非常快,但它可以支持基本面投资者的分析。量化社交媒体对他们高信念投资的影响可以让他们了解一些分析师不容易衡量的额外驱动因素。这也可以帮助他们理解他们的投资在潜在的网络反弹面前是多么的脆弱。最后,instagram 帖子和 twitter 转发通常是购买量的代理,可以用于预测销售的基本模型中。

如果你有兴趣了解我们的 Quant 和基本面对冲基金客户如何使用澳元进行风险分析和投资管理,请不要犹豫,通过电子邮件或 LinkedIn 联系我。您还可以阅读以下更多案例研究:

[## 集群风险管理

如何揭开表面下的结构

towardsdatascience.com](/risk-management-with-clustering-fd594e064806) [## 用机器学习预测收入惊喜

如何预测哪些公司将超过或低于分析师的收益预期

towardsdatascience.com](/forecasting-earning-surprises-with-machine-learning-68b2f2318936) [## 机器学习的价值投资

你最喜欢的持有期不一定是永远…

towardsdatascience.com](/value-investing-with-machine-learning-e41867156108)

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

更新:我开了一家科技公司。你可以在这里找到更多

团队和资源

Mind Foundry 是牛津大学的分支机构,由斯蒂芬·罗伯茨(Stephen Roberts)和迈克尔·奥斯本(Michael Osborne)教授创立,他们在数据分析领域已经工作了 35 年。Mind Foundry 团队由 30 多名世界级的机器学习研究人员和精英软件工程师组成,其中许多人曾是牛津大学的博士后。此外,Mind Foundry 通过其分拆地位,拥有超过 30 名牛津大学机器学习博士的特权。Mind Foundry 是牛津大学的投资组合公司,其投资者包括牛津科学创新、牛津技术与创新基金、、牛津大学创新基金和 Parkwalk Advisors 。

用指数*滑法预测股票价格

原文:https://towardsdatascience.com/forecasting-stock-prices-using-exponential-smoothing-b37dfe54e8e9?source=collection_archive---------8-----------------------

Photo by Marc Schulte on Unsplash

指数*滑法是一种预测方法,它计算过去观察值的加权*均值作为预测值。随着观测数据的老化,权重呈指数衰减。因此,观测值越新,其在预测中的权重就越高。指数*滑法系列对时间序列的三个方面进行建模:趋势水*、趋势斜率和季节性成分。这三个方面产生了三种类型的指数*滑:单指数*滑、双指数*滑和三指数*滑(也称为霍尔特-温特斯法)。

在本文中,我们将尝试使用指数*滑法来预测股票价格。我们将首先使用单指数*滑,然后是双指数*滑,最后是三指数*滑(也称为霍尔特-温特斯法)。我们对指数*滑的实现遵循这里的方程式和这里的方程式(322 页)。

问题陈述

我们的目标是使用前 N 天的数据来预测 Vanguard Total Stock Market ETF(VTI)的每日调整收盘价。在这个实验中,我们将使用 VTI 从 2013 年 1 月 2 日到 2018 年 12 月 28 日的 6 年历史价格,可以从雅虎财经轻松下载。下载后,数据集如下所示:

Downloaded dataset for VTI.

总之,我们有 1509 天的数据可以处理。请注意,周六和周日不包括在上面的数据集中。整个数据集中调整后的收盘价如下图所示:

Adjusted closing prices from 2013–01–02 to 2018–12–28.

要有效地评估指数*滑的性能,仅在一个日期运行一次预测是不够的。相反,我们将在该数据集中的不同日期执行各种预测,并对结果进行*均。对于所有预测,我们将比较指数*滑法和终值法。

为了评估我们方法的有效性,我们将使用均方根误差(RMSE)、*均绝对百分比误差(MAPE)和*均绝对误差(MAE)指标。对于所有指标,值越低,预测越好。与我们的上一篇文章类似,我们将使用最后一个值方法对我们的结果进行基准测试。

培训和验证

为了进行预测,我们需要训练和验证数据。我们将使用 3 年的数据作为训练集,这对应于 756 天,因为一年中大约有 252 个交易日(252*3 = 756)。我们将使用未来 1 年的数据进行验证,这相当于 252 天。换句话说,对于我们做出的每个预测,我们需要 756+252 = 1,008 天的数据来进行模型训练和验证。将使用训练集来训练模型,并且将使用验证集来调整模型超参数(在这种情况下为⍺、β、𝛾,见下文)。

为了调整超参数,我们将使用移动窗口验证方法。移动窗口验证方法在我们的上一篇文章中有详细描述。下面举例说明了 756 天的训练规模、40 天的验证规模和 40 天的预测范围的情况。

Moving window validation example.

在下文中,我们将使用指数*滑法对数据集中的若干天进行预测,每个预测期为 21 天(注意,一个月中大约有 21 个交易日,不包括周末)。我们将使用预测之前的 1008 天作为训练和验证集,如上所述,采用 756:252 的比例。

单指数*滑

指数*滑的基本方程如下所示。

这里:

  • S 表示*滑后的值
  • y 表示时间序列
  • t 表示时间序列 y 的时间段,取值从 1 到 n
  • α表示*滑常数,α值越小,曲线越*滑

要初始化,请设置

注意这里没有 S₁ 。要执行预测,请计算

指数*滑方程非常简单,我们可以自己实现。单一指数*滑的代码如下所示。

使用移动窗口验证方法对数据集应用单指数*滑的结果如下所示。我们将⍺从 0.01 变化到 0.99,步长为 0.01,并选择⍺的最佳值,该值在我们的验证集上给出最低的 RMSE。正如人们可能观察到的那样,单一指数*滑法只能投射出一条水*直线,不能很好地捕捉趋势。

Forecasts on multiple days using single exponential smoothing.

另一种可视化预测的方法是绘制每个预测的实际值。如下图所示。如果我们有完美的准确性,每个预测应该位于对角线 y=x 线上。

Comparing the forecasts using single exponential smoothing with their actual values.

下面显示了每个预测的 RMSE、MAPE 和 MAE,以及使用各自的验证集调整的相应最佳α。

RMSE, MAPE, and MAE of each forecast made with single exponential smoothing.

上述预测给出的*均 RMSE 为 2.52,*均 MAPE 为 1.69%,*均*均月*均误差为 2.25。

你可以查看 jupyter 笔记本上的单指数*滑这里。

双指数*滑

考虑到单指数*滑不能很好地捕捉趋势,双指数*滑引入了第二个方程来模拟趋势。

这里:

  • S 表示*滑后的值
  • y 表示时间序列
  • t 表示时间序列 y 的时间段,取值从 1 到 n
  • α表示*滑值的*滑常数
  • b 表示趋势斜率的估计值
  • β表示趋势斜率的*滑常数

第一个等式通过将前一个时间段的趋势添加到最后一个*滑值来调整趋势。第二个*滑方程更新趋势。这个等式类似于单指数*滑的基本形式,但是这里应用于趋势的更新。

要初始化,请设置

要执行预测,请计算

这里:

  • S 表示*滑后的值
  • t 表示时间序列 y 的时间段,取值从 1 到 n
  • 表示趋势斜率的估计值
  • 代表预测
  • H 表示预测范围

双指数*滑的代码如下所示。

使用移动窗口验证方法对数据集应用双指数*滑的结果如下所示。我们以 0.01 的步长从 0.01 到 0.99 改变⍺和β,并选择在我们的验证集上给出最低 RMSE 的⍺,β的最佳值。

Forecasts on multiple days using double exponential smoothing.

预测值与实际值的对比图如下所示。

Comparing the forecasts using double exponential smoothing with their actual values.

下面显示了每个预测的 RMSE、MAPE 和 MAE,以及使用各自的验证集调整的相应最佳α和β。

RMSE, MAPE, and MAE of each forecast made with double exponential smoothing.

上述预测给出的*均 RMSE 为 2.31,*均 MAPE 为 1.54%,*均*均月*均误差为 2.06。到目前为止,正如我们所料,双指数*滑比单指数*滑效果更好。

然而,仔细观察β的最佳值会发现,我们最初的β下限设置得太低了。接下来,我们尝试了一种“微调”方法来调整超参数——我们首先像以前一样以 0.01 的步长将⍺和β从 0.01 变到 0.99。找到⍺和β的初始最佳值后,我们接着在初始最佳值+/- 0.01 的范围内改变它们的值,步长为 0.001。下图显示了经过微调的最佳α和β。

RMSE, MAPE, and MAE of each forecast made with double exponential smoothing, with hyperparameter finetuning.

通过微调,上述预测给出了稍好的*均 RMSE 为 2.29,*均 MAPE 为 1.53%,*均*均误差为 2.04。

你可以在 jupyter 笔记本上查看双指数*滑这里(没有微调)和这里(有微调)。

三重指数*滑

三重指数*滑法,也称为霍尔特-温特斯法,引入了第三个方程来考虑季节性。

这里:

  • S 表示*滑后的值
  • y 表示时间序列
  • t 表示时间序列 y 的时间段,取值从 1 到 n
  • α表示*滑值的*滑常数
  • b 表示趋势斜率的估计值
  • β表示趋势斜率的*滑常数
  • L 表示周期
  • I 表示季节性成分的估计值
  • 𝛾表示季节性成分的*滑常数

我们选择将周期设定为每年,是因为出现了圣诞老人集会、一月效应和五月卖出效应等现象。由于一年大约有 252 个交易日,我们设 L = 252。

要初始化*滑值,请设置

要初始化趋势斜率,请设置

要初始化季节性组件,请设置

这里:

  • P 表示我们列车组的周期数(因为我们的列车长度为 3 年, P =3)

上面的等式首先计算每个周期中所有值的*均值,用 Aᵢ 表示。接下来,我们计算每个 y 分量与其对应的 Aᵢ 的差值,并取*均值。参见此处的示例。

三重指数*滑的代码如下所示。

使用移动窗口验证方法对数据集应用三重指数*滑的结果如下所示。我们以 0.01 的步长从 0.01 到 0.99 改变⍺和β,以 0.1 的步长从 0.1 到 0.9 改变𝛾。然后,我们选择⍺、β和𝛾的最佳值,这些值在我们的验证集上给出了最低的 RMSE。

Forecasts on multiple days using triple exponential smoothing.

预测值与实际值的对比图如下所示。

Comparing the forecasts using triple exponential smoothing with their actual values.

上述预测给出的*均 RMSE 为 3.91,*均 MAPE 为 2.65%,*均*均月*均降水量为 3.50。

下面显示了每个预测的 RMSE、MAPE 和 MAE,以及使用各自的验证集调整的相应最佳α、β和𝛾's。

RMSE, MAPE, and MAE of each forecast made with triple exponential smoothing.

上述预测给出的*均 RMSE 为 3.91,*均 MAPE 为 2.65%,*均*均月*均降水量为 3.50。

你可以在 jupyter 笔记本上查看三重指数*滑这里。

调查的结果

让我们将我们的发现汇总在下表中。

Comparing the different methods.

可以观察到,三重指数*滑的性能最差,这可能是因为年度季节性假设在我们的数据集中不成立。另一方面,双指数*滑法的性能最好,优于最后一个值法。

在我们的下一篇文章中,我们将探索应用于股票价格预测的其他预测技术。敬请期待!

使用 Prophet 预测股票价格

原文:https://towardsdatascience.com/forecasting-stock-prices-using-prophet-652b31fb564e?source=collection_archive---------10-----------------------

预测是一门硬科学,需要大量的专业知识。出于这些原因,脸书开源了 Prophet T1,它允许任何拥有 Python 编程技能的人轻松实现对时间序列的预测。你可以在脸书的博客或报纸上读到更多关于先知的内容。

在本文中,我们将尝试使用 Prophet 来预测股票价格。Prophet 使用一个可分解的时间序列模型,它有三个主要的模型组件:增长、季节性和假期。它们通过以下等式组合在一起

*y(t) = g(t) + s(t) + h(t) + e(t),*

其中 g(t) 表示模拟非周期性变化的增长函数, s(t) 表示由于每周或每年的季节性引起的周期性变化, h(t) 表示节假日的影响, e(t) 表示误差项。这种可分解的时间序列在预测中非常常见,在本文的后面,我们将看到如何调整上述方程的每个组成部分。

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

问题陈述

我们的目标是使用前 N 天的数据来预测 Vanguard Total Stock Market ETF(VTI)的每日调整收盘价。在这个实验中,我们将使用 VTI 从 2013 年 1 月 2 日到 2018 年 12 月 28 日的 6 年历史价格,可以从雅虎财经轻松下载。下载后,数据集如下所示:

Downloaded dataset for VTI.

总之,我们有 1509 天的数据可以处理。请注意,周六和周日不包括在上面的数据集中。整个数据集中调整后的收盘价如下图所示:

Adjusted closing prices from 2013–01–02 to 2018–12–28.

要有效地评估 Prophet 的性能,仅在一个日期运行一次预测是不够的。相反,我们将在该数据集中的不同日期执行各种预测,并对结果进行*均。对于所有的预测,我们将比较先知法和终值法。

为了评估我们方法的有效性,我们将使用均方根误差(RMSE)、*均绝对百分比误差(MAPE)和*均绝对误差(MAE)指标。对于所有指标,值越低,预测越好。

培训和验证

为了进行预测,我们需要训练和验证数据。我们将使用 3 年的数据作为训练集,这对应于 756 天,因为一年中大约有 252 个交易日(252*3 = 756)。我们将使用未来 1 年的数据进行验证,这相当于 252 天。换句话说,对于我们做出的每个预测,我们需要 756+252 = 1,008 天的数据来进行模型训练和验证。将使用训练集来训练模型,并且将使用验证集来调整模型超参数。

为了调整超参数,我们将使用移动窗口验证方法。最好用一个例子来解释。假设我们总共有 896 天的数据,我们希望在第 857 天执行预测,预测范围= 40 天。作为一种启发,对于预测范围 H ,我们通常每 H /2 个周期进行一次预测。对于 756 天的训练集,我们将能够进行 4 次验证(见下图)。来自这 4 个验证的误差度量将被*均,并且模型超参数将基于给出最低*均误差度量的组合来选择。有了这些最佳超参数,我们将在第 857 天进行预测并报告结果。

Moving window validation example.

在下文中,我们将首先对数据集的第 1009 天进行预测,预测跨度为 21 天(注意,一个月中大约有 21 个交易日,不包括周末)。对于 Prophet,我们将使用前 1008 天作为训练和验证集,如上所述,以 756:252 进行划分。我们将在下一节中首先解释最后一个值方法。

最后一个值

在最后一个值方法中,我们简单地将预测值设置为最后一个观察值。在我们的上下文中,这意味着我们将当前调整后的收盘价设置为前一天的调整后的收盘价。这是最具成本效益的预测模型,通常用作比较更复杂模型的基准。这里没有要优化的超参数。我们对数据集第 1009 天的预测显示如下,预测时间跨度为 21 天。

Predictions on test set using Last Value method.

上述预测给出的 RMSE 为 1.89,MAPE 为 1.59%,*均相对误差为 1.80。

无超参数调谐的 Prophet

要使用 Prophet 运行预测,请使用下面的代码。

请注意,您需要从未来的数据框架中删除周末。不这样做将会给你不好的预测结果。更多信息请见这里或者这里。另一件要注意的事情是,当我们创建未来数据帧时,我们为大于 H 的时间段创建它。这是因为如果我们为 H 的时间段创建未来数据帧,随后在我们从数据帧中移除周末之后,我们可能在数据帧中以少于 H 天结束。

为了快速可视化,您可以使用 Prophet 绘制预测图,如下所示:

m.plot(forecast)

Predictions plotted using Prophet.

先知可视化很好,但为了更详细的外观,我仍将使用 Matplotlib:

Predictions on test set using Prophet.

上述预测给出的 RMSE 为 3.40,MAPE 为 2.87%,*均相对误差为 3.25。在这一点上,最后一个值法更胜一筹。下面我们将调整超参数,并观察预测是否有所改善。

具有超参数调谐的 Prophet 变点

时间序列的轨迹通常会发生突变。默认情况下,Prophet 采用自动变点检测。然而,可以通过使用参数 changepoint_prior_scale 来调整该变点检测的强度。增加 changepoint_prior_scale 将使趋势更加灵活,并导致过度拟合。减少 changepoint_prior_scale 将会降低趋势的灵活性,导致拟合不足。默认情况下,该参数设置为 0.05。

可以在 Prophet 中设置变点先验比例,如下所示:

m = Prophet(changepoint_prior_scale=changepoint_prior_scale)

我们使用训练集和验证集进行预测,下面显示了结果:

Tuning changepoint_prior_scale using RMSE, MAPE and MAE.

上述过程总共花费了 8 分钟。从上面可以看出,changepoint_prior_scale 的最佳值是 1。接下来,我们使用这个值并在测试集上运行我们的预测。结果如下所示。

Predictions on test set after tuning changepoint_prior_scale.

上面的预测给出的 RMSE 为 0.64,MAPE 为 0.52%,*均相对误差为 0.58。

具有超参数调整的 Prophet 每月季节性

可以在 Prophet 中设置每月季节性,如下所示:

m = Prophet()
m.add_seasonality(name='monthly', period=21, fourier_order=fourier_order)

上面的傅立叶级数是指用于估计季节性的部分和的项数。关于傅立叶阶的更多细节,请参考 Prophet 文档此处。

我们使用训练集和验证集进行预测,下面显示了结果:

Tuning fourier order of monthly seasonality using RMSE, MAPE, and MAE.

上述过程总共花费了 17 分钟。从上面,我们观察到傅立叶级数的最佳值是 3。接下来,我们使用这个值并在测试集上运行我们的预测。结果如下所示。

Predictions on test set after tuning fourier_order.

上面的预测给出的 RMSE 为 3.52,MAPE 为 2.98%,*均相对误差为 3.37。

具有超参数调谐的预言家—假日

Prophet 在进行预测时能够将节假日考虑在内。首先,我们需要构建一个假日数据框架,如下图所示,它可以很容易地从 csv 文件构建。

Holidays of the United States from 2013 to 2018 (only first 5 rows are shown).

列 lower_window 和 upper_window 将假日延长到日期前后的[lower_window,upper_window]天。更多信息,请参见此处。

假日可以在 prophet 中设置(假日是上面显示的数据框):

m = Prophet(holidays=holidays)

我们使用训练集和验证集进行预测,下面显示了结果:

Tuning window size for holidays using RMSE, MAPE, and MAE.

上述过程总共花费了 9 分钟。从上面,我们观察到窗口大小的最佳值是 None ie。不考虑假期会给出更好的预测。接下来,我们使用这个值并在测试集上运行我们的预测。结果如下所示。

Predictions on test set after tuning window_size.

上述预测给出的 RMSE 为 3.40,MAPE 为 2.87%,*均相对误差为 3.25。

先知与超参数调整-变点,每月季节性和假期

这里,我们调整变点、傅立叶级数和窗口大小,以观察性能是否可以进一步提高。我们使用训练集和验证集进行预测,下面显示了结果:

Tuning changepoint_prior_scale, fourier_order for monthly seasonality, and window size for holidays using RMSE, MAPE, and MAE. Only 5 rows of the entire dataframe are shown.

以网格搜索方式测试上述每个超参数总共需要 8 分钟* 17 分钟* 9 分钟= 20 小时。我们在我们的机器上用 Python 在 8 个内核上实现了一个并行化的实现,将这个过程减少到了 2 个小时。您可以查看 Jupyter 笔记本来了解这一实现(本文末尾提供了链接)。

从上面,我们观察到 changepoint_prior_scale、fourier_order 和 window 的最佳值分别为 2.5、10,并且不使用节假日。接下来,我们使用这些值并在测试集上运行我们的预测。结果如下所示。

Predictions for test set after tuning changepoint_prior_scale, fourier_order. and window_size.

上面的预测给出的 RMSE 为 0.55,MAPE 为 0.41%,*均相对误差为 0.47。

在这一点上,巩固我们从上面得到的结果是有好处的:

Performance evaluation of our various methods, based on forecast made for the 1009th day.

通过一起调整变点、傅立叶阶和窗口大小,我们能够使用 Prophet 在第 1009 天的预测中实现卓越的性能。接下来,我们来看看 Prophet 在其他日子是如何工作的。

多日预测

观察了上面超参数调整的效果后,我们将在这里扩展我们的方法来运行多天的预测。我们将从数据集的第 1009 天开始进行预测,每 42 天重复一次预测。因为我们的数据集中有 1509 天,所以我们将总共进行 12 次预测。对于每个预测,我们将坚持 21 天的预测范围。此外,对于第 t 天的每个预测,我们使用之前的 1008 天作为训练和验证集,如上所述训练和调整超参数。在优化超参数之后,我们将在 t 日运行预测。

如果没有我们的并行实施,要进行 12 次预测,需要 12 * 20 小时= 10 天。对于我们上面的并行实现,需要 12 * 2 小时= 24 小时。

结果如下所示。

Predictions on multiple days using Prophet.

从上面我们观察到,并不是所有的预测都是好的。在某些日子里,预测的方向和水*与实际值非常匹配,而在某些日子里,预测的方向和水*完全偏离。让我们将上面的结果与下面显示的最后一个值方法进行比较。

Predictions on multiple days using Last Value method.

Prophet 得出的*均 RMSE(11 次预测的*均值)为 3.16,*均 MAPE 为 2.15%,*均*均误差为 2.86。虽然这看起来不太坏,但最后一个值方法实际上返回了更好的结果——*均 RMSE 为 2.53,*均 MAPE 为 1.69%,*均*均*均误差为 2.26。

你可以在这里找到我的笔记本。你可以随意使用它,如果你设法找到超参数,以至于预言家可以持续击败最后一个值方法,请在下面的评论中分享!

使用 XGBoost 预测股票价格(第 1/5 部分)

原文:https://towardsdatascience.com/forecasting-stock-prices-using-xgboost-a-detailed-walk-through-7817c1ff536a?source=collection_archive---------2-----------------------

一步一步的演练

Photo by Jamie Street on Unsplash

野外有许多机器学习技术,但极限梯度提升(XGBoost)是最受欢迎的技术之一。梯度推进是以迭代的方式将弱学习者转换为强学习者的过程。XGBoost 这个名字指的是推动提升树算法的计算资源极限的工程目标。自 2014 年推出以来,XGBoost 已被证明是一种非常强大的机器学习技术,通常是许多机器学习竞赛中的首选算法。

在本文中,我们将尝试使用 XGBoost 来预测股票价格。我们已经在的前一篇文章中对 XGBoost 进行了试验,但是在本文中,我们将更详细地研究 XGBoost 应用于股票价格预测问题的性能。下面我们列出了这篇文章和上一篇文章的主要区别:

  • 在上一篇文章中,我们只预测了 1 天,但在这里我们预测了下一个 21 天(注意一个月大约有 21 个交易日,不包括周末)。为此,我们使用了一种被称为递归预测的技术。
  • 在前一篇文章中,我们使用了一个简单的训练-验证-测试分割,但是这里我们使用了移动窗口验证方法来执行超参数调整。
  • 在上一篇文章中,用作滞后特征的前几天的天数(表示为 N )被视为要优化的超参数。但是这里我们设置 N =14,让模型自己推断哪个滞后期对预测更重要。
  • 在上一篇文章中,我们只使用了前 N 天的价格作为特征,但在这里我们做了更多的特征工程并引入了更多的特征。

在本文的其余部分,我们将通过机器学习项目的标准步骤,重点关注我们的股票价格预测问题:

问题陈述
探索性数据分析
训练、验证、测试拆分
特征工程
特征缩放
超参数调优
应用模型
调查结果

值得注意的是,这里没有提到机器学习项目的其他步骤,如数据清理(这里不是问题)、缺失值插补(这里没有缺失值)和特征选择(嗯,我们这里没有很多特征)。这些话题也很重要,但在我们的问题中并不是一个问题,你会在下面看到。

问题陈述

在开始任何工作之前,明确定义问题陈述是非常重要的。在这里,我们旨在使用前 N 天的数据来预测 Vanguard Total Stock Market ETF(VTI)的每日调整收盘价。在这个实验中,我们将使用 VTI 从 2013 年 1 月 2 日到 2018 年 12 月 28 日的 6 年历史价格,可以从雅虎财经轻松下载。下载后,数据集如下所示:

Downloaded dataset for VTI.

总之,我们有 1509 天的数据可以处理。请注意,周六和周日不包括在上面的数据集中。整个数据集中调整后的收盘价如下图所示:

为了有效地评估 XGBoost 的性能,在一个日期运行一次预测是不够的。相反,我们将在该数据集中的不同日期执行各种预测,并对结果进行*均。

为了评估我们方法的有效性,我们将使用均方根误差(RMSE)、*均绝对百分比误差(MAPE)和*均绝对误差(MAE)指标。对于所有指标,值越低,预测越好。与我们的上一篇文章类似,我们将使用最后一个值方法来测试我们的结果。

探索性数据分析

EDA 是机器学习项目的一个重要组成部分,可以帮助您获得对数据集的良好“感觉”。如果你参加机器学习竞赛(或计划参加),广泛的EDA 可能会帮助你生成更好的功能,甚至发现“信息泄漏”,这可以帮助你爬上排行榜。正如我们将在下面看到的,EDA 过程包括创建可视化来帮助您更好地理解数据集。

下图显示了每个月的*均调整收盘价。我们可以推断,根据我们的数据集,*均而言,较晚的月份比较早的月份具有更高的值。

Average adjusted closing price by month.

下图显示了该月每天的*均调整收盘价。*均而言,有一个向上倾斜的趋势,该月的后几天的价格高于前几天。

Average adjusted closing price by day of month.

下图显示了一周内每天的*均调整收盘价。*均而言,周四和周五的调整后收盘价高于一周中的其他日子。

Average adjusted closing price by day of week.

下面的热图显示了前几天调整后的收盘价与当天收盘价的相关性。很明显,调整后的收盘价越接*当天,它们的相关性就越高。因此,应在预测中使用与前 10 天的调整后收盘价相关的特征。

Correlation heatmap for the lag features.

基于上面的 EDA,我们推断与日期相关的特性可能对模型有帮助。此外,前 10 天的调整收盘价与目标变量高度相关。这些是我们将在下面的特征工程中使用的重要信息。

特征工程

特征工程是一个创造性的过程,是任何机器学习项目中最重要的部分之一。为了强调特征工程的重要性,吴恩达有一句很好的名言值得分享(来自维基百科):

想出特性是困难的,耗时的,需要专业知识。“应用机器学习”基本上是特征工程。

— 吴恩达,通过大脑模拟的机器学习和人工智能

在这个项目中,我们将生成以下特性:

最* N=10 天



日月
日周
日年
是 _ 月 _ 日
是 _ 月 _ 日
是 _ 季 _ 日
是 _ 季 _ 日
是 _ 年 _ 日
是 _ 年 _ 日

使用 fastai 包可以很容易地生成与日期相关的特性:

使用上面的代码后,数据帧如下所示。列 adj_close 将成为目标列。为简洁起见,省略了与最* N 天的调整后收盘价相关的特征。

Dataframe containing the target column and date features.

下面的热图显示了功能与目标列的相关性。特征年份与调整后的收盘价高度相关。这并不奇怪,因为在我们的数据集中,有一个向上倾斜的趋势,即年份越大,调整后的收盘价越高。其他特征没有表现出与目标变量的高度相关性。从下面我们还发现特征是 _year_start 全是 nan。这是因为一年的第一天从来都不是交易日,所以我们从模型中删除了这个特性。

Correlation heatmap for date features.

下面是一个条形图,显示了前 10 个最重要功能的重要性分数。这是针对 2017 年 1 月 3 日的预测获得的,其他日期的预测可能具有不同的功能重要性排名。不出所料,调整后的前一日收盘价是最重要的特征。

Top 10 most important features for the forecast of 2017–01–03.

培训、验证和测试

为了进行预测,我们需要训练和验证数据。我们将使用 3 年的数据作为训练集,这对应于 756 天,因为一年中大约有 252 个交易日(252*3 = 756)。我们将使用未来 1 年的数据进行验证,这相当于 252 天。换句话说,对于我们做出的每个预测,我们需要 756+252 = 1,008 天的数据来进行模型训练和验证。将使用训练集来训练模型,并且将使用验证集来调整模型超参数。

为了调整超参数,我们将使用移动窗口验证方法。移动窗口验证方法在我们以前的一篇文章中有详细描述:

[## 使用 Prophet 预测股票价格

预测是一门硬科学,需要大量的专业知识。由于这些原因,脸书开源先知…

towardsdatascience.com](/forecasting-stock-prices-using-prophet-652b31fb564e)

下面举例说明了 756 天的训练规模、40 天的验证规模和 40 天的预测范围的情况。

Moving window validation example.

在时间序列预测中,训练、验证、测试分割必须按时间顺序进行,这一点非常重要。不这样做将导致模型中的【信息泄漏】,这被定义为根据提供关于测试集的信息的数据来训练模型的场景。例如,如果我们有今天的开盘价,并试图预测昨天的收盘价,我们可以立即将我们的预测设置为等于今天的开盘价,我们应该会得到相当好的结果。最终的结果是,我们的模型将给出比现实生活中可以预期的更好的性能。因此,在建立机器学习模型时,我们需要非常小心信息泄露。

在接下来的内容中,我们将使用 XGBoost 对测试集中的几天进行预测,即:

2017–01–03
2017–03–06
2017–05–04
2017–07–05
2017–09–01
2017–11–01
2018–01–03
2018–03–06
2018–05–04
2018

对于上述 12 个预测中的每一个,我们将使用 21 天的预测范围。我们将使用预测日期之前的 1008 天作为训练和验证集,如上所述,分割比例为 756:252。

特征缩放

特征缩放在这里很重要,因为如果你看上面的调整后收盘价图,按时间顺序分割训练集和测试集几乎总是导致测试集的调整后收盘价比训练集的值高。这意味着,在不调整调整后的收盘价的情况下训练的模型将仅输出训练集中价格范围附*的预测。这在我们之前的文章中也有解释:

[## 机器学习技术在股票价格预测中的应用

机器学习有很多应用,其中之一就是预测时间序列。最有趣的(或者…

towardsdatascience.com](/machine-learning-techniques-applied-to-stock-price-prediction-6c1994da8001)

我们已经试验了各种技术,在本文中,我们将使用从上面找到的具有最佳性能的方法。对于每个样本的调整后收盘价的每个特征组(滞后特征),我们将调整它们,使其均值为 0,方差为 1。例如,如果我们在第 T 天进行预测,我们将采用最后 N 天(第 T - NT -1 天)的调整后收盘价,并将它们换算成*均值为 0,方差为 1。对滞后特性的训练集、验证集和测试集进行同样的操作。日期要素不进行缩放。然后,我们使用这些缩放的滞后特征和日期特征来进行预测。预测值也将被缩放,我们使用它们相应的*均值和方差对它们进行逆变换。

超参数调谐

我们对验证集执行超参数调整。对于 XGBoost,有几个超参数可以调整,包括 n_estimatorsmax_depthlearning_ratemin_child_weight子样本gammacolsample_bytreecolsample_bylevel 。关于每个超参数的定义,见这里的。

为了查看超参数调整的有效性,我们可以查看 2018 年 11 月 1 日预测的验证集上的预测。下面显示了未进行超参数调整的预测,其中我们仅使用软件包中的默认值:

Predictions on the validation set without hyperparameter tuning.

下面显示了超参数调整后相同验证集的预测。你可以看到 1 月 18 日的疯狂预测现在稳定多了。

Predictions on the validation set with hyperparameter tuning.

下面显示了调整前后的超参数:

XGBoost hyperparameters before and after tuning.

显然,调整后的超参数与默认值相差很大。同样,在调整了 RMSE 之后,MAPE 和 MAE 的验证如预期的那样下降了。例如,RMSE 从 3.395 跌至 2.984。

应用模型

如上所述,执行了 EDA、特征工程、特征缩放和超参数调整之后,我们现在准备在测试集上执行我们的预测。在这种情况下,我们有一个 21 天的预测范围,这意味着我们需要为每个预测生成 21 个预测。我们不能一次生成所有 21 个预测,因为在生成第 T 天的预测后,我们需要将该预测反馈到我们的模型中,以生成第 T +1 天的预测,依此类推,直到我们得到所有 21 个预测。这被称为递归预测。因此,我们实现了如下流程图所示的逻辑:

Flowchart for recursive forecasting.

对于预测范围内的每一天,我们需要预测、重新调整预测、计算最后 N 个值的新*均值和标准偏差、调整最后 N 天的调整后收盘价,并再次预测。

调查的结果

下面显示了每个预测的 RMSE、MAPE 和 MAE,以及使用各自的验证集调整的相应(选定)最佳超参数。

RMSE, MAPE, and MAE of each forecast made with XGBoost.

使用移动窗口验证方法在我们的测试集上应用 XGBoost 的结果如下所示。

Forecasts on the test sets using XGBoost.

另一种可视化预测的方法是绘制每个预测的实际值。如下图所示。如果我们有完美的准确性,每个预测应该位于对角线 y=x 线上。

最后,以下是我们的模型相对于最后一个值方法的基准测试结果:

Final results.

与最后一个值方法相比,使用带有或不带有日期特性的 XGBoost 可以获得更好的性能。有趣的是,省略日期特征给出的 RMSE 比包含日期特征的略低(2.32 比 2.42)。正如我们之前发现的,日期特性与目标变量的相关性很低,可能对模型没有太大帮助。

你可以在 Jupyter 笔记本上查看不带日期功能的 XGBoost这里,带日期功能的 XGBoost这里。

我们希望你喜欢上面的文章,在那里我们通过真实的数据集而不是简单的教科书例子来工作和思考。递归预测机制的复杂性花费了我们比预期更长的时间,但是很有趣。本文的另一个重要观点是表明在构建机器学习模型时需要做出许多决定,这使得它不仅是一门科学,也是一门艺术。请在下面留下您的评论,并在这里查看第 2 部分!

时间序列预测的技术指标和 GRU/LSTM

原文:https://towardsdatascience.com/forecasting-with-technical-indicators-and-gru-lstm-rnn-multivariate-time-series-a3244dcbc38b?source=collection_archive---------5-----------------------

【门控循环单元】【GRU】【长短期记忆】【LSTM】

多元时间序列预测模型

Image by author

技术指标有很多,主要被股票交易者使用。大多数指标都有用户定义的变量,允许交易者调整关键输入,如回望期,它告诉我们将使用多少历史数据来进行计算,以满足他们的需求。我们将使用一些指标在现有数据集中创建特征。应用这些特征,我们将会看到我们是否能预测一只特定股票的未来价格。

我在这里曾经用【GRU】【LSTM】的门控循环单元来比较它们的表现。LSTM 在基于序列的长期依赖任务上已经建立良好,GRU 是机器学习领域的一个补充。它是【RNN】递归神经网络的即兴版本。我发现这篇 文章 挺有意思的,想多了解一下这两种网络架构。虽然它们在 NLP(自然语言文本处理)领域很受欢迎,但在这里,我已经在数字金融市场数据上试验了它们的性能。

GRU 和 LSTM 之间有一些相似之处和不同之处。

相似之处:

  • 两个网络都具有从 t 到 t + 1 的附加分量;新内容被添加到现有内容的顶部。
  • 两者都解决了渐变消失和爆炸的问题
  • GRU 的更新门和 LSTM 的遗忘门取现有状态和新计算的状态之间的线性和

差异:

  • GRU 有两个门,重置和更新门,相比之下,LSTM 有三个门,输入,忘记和输出。GRU 没有输出门,GRU 的更新门做 LSTM 的输入和遗忘门的工作。
  • 考虑到更少的参数和需要更少的数据来概括,GRU 在计算上更有效。
  • LSTM 有一个内部存储状态单元,而 GRU 没有单独的存储单元
  • GRU 没有任何机制来控制其状态或内存内容暴露的程度,而是每次都暴露整个状态或内存内容。LSTM 可以控制想要暴露多少内存内容。

你可以访问这篇文章来获得更多关于 GRU 和 LSTM 网络架构的理论观点。我将在这里用一个简单的例子解释特征创建和应用 RNN。

我创建了 2 个数据副本(tek_ind_1 & tek_ind_2)来添加不同技术指标组的列。

tek_ind_1 数据帧:

tek_ind_2 数据帧:

随机振荡器的计算(%K 和%D)

CCI =(典型价格 ma) / (0.015 **均偏差):

  • 典型价格=(高+低+收盘)/ 3
  • p =周期数(通常为 20)
  • ma =移动*均值
  • 移动*均=典型价格/ p
  • *均偏差=(典型价格-毫安)/ p

市云的计算:

  • 转折线=(最高价+最低价)/ 2,过去 9 天
  • 标准线=(最高价+最低价)/ 2,过去 26 天
  • 领先跨度 1 =(标准线+转折线)/ 2,提前 26 天绘制
  • 领先跨度 2 =(最高价+最低价)/ 2,过去 52 天,在今天之前 26 天绘制
  • 云=跨度 1 和跨度 2 之间的阴影区域

傅立叶变换:

对于已知具有季节性或每日模式的数据,我们希望使用傅立叶分析进行预测。这就像是外推和去噪的结合。我们希望重复多个时期的观察数据。并且还想通过找到观测数据中的主导频率分量来找到模式。我们将计算信号的傅立叶变换和频谱密度。

  • 第一步是使用 fft()函数计算信号的 FFT
  • 一旦获得 FFT,我们需要取其绝对值的*方,以便获得功率谱密度(PSD)

如果我们与 10、50、200 日均线图进行比较,我们可以看到傅立叶变换通过去噪更好地*滑了数据。

RNN 的数据准备:

我们看到数据点从-100 到 756.77 不等;我们需要对 RNN 网络的数据进行扩展和标准化。这将在我们分割训练/测试数据集后完成。

现在,让我们定义一个函数来创建时间序列数据集。我已经指定了回看间隔(60 个时间步)和预测列。RNN 的作品基于时间步骤。如果我们制作 60 个时间步长,这意味着,为了制作未来预测,我们的 RNN 将观察之前的 60 个时间步长,每次预测输出时,它将检查之前的 60 个时间步长。因此,我们需要相应地创建数据结构。

上面是转换数据集的前 4 行。我们可以看到 22 个输入变量(输入序列)和 1 个输出变量(收盘价)。如果我们检查数据的新形状,我们可以看到 60 个时间步长的差异。

这里,我们将数据集分为训练集和测试集。然后将训练集和测试集分成输入变量和输出变量。最后,输入被整形为 LSTMs 所期望的 3D 格式,即【样本、时间步长、特征】。我们将对 90%的数据进行模型拟合,然后对剩余的数据进行评估。

训练/测试分割:

值序列对于时间序列数据至关重要。因此,我们使用如下的系统方法将训练和测试中的数据分开。此外,需要标准化来拟合用于神经网络架构学习的数据。

为 LSTM 塑造数据:

在这里,我采取了 60 天的回顾期,模型将通过过去 60 个时间步骤来预测未来价格。

塑造训练数据:

LSTM 模式:

我们现在创建的 LSTM 模型有三个 LSTM 层和一个密集层。我定义了 LSTM,第一个隐层有 75 个神经元,第二和第三层有 30 个神经元;输出层中的 1 个神经元用于预测价格。输入形状将是具有 22 个特征的 60 个时间步长。

该模型是用*均绝对误差(MAE)损失函数和有效的随机梯度下降的 Adam 版本编译的。

准备测试数据:

一旦模型适合训练数据,我们希望看到模型在样本外数据上的技巧。与我们在训练集中所做的一样,我们将准备测试集,并且我们需要从训练数据中提取回望值。回看是用作预测下一个时间段(本例中为 60)的输入变量的先前时间步数。

该模型拟合了 20 个训练时期,批次大小为 32。

GRU:

GRU 网络是使用与 LSTM 相同的参数和配置创建的。

这里,LSTM 和 GRU 有相同的架构,但是 LSTM 的参数数量是 49,771,而 GRU 的 GRU 是 37,741。

正如我们已经讨论过的差异,GRU 有两个门,而 LSTM 有三个门。GRU 的参数较少,计算效率比 LSTM 高。

诊断图:

LSTM 和 GRU 模型的训练历史被用于诊断模型的行为。为了方便起见,我创建了一个单独的情节。

我们可以看到,在这两种情况下,训练损失都大大低于验证损失,表明模型可能对训练数据拟合不足。可以通过增加可以试验的时期来提高性能。

LSTM 预测:

这给了我们按比例缩小的预测值;我们反转标度,需要将这些值调整到正常标度。让我们找出数据的缩放级别。

这里,第一个值是开盘价;为了达到正常比例,我们将该值除以 1,如下所示。

评估模型:

现在,我们可以预测整个测试数据集,将预测与测试数据集相结合,并反转缩放比例。根据原始比例的预测值和实际值,我们可以计算模型的误差分数(均方根误差-RMSE)。RMSE 给出的误差单位与变量本身的单位相同。

可以通过取观察值和预测值的*均值并将它们彼此相除来计算精度。

我们可以在 GRU 模型上做类似的练习。

此外,可以通过添加更多的时间变量来提高模型的性能,例如添加周(星期几,星期号)、月(月号)和年列、时滞等。以及调整超参数和时期。

结论:

GRU 和 LSTM 的关键区别在于,GRU 有两个门(复位更新门),而 LSTM 有三个门(即输入输出忘记门)。GRU 网络更简单,因此更容易修改,例如在网络有额外输入的情况下增加新的门。一般来说代码更少。但是,如果序列很大或者准确性非常关键,我会推荐 LSTM

我这里可以连接

忘记 API 用漂亮的汤做 Python 抓取,从 web 导入数据文件:第 2 部分

原文:https://towardsdatascience.com/forget-apis-do-python-scraping-using-beautiful-soup-import-data-file-from-the-web-part-2-27af5d666246?source=collection_archive---------5-----------------------

不是每个网站都有 API,但 Beautiful Soup 将永远与您在一起,从任何网站收集任何类型的数据。

Souce: gurutechnolabs.com

如今,数据在每个行业都扮演着至关重要的角色。这些数据大部分来自互联网。大多数公司在一项技术上投资数百万美元来获得用户,却没有从投资产品回报中获利。互联网是如此之大,它包含了比你的书呆子教授更多的信息。
从网络中提取信息的重要性变得越来越明显。大多数时候,当我们在你的 facebook、twitter、LinkedIn 上添加任何信息并在 Yelp 上提供反馈时,这些信息都被视为数据。

这种来自互联网的数据有很多不同的来源,例如评论、Yelp 上的餐厅反馈、Twitter 讨论、Reddit 用户讨论和股票价格等。你可以收集所有这些数据,组织并分析它们。这就是我们在本教程中要讨论的内容。
从互联网上提取或导入数据有多种方式。您可以使用 API 从任何主要网站检索信息。这就是如今每个人从互联网上导入数据的方式——所有主要网站,如 Twitter、Twitch、Instagram、脸书,都提供 API 来访问他们的网站数据集。所有这些数据都以结构化的形式存在。但是大部分网站都没有提供 API。我认为他们不希望我们使用他们的用户数据,或者他们因为缺乏知识而不提供这些数据。因此,在这个主题中,我们将从 web 导入数据,而不使用任何 API。但是在我们处理之前,请看看我们这个系列的部分 1 ,因为一切都像点一样连接在一起。

[## 一些你不知道的数据文件如果你只是一个数据科学的初学者,导入数据文件…

如果你是数据科学领域的新手,那么你必须努力学习数据科学概念。现在…

towardsdatascience.com](/something-you-dont-know-about-data-file-if-you-just-a-starter-in-data-science-import-data-file-e2e007a154c4)

什么是美丽的汤

Don’t write that awful page ( Source: crummy.com)

Beautiful Soup 是从特定网站或互联网上删除数据的最佳图书馆。这也是最舒适的工作。它从 HTML 中解析并提取结构化数据。Beautiful Soup 自动将传入文本转换为 Unicode,将传出版本转换为 UTF-8。除了文档没有定义编码和 Beautiful Soup 抓不到编码之外,你不需要记住编码。那就不得不提原始编码了。

规则:要运行您的程序,请使用 Jupyter python 环境运行您的程序。而不是一次运行整个程序。我们只是采取预防措施,所以你的程序不会破坏网站。请检查网站的条款和条件,然后再开始从那里提取数据。请务必阅读关于合法使用数据的声明。

基础-熟悉 HTML

HTML 代码在从网站提取数据的过程中起着重要的作用。所以,在我们处理之前,让我们跳到 HTML 标签的基础。如果你对 HTML 标签有一点点的了解,你就可以前进到下一个层次。

<!DOCTYPE html>  
<html>  
    <head>
    </head>
    <body>
        <h1> Learning about Data</h1>
        <p> Beautiful Soup</p>
    <body>
</html>

这是 HTML 网页的基本语法。每个 <标签> 都服务于网页内部的一个区块:
1。!DOCTYPE html > : HTML 文档必须以类型声明开头。
2。HTML 文档包含在 < html >< /html > 之间。
3。HTML 文档的元和脚本声明在 <头></头> 之间。
4。HTML 文档的可见部分在 <正文></正文> 标签之间。
5。标题用 < h1 >< h6 > 标签定义。6。用 < p > 标签定义段落。

其他有用的标签包括用于超链接的 < a > ,用于表格的 < table > ,用于表格行的 < tr > ,以及用于表格列的< td > 。

让我们检查一下你的 HTML 页面

[## 亚洲国家地区列表-维基百科

需要额外的引用来验证。通过增加对可靠来源的引用来改进这篇文章。无来源…

en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_Asian_countries_by_area)

让我们用一个维基百科页面来做报废。如果你有谷歌 chrome 浏览器,那么进入页面,首先右击它,打开浏览器检查器检查网页。

Inspect Wikipedia Page

从结果中你可以看到这个表在 wiki 表中是可排序的,如果你仔细查看,你可以在那里找到你所有的表信息,太棒了!!!。看看你能用漂亮的汤做什么会更令人惊奇。

Wikitable Sortanble

让我们开始你的 DIY 项目吧

现在我们知道了我们的数据及其位置。因此,我们将开始废弃我们的数据。

在我们处理之前,您需要安装或导入一些库。

#Import Libraries
*from* ***bs4*** *import* ***BeautifulSoup*** *import* ***requests***

如果你在安装中遇到任何麻烦,你可以在每一行前面使用 sudo

请求
它本来是人类用来交流的语言。这意味着您不必手动将查询字符串连接到 URL,或者对您的帖子数据进行格式编码。请求将使您能够利用 Python 发送 HTTP/1.1 请求。在其中,您可以通过简单的 Python 库组合内容,如标题、表单数据、多部分文件和参数。它还使您能够以同样的方式获得 Python 的响应数据。

BS4—Beautiful Soup
Beautiful Soup 是一个 Python 库,用于从 HTML 和 XML 文件中提取数据。它与您最喜欢的解析器一起工作,产生操作、检查和转换解析树的自然方式。它通常会节省程序员几个小时或几天的工作。

*# Specify with which URL/web page we are going to be scraping*
url = requests.get(‘[https://en.wikipedia.org/wiki/List_of_Asian_countries_by_area](https://en.wikipedia.org/wiki/List_of_Asian_countries_by_area)[’).text](https://en.wikipedia.org/wiki/Premier_League).text)

我们首先研究给定网页的源代码,并使用 BeautifulSoup 函数构建一个 BeautifulSoup (soup)对象。现在,我们需要使用漂亮的 Soap 函数,它将帮助我们解析并应用从维基百科页面获取的 HTML:

*# import the BeautifulSoup library so we can parse HTML and XML documents***from** bs4 **import** BeautifulSoup

然后,我们将使用 Beautiful Soup 来解析我们在“URL”变量中收集的 HTML 数据,并分配一个不同的变量来以名为“Soup”的 Beautiful Soup 格式存储数据

*#Parse the HTML from our URL into the BeautifulSoup parse tree format*soup **=** BeautifulSoup(url, "lxml")

要了解我们的 web 页面中底层 HTML 的结构,请使用 Beautiful Soup 的 prettify 函数并检查它。

*#To look at the HTML underlying to the web* 
print(soup.prettify())

这是我们从pretify()函数中得到的结果:

<!DOCTYPE html>
<html class="client-nojs" dir="ltr" lang="en">
 <head>
  <meta charset="utf-8"/>
  <title>
   List of Asian countries by area - Wikipedia
  </title>
  <script>

如果您访问此链接 并查看我们的亚洲国家维基百科页面,我们可以看到关于国家地区的更多信息。维基百科表格已经设置好了,这使得我们的工作更加容易。

让我们在我们美化的 HTML 中寻找它:

就这样,以一个 HTML < table > 标签开始,标签的类标识符为“wikitable sortable”我们将记住这个类以备将来使用。如果你在你的程序中往下走,你会看到表格是如何组成的,你会看到开始和结束的行都有<>< /tr > 标签。

第一行标题具有第 <个> 标签,而下面每个俱乐部的数据行具有 < td > 标签。使用 < td > 标签,我们将告诉 Python 保护我们的数据。

在我们继续之前,让我们设计一些漂亮的 Soup 函数来演示它如何从 HTML 网站获取数据并传递给我们。如果我们做标题函数,Beautiful Soup 将返回标题的 HTML 标签和其中的内容。

*#To get the title of the page*
soup.title()

我们可以利用这些信息开始准备对 HTML 的攻击。
我们知道数据保存在一个 HTML 表中,所以首先,我们让 Beautiful Soup off 检索页面中所有出现的 < table > 标签,并将它们添加到一个名为 all_tables 的数组中。

*# use the 'find_all' function to bring back all instances of the 'table' tag in the HTML and store in 'all_tables' variable*all_tables**=**soup.find_all("table")all_tables

在 table class 'wiki table sortable下,我们有以国家名称为标题的链接。

# *use the 'find_all' function to bring back all instances of the 'table' tag in the HTML and store in 'all_tables' variable*My_table = soup.find('table',{'class':'wikitable sortable'})
My_table

在 table class 'wiki table sortable下,我们有以国家名称作为标题的连接。现在,我们要提取 < a > 内的所有链接,我们使用 find_all()

links = My_table.findAll('a')
links

从 URL 中,我们必须提取标题,即国家的名称。为此,我们必须创建一个国家列表,以便我们可以从链接中提取国家的名称,并将其添加到国家列表中。

Countries = []
**for** link **in** links:
    Countries.append(link.get('title'))

print(Countries)

现在,我们必须将列表国家转换成熊猫数据框架,以便在 python 中工作。

**import** **pandas** **as** **pd**
df = pd.DataFrame()
df['Country'] = Countries

df

如果你对大量废弃数据感兴趣,你应该考虑使用 Scrapy ,一个强大的 python 抓取框架,并尝试将你的代码与一些公共 API 集成。
数据检索的性能明显高于抓取网页。例如,看看脸书图形 API ,它可以帮助你获得脸书网页上没有显示的隐藏数据。当你的信息变得太大时,考虑使用数据库后端,比如 MySQL T21。

这就是我们美丽的汤教程的结尾。自信地说,它让你开始为下一个项目检查一些刮掉的东西。我们已经引入了获取 URLHTML 数据的请求,解析 HTMLPandas 的 Beautiful Soup 将数据转换成数据帧以便正确显示。

你可以在这里找到这本教程笔记本。如果你有问题,请随时提问。在下一个教程中,我们将讨论 API。欢迎随时在 LinkedIn 上联系我。

参考文献:1。http://www . Greg reda . com/2013/03/03/we B- scraping-101-with-python/。

2。http://www . analyticsvidhya . com/blog/2015/10/初学者-指南-web-刮-美-汤-python/ 。

3.https://github . com/stewync/we B- Scraping-Wiki-tables-using-beautiful soup-and-Python/blob/master/Scraping % 2b Wiki % 2b table % 2b busing % 2b Python % 2b band % 2b eautiful soup . ipynb

4.https://en . Wikipedia . org/wiki/List _ of _ Asian _ countries _ by _ area

5.【https://www.crummy.com/software/BeautifulSoup/

别管机器人了!这是人工智能将如何得到你

原文:https://towardsdatascience.com/forget-the-robots-heres-how-ai-will-get-you-b674c28d6a34?source=collection_archive---------3-----------------------

人工智能比传统软件更危险的真正原因

Here’s the audio version of the article, read for you by the author.

人工智能伦理是这些天的热门话题,所以你会看到各种各样的言论。抱怨的范围从“机器人抢了我的工作”“你的计算机系统就像 一样有偏见 就像你一样(你这个混蛋)。”

为什么我们不讨论是什么让 ML/AI 独特地比其他技术更危险?

与人工智能伦理相关的话题是至关重要的、及时的和必要的。我们继续讨论吧!我只是希望我们不要使用人工智能伦理这个术语,只要它…甚至与人工智能无关。

当人工智能伦理讨论没有抓住要点时

不是挑世界经济论坛的毛病(非常爱你,伙计们),但我发现这篇 WEF 关于人工智能 9 大伦理问题的文章是一个快速练习的方便素材。

许多人工智能伦理话题并不是专门针对人工智能的。它们一般都是关于技术的,并不新鲜。

取他们的章节标题,用“技术”替换{“人工智能”、“机器人”、“机器”、“智能系统”、“人工”},看看我们是否打破了什么。

You can find the full article here.

他们的“9 大问题”有多少是 特定 给 AI 的?

  1. 乔布斯去世后会发生什么?
  2. 我们如何分配技术创造的财富?
  3. 技术如何影响我们的行为和互动?
  4. 我们怎样才能防范错误?
  5. 我们如何消除技术 偏差
  6. 我们如何保护技术免受敌人攻击?
  7. 我们如何防范意外的后果?
  8. 我们如何控制复杂的技术?
  9. 我们如何定义技术的人道待遇?

道德问题 1-8 通常与技术相关,当然也与大规模的传统软件相关。利用人工智能让公众对它们感兴趣让我想起了地质学家用宠物岩石作为教具。这一切都很有趣,直到地质课变成了宠物岩石心理学(第 9 期)。

Paint a face on something and before long you’re having conversations with it. That’s a malfunction with how our species is wired. Just because something about it reminds you of you doesn’t mean it’s got a brain.

利用人工智能让人们思考技术中的伦理问题,让我想起了地质学家用宠物岩石作为教具。这一切都很有趣,直到地质课变成了宠物岩石心理学。

如果你想延续对人们的不公*待遇,推出无效的解决方案,扰乱劳动力市场,改变人们相互之间的互动方式,发布落入坏人手中的具有意想不到的后果的东西,并创建一个你无法摆脱的复杂系统,你可以在没有 ML/AI 的情况下完成这一切。(请不要。)你也可以就所有这些事情对我们的世界意味着什么进行富有成效的讨论,而不必求助于大数据或神经网络。

奇点可以等待(它的星云奖)。

那么,有没有针对 ML/AI 的问题呢?当然啦!难道是奇点?我们不要操之过急。奇点可以等待(等待它的星云奖)。有一个更紧迫的候选人可以归结为今天的人工智能实际上是什么

This is just another pet rock. The mimicry is slightly better, sure, but it’s still a lifeless object with a face painted on it.

人工智能对抗机器人

AI 有什么了不起的?它让你自动化不可言喻的!您可以使用数据中的模式,而不必思考解决方案。你知道这有多强大吗?这意味着即使你不能给出指令,你也可以自动完成你的任务。你还想要什么?做人?替代人类?奇点?停止。人工智能与此无关。将它作为镀铬人形机器人进行营销利用了公众的无知…并转移了你对真正危险的注意力。

机器人只是另一种宠物石。去吧,在你的吸尘器上贴上眼睛贴纸,我知道你想。

如果我们用我们的精神能量担心错误的事情,我们会错过我们真正应该担心的部分。你不应该让诗人骗你。

Neural networks aren’t brains.

今天使用人工智能这个术语的方式并不是为了开发具有人格的替代类人实体。(更好的说法是 HLI。)这是一套用不同方式编写软件的工具,让你用例子(数据)而不是明确的指令来编程。

"人工智能是一套用例子(数据)而不是显式指令编程的工具."

寻找人工智能的希望?AI 的危险怎么样?他们都在最后一句话里。仔细看…

注意力分散的程度

假设您想要自动化一项需要 10,000 个步骤的任务。在传统编程中,一个必须为这些小指令中的每一条流汗。

在传统的编程中,解决方案的每一部分都是由人手手工制作的。

把它想象成需要人手排列的 10K 乐高积木。由于开发人员幸运地没有耐心,他们会打包一些部分,这样就不需要重复。你可以下载一些其他人已经组装好的包,而不是使用 10,000 个零散的部分,然后你就可以在更高的抽象层次上工作了——你只需要将 50 个预先构建的 200 个小积木组装在一起。如果你信任包装这些乐高积木的人的工作,那么你就不需要考虑每个积木的细节。你可以把屋顶部分和房子部分连接起来,而不是考虑瓦片和砖块的水*。谁会有时间做这些呢?(也许,当你完成后,你会把你的 10K 作品打包,这样制作 100K 史诗的人就可以即时复制它,这样也可以节省时间。向 GitHub 致敬!)

但事情是这样的:即使 you 不需要自己做所有的事情(谢天谢地),这 10,000 个步骤中的每一条指令都被人类的大脑折磨过……而这就是与 ML/AI 一起消失的部分。

机器学习将你从高度抽象带到新的分心水*。

在 ML/AI 工程中有很多愤怒和不满,但大部分都是关于旋转和争论不友好的工具。您可能会在项目中编写 10K 代码行,但大多数代码都是为了哄骗那些笨拙的工具接受您的指令。随着工具变得越来越好,你最终会发现 ML/AI 中只有两条真正的指令:

  1. 优化这个目标 …
  2. … 在此数据集上。

仅此而已。现在你可以用两行人类思维来自动化你的任务,而不是一万行。这很美,也很可怕!

AI 真正自动化的是谁的工作?

有些任务不是很重要,我们不需要太多思考就可以完成,这真是太棒了。您可以更快地完成工作!即使你不知道怎么做,你也能把事情做好!这就是那些没有被科幻蒙蔽双眼的人对 ML/AI 的狂热的来源——而这种狂热是真实的。

ML/AI 让人类跳过手工制作这 10,000 个显式的解决步骤,而是通过开发人员给出的例子中的模式来自动产生这 10,000 行(或类似的内容)的解决方案。

最根本的区别在于内在的体贴程度。

如果你从未思考过 ML/AI 实际上自动化了谁的工作,请准备好大吃一惊:

开发人员自动化/加速其他人的工作。

ML/AI 自动化/加速了开发者的工作。

不要编写“做这个,然后这个,然后这个,然后……”你可以说,“努力在这些 数据 上取得好成绩。”换句话说,“这是我喜欢的,让我知道你的一只打字机上的猴子什么时候到了。”

(别担心,要让算法在数据集上运行,还有很多争论要做,所以软件工程师不会过时。然而,随着它们从通过指令告诉计算机做什么转变为通过数据告诉它做什么,它们的工作方式将会改变。)

允许粗心大意

该是笑点的时候了!这里有一个最直接的特定于 ML/AI 的问题:粗心导致

当我们人类同胞的福祉受到威胁时,轻率是一种危险。人工智能是一个轻率的推动者。

重要的是,不管是谁负责这个项目,他真的会把 5000 条指令的思想放进每一条 2 ML/AI 线吗?真的,真的?

What else did you forget to think through?

哪些例子?

ML/AI 是关于用例子来表达自己,所以你有一个不幸的选择,将你的系统指向一个数据集,而从来没有验证过里面的东西是相关的、无偏见的,高质量的例子。现在是关于人工智能偏见从何而来的海明威演讲…

人工智能偏见:不恰当的例子,从来没有审查。

哪些目标?

你也有足够的时间轻率地选择一个目标,这个目标听起来不错,但结果却是个糟糕的主意。“尽可能多地捕捉垃圾邮件”一位领导者可能会对人类开发人员说,期待一个可靠而明智的过滤器。对一个人工智能算法说同样的话,你很快就会开始奇怪为什么没有新邮件进来。(回答:将所有的标记为垃圾邮件会在你的陈述的目标上得到满分)。

任何一个傻瓜都能说出一个轻率的目标。不幸的是,一个学习系统会让他们这样做。

所有这一切都因一种奇怪的神秘主义而加剧,这种神秘主义依附于词语、【数学】、——我怀疑当人们选择他们的目标和例子时,它会诱使人们甚至更少地思考他们在做什么。唉,这里除了你自己没有大脑,数学是夹在你的主观性三明治中间的一层小小的客观性。

数学是夹在你的主观性三明治中间的一层薄薄的客观性。

哦亲爱的。随着工具变得越来越好,进入的门槛会变得很低,以至于你会在去洗手间的路上被绊倒……这对小型个人项目来说非常好。但当涉及到具有影响他人力量的项目时,ML/AI 要求负责人付出更多努力,而不是更少。这需要高超的领导能力。我们准备好迎接挑战了吗?

“Give me a place to stand and with a lever I will move the whole world.” -Archimedes

技术,伟大的杠杆

技术改善了我们的世界,拓展了我们的视野,让我们活得更长,让我们的物种能够养活自己,尽管我们毫无节制地想要繁衍成几十亿。它也能使人吃惊、不稳定和重新分配。规模越大,破坏性就越大。这是一个扩展人类潜能的杠杆,但每当你用技术放大自己的时候,要小心了!更容易踩在身边的人身上。

It’s always more appropriate to think of your tools — including AI — as extending you, rather than being autonomous. When they enlarge you, be sure you’ve got the skills to avoid stepping on those around you.

当我们用技术放大自己的时候,就更容易把周围的人踩在脚下。

尽管许多与人工智能伦理相关的问题并不是人工智能特有的,但人工智能可能会在一些痛处引起额外的炎症。这就是为什么这些讨论重新焕发活力是有意义的。

疏忽的配方被放大了

如果你问我是否害怕人工智能,我听到你问我的是我是否害怕人类的疏忽。这是这个问题对我来说唯一有意义的方式,因为我不相信机器人童话或者和宠物石头说话。

让开,创造人工生命的伦理。你好,不顾规模的伦理学。

以我们开始的 9 个主题为例,注入更多、更多、更大的规模和速度。当你在这个等式中加入一个轻率的促成因素时,你就得到了一个迅速放大疏忽的配方。

人工智能的可怕之处不在于机器人。是人民。

权力越大,责任越大,但在一个由大规模数据驱动的社会中,人们是否急于打造负责任领导所需的新肌肉?难怪我们担心被踩。

我害怕 AI 吗?

号码

我对人类的人工智能未来持乐观态度,但我也尽我所能不让它听天由命。我相信,人工智能时代负责任的领导技能是可以教授的,人们可以明智地建立安全有效的系统,推动进步,让周围的人生活得更好。这就是为什么我(和其他像我一样的人)选择站出来和分享我们通过经验或在以前孤立的学术学科中搜罗来之不易的知识。

人工智能是我们如何超越低垂的果实来解决人类最具挑战性的问题。

当我们把我们的声音集合在一起,培养一批精于决策智能的新一代领导者时,我们希望帮助新一代人更周到地构建人工智能,并释放技术的最佳一面。同样的一面,带我们去星星,让我们免于疾病,消除无知,节约资源,把我们和世界另一端的爱人联系起来。

如果我们允许的话,科技会变得很美好…我相信我们会的。

感谢阅读!人工智能课程怎么样?

如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:

Enjoy the entire course playlist here: bit.ly/machinefriend

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格联系。

MS SQL Server 的 SQL Complete 中的格式化功能

原文:https://towardsdatascience.com/formatting-capabilities-in-sql-complete-for-ms-sql-server-57bcc3fdfb26?source=collection_archive---------33-----------------------

回到时间优化的问题。MS SQL Server 中快速脚本理解和定义对象的另一种方式

MS SQL Server 开发人员和 DBMS 管理员都知道,在编码过程中,文本格式化需要花费大量时间。还有,格式化往往很肤浅,甚至完全没有。事情变得更加复杂,因为每个人都有不同的格式,没有统一的风格。所有这些都会导致这样的情况,一个专家会花很多时间去理解另一个专家写的代码。

从我自己的经验来看,建立一套格式规则通常需要几年的时间。在整个公司范围内,甚至是公司的某个部分,开发和应用这种标准的主要问题在于,一个人很难学会用不同的方式编写代码。在代码审查过程中也会感觉到很多阻力,因为维护代码的专家并不总是同意格式规则。在实践中,如果没有特殊的工具,手工维护这些标准是非常困难的。

当你有专门的代码格式化软件时,你可以通过它设置自己的格式化标准,或者直接使用默认的格式化标准。这样,从现在开始,所有代码都将被自动格式化。因此,您不需要在脚本格式化和格式审查上花费时间。

通常,标准化流程有以下生命周期:

  1. 公司中使用 SQL 的人数增长到 4 人以上(这个值不一定在所有情况下都相同,但通常 4 是一个很好的里程碑)
  2. SQL 代码的数量增加了,专家们现在不得不交换知识,有时在他们的任务中互相替换。通常,在这一点上,已经有许多数据库和至少几个项目。来自不同项目和/或数据库的人们相互分享他们对这些项目和数据库的知识。
  3. 有必要建立统一的格式样式。指定一个团队来开发格式规则,并在投票中展示它们,或者提出一个现成的解决方案。
  4. 投票后,相应地更改标准,然后重复步骤 3-4,直到标准被必要数量的人接受(在大多数情况下,最好是几乎每个人都接受标准,而不只是大多数人,这将有助于尽可能地遵守标准)
  5. 决定如何维护标准,包括在代码审查级别。

初始标准通常取自所选工具中的默认标准,这样,步骤 3-4 将不会循环,步骤 5 将同时求解。

在一些公司,第三步没有实现,所以专家们决定如何自己写代码。这使得开发过程、代码维护和引入变更变得非常复杂。

你可以把一个公司发展代码标准化的过程分为 三个阶段 :

1。没有标准,每个人都按照自己的想法写代码

2。有一个标准,但是是手工维护的

3。有一个标准并自动维护

根据我的观察,我们可以看到开发和维护速度在三个主要阶段之间的增长,如下所示:

此表估计了开发、维护和案例转移所花费的*均时间。

您可以使用特殊的工具来自动维护标准——这些工具可以是自定义编写的,也可以是从可用的第三方解决方案中选择的。

数据库专家迟早会意识到,如果希望所有开发人员更好地理解代码,格式标准化是至关重要的。你可以找到付费和免费的解决方案。

在本文中,我们将研究这些工具中的一个——用于 MS SQL Server 的 SQL Complete 。目前,这个工具集成了 SSMS 和 Visual Studio。它还内置于db forge Studio for SQL Server中。

SSMS 的 SQL Complete 菜单如下所示:

Fig.1 SQL Complete in SSMS

该工具的主要功能是:

  1. 禁用/启用代码完成 —关闭/打开工具
  2. 格式化文档 —开始整个文档的格式化过程
  3. 格式选择 —开始代码选定区域的格式化过程
  4. 转到定义 —转到对象浏览器中的指定对象(存储过程、视图、表、函数等)。)
  5. 执行历史 —打开包含在 SSMS 执行的命令历史的日志
  6. 恢复最后关闭的文档 —打开先前关闭的 SQL 文档选项卡
  7. 最*关闭的文档 —显示最*关闭的文档列表
  8. 选项 —工具设置,包括格式规则
  9. 导入导出设置 —导入导出刀具设置

类似的功能也被集成到 SSMS 下拉菜单中。除此之外,SQL 文档上下文菜单中还添加了以下选项:

  1. 活动格式配置文件 —允许您选择必要的格式配置文件
  2. 将对象脚本化为 CREATE/ALTER —允许您生成光标所在的 DDL 对象。
  3. 将表格脚本化为 CRUD —允许您基于脚本生成程序。
  4. 重命名 —允许您重命名文档中的名字对象、变量和脚本对象。
  5. 将 EXEC 转换为脚本 —允许您将程序代码转换为可执行脚本,主要用于调试等。

Visual Studio 中的 SQL Complete 菜单如下所示:

Fig.2 SQL Complete in Visual Studio

该工具的类似功能已经在前面讨论过了。

Visual Studio 的下拉菜单中集成了相同的功能。

现在,让我们看看代码格式化在这个例子中是如何工作的:

1) 打开脚本文件,点击“格式化文档”:

Fig.3 Script before formatting

2) 这是我们得到的格式化脚本结果:

Fig.4 Script after formatting

现在,让我们看看“转到定义”命令:

Fig.5 Calling the stored procedure

正如前面的屏幕截图所示,当我们指向这个过程时,我们获得了存储过程的签名及其扩展属性的描述。

当鼠标光标被设置在程序上时,我们需要按 F12 或从下拉菜单中选择“转到定义”:

Fig.6 Calling “Go To Definition”

将在对象资源管理器中选择必要的存储过程:

Fig.7 Selection of the necessary stored procedure in the object explorer

对于其他对象类型,如表、视图、函数等,F12 以同样的方式工作。

此外,SQL Complete 工具还提供了一些有用的功能,如:

  1. 代码完成
  2. 通过最佳搜索树实现的工具提示
  3. 搜索无效对象(即引用其他不存在对象的对象)等。

然后

这样,通过具备格式化代码、将代码转化为统一风格和对象导航的能力,您可以显著减少理解脚本和定义对象所花费的时间,这将极大地影响新功能、新软件的开发以及该功能和软件的维护的质量和时间。

组建机器学习/AI 团队?

原文:https://towardsdatascience.com/forming-a-machine-learning-ai-team-22d0ad70c47d?source=collection_archive---------22-----------------------

不要忘记你需要的其他关键技能

企业被围绕机器学习和人工智能创造的炒作所淹没,但我相信没有人想错过这趟巴士,并努力团结起来,建立自己的数据科学能力。但在他们创建机器学习/人工智能团队的热情中,领导层必须小心不要忘记其他也需要的关键辅助和补充技能。我想通过这篇博客来谈谈这些技能,这样决策者就可以为全面的数据科学战略做准备。

Photo by Josh Calabrese on Unsplash

我记得当我还是个孩子在学校的时候,我对宇航员很着迷,每当有人问我长大后想成为什么,我会说我想成为一名宇航员。不仅如此,出于某种原因,我天真地以为 NASA 的每个人都是宇航员。但随着我的成长,我意识到宇航员只是一个成功的太空机构所需的全部技能中的一项。这包括像机械工程师、计算机工程师、地质学家、物理学家、化学工程师等专业人员。在企业中组建成功的数据科学团队也是如此。

这是企业级数据科学系统的高级架构。尽管这可能因企业而异,但这应该让人们对该体系结构工作所需的各种技能有所了解。让我们更详细地研究一下这种架构。

Data Science System Architecture*

*该架构纯粹是说明性的&实际实施可能因多种因素而异

1.数据工程层

数据工程(DE)层是成功的数据科学团队的基础层,没有它,任何数据科学战略都不完整。数据工程团队的核心职责如下

  1. 识别相关数据

随着数据量、种类和速度的激增,数据源大量涌现,企业需要准备好处理任何形式和任何数据量的任何类型的数据。通常,企业的不同数据源可以大致分为内部数据源和外部数据源(基于数据源)。内部数据包括交易系统、显示客户参与度指标(会话、*均会话持续时间等)的数字分析数据、客户反馈和支持指标等。、CRM 等。外部数据包括社交媒体数据、消费者调查信息、行业基准报告等。

DE 团队需要确定所有与解决企业的战术和战略需求相关的数据,并制定适当的策略来解决这些问题。

2。摄取数据

一旦确定,来自所有这些来源的数据需要被吸收到企业数据湖或某种数据存储中。接收必须确保定期且一致地刷新数据。

3。建立数据*台

摄取的数据需要以一种支持商业智能(BI)需求以及机器学习(ML)和 AI 需求以及组织的其他数据需求的形式持久化。通常情况下,大多数企业都会创建一个数据集市/数据仓库,用于存储有关企业运营的历史信息和其他类型的数据存储,如非 SQL 数据存储,以满足高性能下游应用程序的数据需求。创建这些数据结构是 ML & AI 团队成功的关键,因为他们从这些系统中获取数据。

4。维护数据生态系统

一旦创建了数据结构,就需要对它们进行全面的维护,以确保数据在生态系统中以定期和一致的方式得到刷新

所需技能 —数据仓库、NoSQL、ETL 管道构建、大数据生态系统技能— Hadoop、Spark、Hive 等、云— AWS/Azure 数据服务

2.机器学习层

机器学习(ML)层是所有与构建 ML 能力相关的活动所在。您需要在这一层计划的一些活动包括以下内容。

a)模型构建&验证 —利用数据工程层创建的数据,开始构建预测模型,以对客户对电子邮件活动的回复、客户购买产品的倾向、客户流失、预测模型、推荐引擎等事件进行建模。

b)模型部署——一旦模型构建完成并得到验证,就应该将其部署到生产环境中,以获得业务收益。模型可以部署为 I)批处理模式或 ii)实时模式。在批处理模式下,模型用于以预定的时间间隔(通常在营业时间之后)对数据进行评分,或者计划以预设的频率运行(每小时或 2 小时)。这通常是一个更容易处理的设计。相反,在实时模式下,模型被期望以*乎实时的方式几乎即时地评分并返回结果。要实现这样的设计,需要一种机制来接收模型推理请求,然后将模型结果返回给发出请求的应用程序。

为了实现这样的应用程序,通常需要使用服务器端脚本语言(如 node.js 或 flask)来构建 ML API 层。但是,如果生产环境是在 AWS 等云上管理的,那么管理起来就比在本地管理要简单得多。

所需技能 —机器学习、深度学习

3。API 层

a)ML API——正如上一节中简要讨论的那样,为了使模型能够实时使用,或者为另一个应用程序提供它,在架构中提供一个 API 层是很重要的。这一层将包含所有的 API 函数,这些函数将接受对模型进行评分的请求,并将结果对象返回给调用应用程序

b)数据 API——将上述概念扩展到由数据工程层创建的数据存储,需要创建数据 API 层来处理不同消费应用程序从数据存储中提取数据的请求。为此目的描述一个单独的数据 API 层将是一个很好的设计选择

所需技能 — API 开发、Web 开发— Node.js(或任何类似的脚本语言)、云技能— AWS、Azure

4。可视化图层

最后,为了将模型交付给业务用户,最好将其作为具有直观 UI 的 web 应用程序,而不是以用户需要从命令行界面使用的原始形式传递它。如果你没有理解后面的部分,不要担心,因为执行起来就像向别人解释一样枯燥,而且一点也不直观。

如今,将模型作为 web 应用程序部署在云上已经变得越来越容易,因为有一些现有的框架可以自动处理这种设计的许多技术方面,ML 工程师只需要专注于构建一个优秀的模型,而将其余的工作留给这些框架。

所需技能—全栈 web 开发

2D 卷积层的向前和向后传播

原文:https://towardsdatascience.com/forward-and-backward-propagations-for-2d-convolutional-layers-ed970f8bf602?source=collection_archive---------10-----------------------

深度学习:理解理论以便更好地实践

推广到多通道输入和多滤波器

动机

已经有许多关于到数据科学的文章讨论了卷积神经网络的反向传播。

它们很好地解释了简单的情况(例如,只有一个通道的输入,当时只有一个卷积滤波器),但我发现很难将反向传递实现推广到任意选择的层。

为了克服这个困难,我决定回到反向传播的理论方面。找到这些方程后,实现变得容易多了。

本文旨在给出多通道输入和多滤波器卷积层的前向传播和后向传播的关键方程,以及如何得到它们。

如果你只对结果感兴趣,请随意下结论!

几个定义

卷积层执行…卷积!然后,我们需要定义有用的数学运算符:

一方面,任意大小的图像和具有大小为(k1,k2)的核 K 的 C 个通道之间的卷积被定义为:

Convolution of image I with kernel K

另一方面,任意大小的图像和具有大小为(k1,k2)的核 K 的 C 个通道之间的互相关由下式定义:

Cross-correlation of image I with kernel K

明眼人会注意到,图像与核的卷积相当于图像与该核的互相关,但翻转了 180 °:

Kernel flip

因此,我们可以直接将翻转的内核视为我们想要用于卷积的内核,并且 让我们的层仅计算互相关

在本帖中,我们将把元素 X 视为 3 维或 4 维数组:

在 X 有三维的情况下,f 不会出现在符号上。就是这样!我们现在可以讨论卷积层本身。

卷积层

该层将高度 n_H_prev、宽度 n_W_prev 和 C 通道的前一层 A_prev 的输出转换成高度 n_H、宽度 n_W 和 F 通道的变量 Z。

Convolutional layer: input and output shapes

该层的参数是:

  • F 核(或过滤器)由它们的权重 w_{i,j,c}^f 和偏差 b^f 定义
  • 上面解释的内核大小 (k1,k2)
  • 一个激活功能
  • 步长 (s1,s2),其定义了在输入图像上应用内核的步骤
  • p1,p2 定义了我们在 A_prev 的边界上添加的零的数量

正向传播

卷积层转发填充的输入;因此,我们考虑将 A_prev_pad 用于卷积。

正向传播的方程式是:

Forward propagation equations

反向传播

反向传播有三个目标:

  • 将错误从一层传播到上一层
  • 计算误差相对于权重的导数
  • 计算误差相对于偏差的导数

注释

为了便于表示,我们定义如下:

数学!

在实践中,我们通过总是知道 da_{i,j,f}或 dz_{i,j,f}来执行层的向后传递,并且我们假设对于这种情况我们知道 da_{i,j,f}。

dz_{i,j,f}的表达式由等式给出。[2]:

其中 g '是 g 的导数。

利用链式法则,我们可以计算 dw_{i,j,c}^f:

回想一下,dz_{m,n,k}仅与第 k 个滤波器相关联(由等式给出。[1]),fth 内核的权重只和 dz 的 fth 通道挂钩;

然后,我们可以用方程式得到 dz_{m,n,f}/dw_{i,j,c}^f。[1]:

情商的表达。[5]然后是:

可以注意到,这是 A_prev_pad 与内核 dZ 的互相关

对于偏置,遵循相同的程序:

因此:

最后要做的是误差的反向传播:找出 dA_prev 和 dZ 之间的关系。

记住我们在 dZ 和 dA_prev 的填充版本之间有关系(在等式中给出)。[1]),我们将考虑计算 da_prev_pad。

使用链式法则(再次!),我们有:

我们认为 dz_{m,n,f}是和的第一项,这很好。让我们关注第二个术语:

当且仅当 m'+m=i,n'+n=j,c'=c 时,它不等于零。

因此:

所以,

我们注意到等式。[9]描述了一种卷积,其中层的滤波器被认为是图像,dZ 是内核。

我们最终通过选择 da_prev_pad_{i+p1,j+p2,c}获得 da_prev_{i,j,c},p1 和 p2 是该层的第一和第二维周围的填充值。

结论

在本文中,您了解了如何计算具有任意数量滤波器和输入通道的卷积层的前向和后向传播。

正向传递由两个等式给出:

Forward pass equations

要计算卷积层的反向传播,只需实现以下四个等式:

Backward pass equations

其他细节可以在本文中讨论(例如,如何计算 n_H 和 n_W 的值),但许多文章已经讨论了这些要点,因此我鼓励您在开始实现自己的卷积层之前阅读它们。

来源

[1] 杜默林诉&维辛,F. (2016)。深度学习卷积算法指南(cite arxiv:1603.07285)

[2]CMSC 426 相关与卷积课堂笔记,2005 秋季戴维·雅各布

[3] 卷积神经网络 UFLDL 教程

[4] 卷积神经网络中的反向传播,Jefkine,2016 年 9 月 5 日

祝你实现这些算法好运!

干杯,

特里斯坦

前进模式自动微分和双数

原文:https://towardsdatascience.com/forward-mode-automatic-differentiation-dual-numbers-8f47351064bf?source=collection_archive---------0-----------------------

自动微分(AD)是深度学习成功故事背后的驱动力之一。它允许我们有效地计算我们最喜欢的合成函数的梯度值。TensorFlow、PyTorch 以及所有前辈都利用 AD。按照随机*似技术,如 SGD(及其所有变体),这些梯度细化了我们最喜欢的网络架构的参数。

许多人(直到最*包括我自己)认为反向传播、链式法则和自动微分是同义词。但事实并非如此。为了成为这门手艺的真正大师,我们必须找出原因。🔥

TL;博士 : 我们讨论区分计算机程序的不同方法。更具体地说,我们比较正向模式和反向模式(反向模式)的自动微分。最后,我们为一个简单的逻辑回归问题实现了具有双数的正向模式 AD。在 这里可以找到普通数字代码

计算计算机程序的导数

术语“可微分编程”可能有点令人难以置信。一般来说,程序与分析或可微函数没有任何关系。除了计算数学函数的计算机函数。假设你面临的任务是拟合一些逻辑回归模型。一种方法是在给定一些真实标注数据的情况下,迭代最小化逻辑输出函数的二进制交叉熵损失:

解析表达式可以很容易地翻译成一些 Python 代码:

该函数根据固定真实标签(y_true)和预测/拟合标签概率(y_pred)计算数值。在我们的例子中,y_pred相当于 sigmoid 压缩输出,也是β的函数。为了找到最佳拟合系数,我们需要遵循使损失函数最小化的最陡下降方向(即梯度)。为此,我们可以使用一套差异化技术:

  1. 手动鉴别(🙌众所周知,手动微分需要在一张纸上算出导数。然后,导数可以用代码实现。这样做容易出现“数学”错误,而且(至少对我来说)相当耗时。祝你好运,为一张深网解决问题。
  2. 数值微分(💻):我们可以简单地尝试使用两个极小的不同输入来*似梯度,而不是用链和商规则来弄脏您的手。这样我们就接*了导数的正式定义。这带来了两个主要缺点:它需要多个函数求值(每个输入维度至少两次),并且容易出现舍入误差和截断误差(输入永远不会完全相同)。好的一面是——它非常容易实现。
  3. 符号微分 (🈂):符号方法应用符合微分规则的变换,以获得导数的表达式。这是在 Mathematica 等软件中实现的,并且依赖于一些严肃的代数运算。组合函数有导致导数的符号表示过于复杂的风险。这就是通常所说的“表情肿胀”。最终,这会导致任意昂贵的梯度评估。
  4. 自动微分(🔁):ad 没有膨胀到无穷大,而是简化了每个可能时间点的导数表达式。例如每次手术后!所有的数学都可以被看作是一组有限的基本运算(加法、乘法、求幂等)的组合。).对于这样的运算,我们已经知道了导数的函数形式。通过链式法则的优点,我们可以将这些初等导数结合起来,并以内存存储为代价降低表达式的复杂性。

AD 的核心融合了数字世界和符号世界的精华。它在符号微分的基本规则集的帮助下计算导数的值。为了克服膨胀,符号表达在每个阶段都被简化了。简单地通过用先前计算的结果(或简单地输入数据)进行数值评估。因此,它不提供导数本身的解析表达式。相反,它迭代地评估给定数据的梯度。简单来说:f'(2) ≠ f'(x)。

让我们看看这如何应用于我们的逻辑回归问题&将逐步输出定义为 a(h) = σ(h)和 h(X,β) = X β。然后,我们可以将感兴趣的梯度改写为:

上面的表达式是手工推导的。乍一看,这可能不像是一种简化。但是我们现在可以观察到一个更普遍的原理:梯度可以分解成各个变换路径的梯度分量:

  1. 预激活 h(X,β)及其梯度∇h(X,β)写参数β。
  2. 激活 a(h)和它们的梯度∇a(h)写预激活 h
  3. 类问题的对数 log a(h)和梯度对角矩阵∇log a(h)写激活 a

对于每个部分评估 h(X,β),a(h),log a(h ),我们可以很容易地计算对它们各自的输入β,h,a 的灵敏度,并获得它们的导数。最终,真实概率向量 p 提供了缩放梯度的误差信号。

AD:前进与后退模式

我们可以继续进行自动以两种不同的方式计算梯度的各个分量:

  1. 正向累计模式(⏩):简单提出模式将莱布尼茨的链式法则应用于一个正向原始迹中的每个基本操作。由此,获得了导数轨迹。在每一个阶段,我们都以“步伐一致”的方式评估操作符及其梯度!
  • 原始迹:h(X,β) → a(h) → log a(h)
  • 导数迹:∇h(X,β) → ∇a(h) → ∇log a(h)
  • 同步评估+衍生工具:

最后,总梯度∇l然后通过将单个片段相乘并使用 p 重新缩放来获得

  1. 反向累计模式(⏪):另一方面,反向模式不同时计算导数,而是需要两个单独的阶段。在正向阶段中,评估所有中间变量,并将它们的值存储在存储器中。在接下来的反向阶段中,我们再次借助链式法则传播回导数/邻接。反向模式 AD 就是我们通常所说的深度学习中的反向传播 (Rumelhart 等人,1988)。
  • 正向相位:h(X,β) → a(h) → log a(h)
  • 倒相:∇log a(h) → ∇a(h) → ∇h(X,β)。那么我们如何知道用哪种方式来发送我们的梯度呢?我们需要一个簿记方案,该方案由预先指定的计算图提供,该图指定了操作的流程。

比较工作模式时,有两个主要考虑因素:

  1. 内存存储与计算时间:正向模式要求我们存储导数,而反向模式只要求存储激活。正向模式 AD 在变量求值的同时计算导数,而反向模式 AD 在单独的反向阶段计算导数。
  2. 输入与输出维度:给定一个函数 f,我们可以根据要处理的维度区分两种状态:
  • n <
  • n > >m:输入尺寸大于输出尺寸。这是经典的深度学习设置。我们从前向传递获得标量损失评估,并传播回相当高维的输入。→反向模式在计算上比正向模式便宜。

我们感兴趣的是将计算从几个单元推向多个单元。事情并不一定如此明确,因为人们可以相当容易地对正向模式计算进行矢量化。因此,不需要单独的向前传球。我假设反向模式在 DL 中的优势主要来自于减少的内存需求。

双数的作用

于是这里就来了一个简化正向模式 AD 的代数魔术:可以证明正向模式 AD 等价于用对偶数求感兴趣的函数。

我写这篇博文的动机源于我对这种等价性的理解不满意。所以我不得不深入调查。现在让我试着解释一下,使用任何数值计算的对偶部分来计算其各自的参数梯度是多么的优雅。那么什么是双数呢?我们可以将输入变量 x 分解成实数部分和对偶部分:

用 v,v̇实数,ϵ ≠ 0,ϵ = 0。基于这个简单的定义,下面的基本算术性质的结果:

此外,可以用代数方法推导出以下公式:

哇!通过评估 f(x)的对偶形式,并设置 v̇ = 1,我们能够恢复函数值 f(v)以及其评估的导数 f'(v),其形式为ϵ前面的系数!最后,链式法则顺利地转化为双重设置:

这意味着,我们可以通过简单地将导数相乘,轻松地在计算层中传播梯度。为了实现对偶数,我们只需要一个单独的存储系统来跟踪 x = (v,coeff-在 v̇前面)并将各自的导数计算应用到 x 的对偶部分。太棒了代数!

对于多元函数,事情变得有点棘手。想象两个输入:

相对于 x 的偏导数通过设置 v=1 和 u=0 来计算。对于 y,我们必须翻转两位。为了并行执行,并防止多次向前传递,我们可以对事物进行矢量化,并保留一个对角矩阵:

每行代表一个偏导数。所有上述规则很容易转化为多元的情况。

因此,如何看待ϵ仍有待讨论?我从这篇博文中得到的两个直觉如下:

  1. ϵ可以被认为是无穷小数的一种形式。当*方这么小的数时,它就变得不可表示了。直观上,这类似于数值微分步长。
  2. 另一种可能的方式是把ϵ想象成一个矩阵:

计算ϵ x ϵ然后产生所需的零矩阵。通过限制 i = -1 虚数,帮助我们计算旋转。另一方面,双数限制ϵ = 0,并允许有效和精确的导数计算。让我们看看如何将它转化为逻辑回归示例的代码。

让我们把它编码起来!

首先,我们需要一些合成数据来解决二元分类问题。下面的类对象生成系数、高斯噪声和特征。然后,我们取点积并对变换后的特征进行阈值处理,以获得二值标签。此外,还有一些小的实用程序可以对成批数据进行采样,并在不同的时期之间对数据进行混洗。都是很标准的东西。没有双重的。

Let’s generate some data!

接下来我们来定义一下事物的“双肉”。我们需要确保所有的基本运算(加法、乘法、sigmoid 激活以及梯度所需的对数)都作用于向量的对偶表示的实数部分和对偶部分(这需要梯度)。因此,我们需要一个双重包装器来重载/重定义操作符。

Let’s set up some dual number operations

sigmoid 函数的对偶版本将标准σ应用于实部,并使用其计算的导数来改变 n x d 维对偶矩阵的数值。因为σ'(h) = σ(h) (1 — σ)应用于向量 h 的每个元素,因此,对偶部分的整体变化由下式给出:

这又导致大小为 n×d 的雅可比矩阵,同样的概念也适用于对数运算符。现在,我们已经为我们的对偶数运算重新定义了算术设置,让我们研究如何获得我们的逻辑回归预测和相应的二元交叉熵损失:

A simple ‘forward’ pass and dual loss function evaluation

最后,让我们把所有的东西放在一起,形成一个最终的训练循环。我们生成二进制数据并初始化一些占位符列表来存储我们的中间结果。之后,我们计算 Sklearn 解决方案系数来衡量我们的差距。然后,我们可以简单地循环单个批次。我们将系数初始化为对偶张量、样本批次,将梯度系数/对角矩阵设置回它们的偏导数初始化。我们获得预测和损失。损失评估的对偶对应于兴趣梯度∇ L 。SGD 更新然后简单地采用 dual 并在最陡下降方向执行一个步骤。

让我们训练一个简单的例子,看看指标:

Run the training loop!

这个理论的结果是多么令人惊讶。损失随着处理的批次数量而减少。这些系数收敛于 Sklearn 解和训练精度。A 队的汉尼拔会说“我喜欢有计划的时候。”

高效计算 Hessian 矢量积

我们已经讨论了为什么反向传播和反向模式 AD 对于标准深度学习应用更有效。前向模式 AD 仍然有用的一个原因是它在计算 Hessian-vector product,Hv 时的实用性。我们可以使用反向对正向配置来组合正向和反向模式,以计算二阶 Hessian。更具体地说,给定一个输入为 x 的函数 f,我们可以简单地同时使用这两种模式:

  1. 正向模式:通过设置ẋ = v 来计算梯度矢量积∇ f v
  2. 反向模式:取结果并对其应用反向传播:∇ fv = Hv

很聪明,对吧?然后,Hessian 可用于进行高阶优化,这也考虑了损失面的*似曲率。总之,对于前向模式的广告,还是有一些喜爱的。

我们已经看到了前向模式自动微分的能力和局限性。它允许我们同时计算一个函数及其导数。因此,人们能够克服反向模式 AD(又名反向传播)的两阶段原则。这是以存储所有中间节点的双重表示为代价的。此外,单独向后传递的计算工作被转移到向前传递。我们看到了对偶数神奇的代数性质是如何让我们高效而精确地做到这一点的。

结论

总而言之,我发现从零开始实现东西非常令人满意,也非常有洞察力。我对当前的 DL 库及其挑战有不同的看法(例如,静态与动态计算图,存储与计算)。我建议感兴趣的读者仔细看看 Baydin 等人(2018 年)的一项伟大调查。这篇文章是我的起点,提供了一个可读性很强的概述!你也可以在这里找到的所有代码。

  1. baydin a . g . b . a . pearl mutter a . a . Radul 和 J. M. Siskind。(2018):《机器学习中的自动微分:一项调查》,机器学习研究杂志,18。
  2. Rumelhart,D. E .,G. E. Hinton,R. J. Williams 等人。(1988):“通过反向传播错误学习表征”,认知建模,5,1。

罗伯特 是柏林工业大学的一名博士生。本帖原载于 2019 年 9 月 1 日https://roberttlange . github . io

神经网络中的前向传播—简化的数学和代码版本

原文:https://towardsdatascience.com/forward-propagation-in-neural-networks-simplified-math-and-code-version-bbcfef6f9250?source=collection_archive---------3-----------------------

我们都知道从最*十年深度学习已经成为最广泛接受的新兴技术之一。这是由于其功能的代表性。

根据 通用逼*定理 ,一个经过良好引导和工程化的深度神经网络可以逼*变量之间任意复杂和连续的关系。其实深度学习成功的背后还有其他几个原因。我不打算在这里讨论这些可能的原因。

这篇文章的目的是用更简单的方式解释 正向传播 (学习阶段的核心过程之一)。

学习算法/模型在正向传播反向传播的帮助下找出参数(权重和偏差)。**

正向传播

顾名思义,输入数据是通过网络正向输入的。每个隐藏层接受输入数据,按照激活函数对其进行处理,并传递给后续层。

为什么选择前馈网络?

为了产生一些输出,输入数据应该只向前馈送。在生成输出的过程中,数据不应反向流动,否则会形成一个循环,永远无法生成输出。这种网络结构被称为 前馈网络前馈网络有助于正向传播

在隐藏层或输出层中的每个神经元处,处理分两步进行:

  1. 预激活:是输入的加权和,即权重* w.r.t 对可用输入的线性变换。基于这个聚集总和激活函数*,神经元决定是否进一步传递该信息。**
  2. 激活:计算出的输入加权和传递给激活函数。激活函数是给网络增加非线性的数学函数。有四种常用和流行的激活函数— sigmoid、双曲正切(tanh)、ReLU 和 Softmax。

现在让我们借助一个例子来理解正向传播。考虑一个非线性可分离数据,其形式为遵循漩涡模式的两个数据点的卫星。这个生成的数据有两个不同的类。

可以使用sklearn.datasets模块的make_moons()功能生成数据。要生成的样本总数和关于月亮形状的噪声可以使用函数参数进行调整。

*import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from sklearn.datasets import make_moonsnp.random.seed(0)data, labels = make_moons(n_samples=200,noise = 0.04,random_state=0)
print(data.shape, labels.shape)color_map = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","yellow"])
plt.scatter(data[:,0], data[:,1], c=labels, cmap=my_cmap)
plt.show()*

dataset visualization

这里,200 个样本用于生成数据,它有两个类,以红色和绿色显示。

现在,让我们看看神经网络结构来预测这个二元分类问题的类。这里,我将使用一个具有两个神经元的隐藏层,一个具有单个神经元的输出层sigmoid 激活功能。

正向传播期间,在隐藏和输出层的每个节点发生预激活激活。例如在隐藏层的第一个节点,首先计算 a1 ( 预激活),然后计算 h1 ( 激活)。

a1 是输入的加权和。这里,权重是随机生成的。

*a1= w1 * x1+w2 * x2+B1 = 1.76 * 0.88+0.40 (-0.49)+0 = 1.37 *似值 h1 是应用于 a1 的激活函数值。

类似地

*a2= w3 * x1+w4 * x2+B2 = 0.97 * 0.88+2.24 (0.49)+0 =-2.29 *似值和

对于第一个隐藏层之后的任何层,输入是从前一层输出的。

a3= w5 * h1+w6 * H2+B3 = 1.86 * 0.8+(-0.97) 0.44+0 = 1.1 *似值*

所以有 74%的几率第一次观察属于第一类。像这样对所有其他的观察预测输出可以计算出来。

下图显示了第一次观测的数据从输入图层到输出图层的转换。

Data transformation from the input layer to the output layer

现在让我们看看上面的神经网络在 Jupyter 笔记本中的实现。事实上,在构建 Tensorflow、Keras、PyTorch 等深度神经网络框架的同时。被使用。

*from sklearn.model_selection import train_test_split#Splitting the data into training and testing data
X_train, X_val, Y_train, Y_val = train_test_split(data, labels, stratify=labels, random_state=0)
print(X_train.shape, X_val.shape)* 

这里,按照默认的 75:25 的分割比,150 个观察值用于训练目的,50 个用于测试目的。

现在让我们为正向传播定义一个类,其中权重被随机初始化。

*class FeedForwardNetwork:

 def __init__(self):
     np.random.seed(0)
     self.w1 = np.random.randn()
     self.w2 = np.random.randn()
     self.w3 = np.random.randn()
     self.w4 = np.random.randn()
     self.w5 = np.random.randn()
     self.w6 = np.random.randn()
     self.b1 = 0
     self.b2 = 0
     self.b3 = 0

 def sigmoid(self, x):
     return 1.0/(1.0 + np.exp(-x))

 def forward_pass(self, x):
     self.x1, self.x2 = x
     self.a1 = self.w1*self.x1 + self.w2*self.x2 + self.b1
     self.h1 = self.sigmoid(self.a1)
     self.a2 = self.w3*self.x1 + self.w4*self.x2 + self.b2
     self.h2 = self.sigmoid(self.a2)
     self.a3 = self.w5*self.h1 + self.w6*self.h2 + self.b3
     self.h3 = self.sigmoid(self.a3)
     forward_matrix = np.array([[0,0,0,0,self.h3,0,0,0], 
                      [0,0,(self.w5*self.h1),        (self.w6*self.h2),self.b3,self.a3,0,0],
                      [0,0,0,self.h1,0,0,0,self.h2],
                      [(self.w1*self.x1), (self.w2*self.x2),         self.b1, self.a1,(self.w3*self.x1),(self.w4*self.x2), self.b2,  self.a2]])
     forward_matrices.append(forward_matrix)
     return self.h3*

这里,forward_pass()函数计算给定输入观测值的输出值。forward_matrix 是一个 2d 数组,用于存储每次观察的 a1、h1、a2、h2、a3、h3 等的值。使用它的原因只是为了用 GIF 图像来可视化这些值的转换。forward_matrix 的条目如下所示

forward_matrix

*forward_matrices = []
ffn = FeedForwardNetwork()
for x in X_train:
   ffn.forward_pass(x)*

forward_matrices 是所有观察值的列表forward_matrix

*import seaborn as sns
import imageio
from IPython.display import HTMLdef plot_heat_map(observation):
    fig = plt.figure(figsize=(10, 1))
    sns.heatmap(forward_matrices[observation], annot=True,     cmap=my_cmap, vmin=-3, vmax=3)
    plt.title(“Observation “+str(observation)) fig.canvas.draw()
    image = np.frombuffer(fig.canvas.tostring_rgb(), dtype=’uint8')
    image = image.reshape(fig.canvas.get_width_height()[::-1] +             (3,)) return imageimageio.mimsave(‘./forwardpropagation_viz.gif’, [plot_heat_map(i) for i in range(0,len(forward_matrices),len(forward_matrices)//15)], fps=1)*

plot_heat_map()功能创建一个热图,以可视化每次观察的forward_matrix 值。这些热图存储在forwardpropagation_viz.gif图像中。这里,总共为 15 个不同的观察创建了 15 个不同的热图。

forward propagation for 15 different observations

代码优化

而不是使用不同的变量,如 w1、w2…w6、a1、a2、h1、h2 等。单独地,矢量化矩阵可以分别用于权重、预激活(a)和激活(h)。矢量化能够更高效、更快速地执行代码。它的语法也很容易理解和学习。

*class FeedForwardNetwork_Vectorised:

 def __init__(self):
    np.random.seed(0)
    self.W1 = np.random.randn(2,2)
    self.W2 = np.random.randn(2,1)
    self.B1 = np.zeros((1,2))
    self.B2 = np.zeros((1,1))

 def sigmoid(self, X):
    return 1.0/(1.0 + np.exp(-X))

 def forward_pass(self,X):
    self.A1 = np.matmul(X,self.W1) + self.B1 
    self.H1 = self.sigmoid(self.A1) 
    self.A2 = np.matmul(self.H1, self.W2) + self.B2
    self.H2 = self.sigmoid(self.A2) 
    return self.H2ffn_v = FeedForwardNetwork_Vectorised()
ffn_v.forward_pass(X_train)*

结论

这是从我的角度讲的 正向传播 ,我希望我能够解释正向传播中涉及的直觉和步骤。如果你有兴趣学习或探索更多关于神经网络的知识,请参考我的其他关于神经网络的博客文章。链接如下

https://www . analyticsvidhya . com/blog/2020/10/a-comprehensive-guide-to-feature-selection-using-wrapper-methods-in-python/

为什么更好的权重初始化在神经网络中很重要?

分析神经网络中不同类型的激活函数——选择哪一种?

为什么梯度下降还不够:神经网络优化算法综合介绍

人工智能的基础

原文:https://towardsdatascience.com/foundations-of-ai-b11d6ad7ce6f?source=collection_archive---------4-----------------------

理解人工智能的直观框架

Photo by Daniel McCullough on Unsplash

很少有技术像人工智能一样抓住了人类的想象力。自古以来,智能机器人和人造生物的故事就充斥着我们的神话和传说,当我们的祖先认为自主机器的存在时,引发了兴奋和恐惧。这些神话继续影响着围绕人工智能的叙事,尽管我们比以往任何时候都更接*于开发人工通用智能,但鉴于今天充斥着流行语的媒体,很难区分事实和虚构。

尽管某些用例无疑被夸大了,但人工智能有潜力改变我们工作、娱乐和生活的方方面面。在本帖中,我们将通过以下方式为理解这项技术奠定基础:

  • 定义人工智能并描述它如何影响我们快速变化的世界
  • 将人工智能领域简化为五个核心研究领域
  • 用轶事和例子让每个研究领域变得生动

第 1 部分:定义和动机

人工智能是我们通常归因于人类思维和理性的活动的自动化,例如解决问题、决策和学习。人工智能生活在许多经典学科的交叉地带,包括哲学、神经科学、行为经济学、计算机科学和机械工程。这些跨学科的根源有助于解释为什么人工智能抓住了我们的想象力:这个新兴的研究领域为所有兴趣和背景的人提供了一点东西。随着我们对人工智能是什么以及它如何工作的理解不断发展,我们同时在学术界最具挑战性的研究问题上取得了进展:

Source: Artificial Intelligence: A Modern Approach (2nd Edition)

业务影响

人工智能肯定会影响你未来十年的职业道路。尽管大多数行业仍处于概念验证(POC)开发的早期阶段,但许多早期采用者已经开始享受他们的劳动成果。在一项研究中,研究人员发现,主动采用人工智能技术的 F500 公司的自我报告利润率比竞争对手高 3-15%。这些早期的成功信号引发了一波投资浪潮,刺激了风投和公司的发展。各部门每年都要花费数百亿美元来开发和扩展新的人工智能能力。这笔资金大大增加了对数据科学家和 ML 工程师的需求,催生了新的教育模式(例如 MOOCs、bootcamps),通过加快人工智能的采用速度来支持这种良性循环。无论你在我们的经济中扮演什么角色,你可能已经开始注意到这一波浪潮的影响:

Sources: McKinsey Global Institute, Executive Office Report on AI, IBM Analytics Report, Venture Scanner

以适度的怀疑态度对待融资数据总是明智的,而且不清楚这些趋势是否会在熊市中持续。尽管如此,这些趋势背后的势头表明,人工智能将对商业界产生持久的影响。

社会影响

在办公室之外,AI 也将对我们的社会产生深远的影响。虽然人工智能有潜力以我们尚未发现的方式加快和改善我们的日常生活,但它也可能很容易被误用和滥用。几个有代表性的例子包括:

“人工超级智能”(在研究界被称为人工通用智能,或 AGI)的概念尤其具有争议性。尽管我们距离开发出像终结者或玛奇纳那样的自主智能体还有几十年的时间,但许多思想领袖已经开始讨论超人人工智能带来的生存威胁。在一个角落里,斯坦福大学教授兼 deeplearning.ai 首席执行官吴恩达对人工智能将在社会中扮演的角色持乐观态度:

AI 是新电 。就像 100 年前电 改变了一个又一个产业 ,AI 现在也会这样做。”

——吴恩达

在另一篇文章中,特斯拉和 OpenAI 首席执行官埃隆·马斯克主张对人工智能开发采取更加保守的方法:

“如果让我猜我们的 最大的生存威胁 是什么,大概就是【AI】…有了人工智能,我们就是 召唤恶魔 。”

——埃隆马斯克

专家们对我们何时能最终实现 AGI 有不同意见,但是,正如我们很快会说明的,在过去的几年里,我们已经朝着这个目标取得了重大进展。

第 2 部分:理解人工智能

在他们 1995 年的经典人工智能:一种现代方法中,伯克利的 Stuart J. Russell 和谷歌的 Peter Norvig 将人工智能分为五个不同的研究领域,这些领域源于总体图灵测试:

  • 机器学习
  • 专家系统
  • 计算机视觉
  • 自然语言处理
  • 机器人

虽然这五个学科之间的界限已经开始变得模糊,因为我们已经朝着 AGI 取得了进展,但这个框架是理解人工智能的一个有用的起点。在第二部分,我们将提供这五个学科的例子和最新趋势。

机器学习

机器学习(ML)是一门让机器在没有人类干预的情况下做出决策的科学。这个子学科形成了人工智能的主干,使计算机能够使用多维数组学习和解释图像、声音和结构化数据中的模式。ML 进一步细分为四种学习类型:

  • 监督学习:给定一系列特征(例如,一年中的星期、价格等。)和一个带标签的输出变量(例如,销售),在给定一些新的输入数组的情况下,预测标签变量的最佳可能估计值。
  • 无监督学习:给定一系列特征(例如,人口统计信息、邮政编码等。),揭示并可视化阵列中隐藏的关系和异常。
  • 半监督:给定一组特征和有限数量的一些标签输出变量,预测缺失标签变量的最佳估计值。
  • 强化学习:给定某个目标,根据某个用户定义的效用函数,训练一个人工智能体,使其效用最大化。

监督学习是当今商业世界中最常用的 ML 形式,但随着我们不断发现不太传统的学习方法的新用例,这种*衡可能会发生变化。每种学习类型的示例如下:

机器学习要感谢过去几年中许多高调的创新,但它比通常认为的更难做到正确。如果没有观察到统计最佳实践,ML 模型将会过度拟合先前观察到的数据点,并将业务用户引入歧途。我们将在以后的讨论中更深入地讨论最后一点。

专家系统

专家系统是一个人工代理,它 利用预先编程的知识来提供建议或做出决策。最简单的形式,我们可以把一个 ES 想象成一个复杂的决策树或者嵌套的 if-then 逻辑:如果 xyw 发生,我们指示计算机做 z 。尽管专家系统不像机器学习那样被大肆宣传,但是有很多原因可以解释为什么我们更喜欢专家系统而不是机器学习:

  • 专家系统可以利用通过反复试验发现的人类洞察力
  • 专家系统更可预测并且在面对以前看不到的输入时不太可能犯极端错误
  • 专家系统在历史上更快更容易实现,尽管 ML 在最*几年变得更容易使用

Google’s Nest thermometer

专家系统是最普遍的人工智能类型,通常与人工智能结合在一起,以帮助降低错误预测的负面风险。谷歌的 Nest 家庭自动化技术是专家系统发挥作用的最好例子。随着时间的推移,用户将他们的偏好编程到 Nest 中,使系统能够自动将房屋温度调节到所需的水*,并减少供暖费用。使用 ML 来预测所需温度可能会导致设置和能源成本的大幅波动,因此用户定义的逻辑对于稳定这些预测至关重要。

计算机视觉

计算机视觉(CV)是对图像或视频的自动提取、分析和解释。CV 将照片和视频转换为数字数组,使 ML 算法能够根据用户定义的输入进行推断,进行预测,甚至生成新的图像。

Example of an image being converted to an array (source)

CV 的潜在用途已经被研究了几十年,但是 CV 直到最*才成为可能,这要归功于三项创新:

  • 更高效的算法:深度学习(具体来说是卷积神经网络)显著降低了 CV 任务的内存占用和计算运行时间。
  • 更好的计算资源 : GPU 的改进、分布式架构(例如 Spark)以及廉价云计算资源的可用性使得运行内存密集型 CV 算法比以往任何时候都更便宜。
  • 用于训练的图像的可用性:社交媒体*台、社区论坛和数码/移动相机的激增极大地增加了可用于训练 CV 算法的公开图像的数量。

这三项创新为新的 CV 用例打开了闸门,包括自动驾驶汽车和自动化零售商(如 Amazon Go)。随着相机、激光雷达和其他空间传感器变得越来越便宜,我们将很快找到使用 CV 来缓解许多最低效过程的方法。

自然语言处理

自然语言处理(NLP)是对人类语言的自动提取、分析和生成。NLP 算法以各种方式解析句子(例如,按单词拆分、按字母拆分、从左到右和从右到左阅读等)。)来自动推断作者的意思和意图。NLP 的各种用例包括:

  • 命名实体识别和会议决议
  • 词性标注
  • 阅读理解和问题回答
  • 机器翻译
  • 文本摘要和主题建模
  • 拼写检查和自动完成

像 CV 一样,NLP 在过去十年里取得了很大进展,这要归功于深度学习的创新,这些创新使得在人类语言上训练 ML 模型变得更快更容易。过去,工程师会花数小时检查、过滤和转换文本,以避免计算瓶颈。今天,像 fast.ai 的 NLP 库这样的开箱即用的解决方案可以粉碎阅读理解准确性记录,而不需要时间密集型的预处理。

How Alexa and Siri interpret your commands (source)

Siri 和 Alexa 是自然语言处理在实际应用中的很好的例子:通过收听“唤醒词”,这些工具允许你播放音乐,搜索网络,创建待办事项列表,以及控制流行的智能家居产品——所有这些都是在你的智能手机留在口袋里的时候。这些虚拟助手将随着时间的推移不断改进,因为它们从现有用户那里收集数据,释放新的用例,并与现代企业集成。

机器人学

机器人学是设计、建造、操作和应用机器人来解决人类问题的科学。机器人有成千上万种形状和大小,因此很难确定这个术语的准确含义。工业机器人的先驱约瑟夫·恩格尔伯格说得好:

*“我无法定义机器人,但我看到一个就知道一个。”

  • 约瑟夫·恩格尔伯格*

Boston Dynamic’s Atlas

机器人研究领域在过去十年中以极快的速度发展,使得新的设计和用例似乎直接来自科幻小说。私营制造商继续在各自的领域推进机器人技术的发展:

  • 波士顿动力公司是人形机器人领域的早期创新者,它继续向模拟人类运动靠拢。
  • DJI 专注于消费级无人机,让普通人比以往任何时候都更容易飞上天。
  • 亚马逊机器人位于亚马逊物流战略的核心,每年为这家零售巨头节省数十亿美元。

大多数机器人依靠专家系统来完成他们的目标,但是通过将机器学习、计算机视觉和自然语言处理集成到他们的操作系统中,未来的机器人将变得更加有用。

结论:通往 AGI 的道路

Russell 和 Norvig 的框架为思考人工智能提供了一个有用的结构,但这五个类别并不意味着相互排斥;过去十年中最激动人心的创新都发生在它们的交叉点上。随着时间的推移,这种学科融合只会变得更加明显:送货无人机、自动驾驶汽车和人工通用智能如果要取得成功,就必须紧密整合所有五个学科。尽管如此,每一个复杂的问题在解决之前都必须分解成其核心组成部分,这五个学科框架为理解人工智能提供了一个基本的心智模型。

当你运用这些新发现的知识时,有一些指导原则值得带回你的团队:

  • 持怀疑态度:人工智能是五个深入复杂的研究领域的总称,同时拥有这五个学科的技术专长是极其罕见的。询问潜在的候选人他们以前的经历,并根据他们的专长做出自己的推断。
  • 建立一个多样化的团队:因为最有价值的人工智能用例位于这些学科的交叉点上,如果你的团队想要成功,招募具有不同背景和技能的队友是很重要的。招聘各种职位(例如,数据科学家、UX 设计师、ML 工程师)是一个开始,但请有 T 形经历的候选人找出可以身兼数职的人。
  • 拥有你的专长:这五个学科中的一个领域的创新往往会给其他四个领域带来新的想法,这意味着所有五个学科领域都处于不断变化的状态。不要试图将人工智能社区作为一个整体来关注,而是关注你认为最适合你的业务和兴趣的 1-2 个学科。这样做,你就能发现机会,将最新最好的技术应用到对你最重要的问题上。

ML 基础:参数化函数

原文:https://towardsdatascience.com/foundations-of-ml-parameterized-functions-d2951a62272e?source=collection_archive---------12-----------------------

对参数化函数的软介绍,这是机器学习和统计学中的一个基础话题,通过小的编程例子来解释。

本文的目标

在这篇文章的结尾,我希望下面的句子有意义:

我最喜欢的参数化函数的可视化来自于高阶函数的几何解释。

为了实现这个目标,我将解释参数化函数高阶函数功能几何。如果你已经知道这些并且上面的句子已经有意义,这篇文章可能不适合你。如果以上任何(或全部)听起来很吓人,希望我能帮上忙!

什么是函数?

这听起来很基本,但我想从同一页开始,所以请允许我简单地解释一下我说的功能这个词的意思。

在编程中,函数只是一个接受一些参数并返回一些东西的过程。示例:

在数学中,我们对函数的定义更严格一些。所以让我们在定义中增加一个限制。

对于任何给定的输入x,只能有一个输出y

用反例的方式解释:

为什么这不是一个函数?因为如果我连续两次通过x = 0,我将不会得到相同的答案。也就是说,对于给定的输入(x = 0),我得到了不同的输出(x + random())。

什么是高阶函数?

高阶函数还是函数。它接受一些参数并返回一个东西。在这种情况下,它返回的“东西”也是函数!示例:

事情变得有点复杂;让我解释一下。每次我们调用我们的高阶函数buildAdder,我们都会基于参数a创建一个新的函数。

在本例中,addOne仍然是一个接受一个数字并返回该数字加 1 的函数。但是由于我们的高阶函数,我们可以通过向buildAdder传递不同的参数来生成许多这样的加法函数。

什么是参数化函数?

在最后一个例子中,addA是一个参数化函数!参数化函数是作用于某些参数的函数,但它的作用方式是基于外部常数的。例如,在addA的上下文(范围)中,a是外部设置的常量值。在addOne的情况下,a是不变的一个

这里的关键点是addA可以是许多不同函数中的一个(这里是无限个)。我们通过其参数a来确定我们正在处理的众多函数中的哪一个。

因为a的值决定了addA承担的精确功能,我们需要一些语言来讨论addA可以创建的所有可能功能的集合。为了具体说明这一点,我们来看一些例子:

函数的是一个参数化函数可以采用的所有函数的集合。在这个例子中,我们看到class1是包含每个整数值的函数的集合。我们可以更简洁地这样写:

第一类函数包含所有的addA,其中a是一个整数。下一个类包含所有的addA,其中a是一个实数。第三类包含所有的addA,其中a是一个正实数。

如果我们比较这些集合的大小,我们会发现class2class1大。我们之所以知道这一点,是因为实数比整数多,并且a的值与类中的函数有一对一的映射。

我们如何几何地看待参数化函数?

为了更容易形象化,让我们看一个也有两个参数的二元函数。我们可以把这两个变量当作一个数组变量,也可以把这两个变量独立处理;这在很大程度上是一种风格选择。下面是一个x的函数示例,其中x是一个包含两个元素的数组:

我们指向这个网格上的任何地方,都会产生一个新的函数。该函数将由其ab坐标定义,并且对于x的值表现不同。这种解释的一个有价值的用途是定义函数类的约束。例如,也许我们只想查看阴影区域中包含的函数。

那么这和机器学习有什么关系呢?

我们在机器学习中做的大量工作是寻找特定的函数。我们选择一个模型类(参数化的函数类)并优化它(为参数找到某个值)。

通过这个镜头来观察机器学习,很明显我们所做的就是在参数空间中搜索与我们的数据相匹配的函数!为了让这个说法更清楚,我们来想象一个例子。假设我被赋予了这个功能:

I am no artist..

如果我摆弄abc足够长的时间,我应该能够找到一条非常接*我得到的曲线。如何找到正确的abc?答案就在优化文献中,但那是另外一个故事了。现在,只要知道我们正在搜索这个类定义的所有可能函数的集合,直到我们找到一个看起来与我们的数据相似的函数。

在机器学习中,我们通常不会被告知用来生成我们的数据的函数类。相反,我们必须使用足够通用的函数类来模拟许多不同的函数。例如,函数类y = a*x + b可以模拟任何线,但是一条线绝对不足以*似生命的复杂函数。所以我们想得更大更深。这导致了最流行的函数类:神经网络。神经网络可以模拟任何函数!

神经网络的一个普遍紧张的事实是它们是通用函数逼*器。这意味着,给定足够多的隐藏节点,它们可以逼*任何函数。该函数的*似精度取决于网络中隐藏节点的数量。这意味着神经网络是一类足够通用的函数,可以模拟任意复杂的函数。然而,让他们这样做本身就是一门艺术!

自动化数据提取的四种基本方法

原文:https://towardsdatascience.com/four-basic-ways-to-automate-data-extraction-3151064dc110?source=collection_archive---------13-----------------------

1。从哪里获取数据?

做数据分析 的人都知道,如何获取数据是至关重要的一步。数据抽取是数据分析的基础。没有数据,分析就没有意义。有时,我们有多少数据源,我们有多少数据,以及数据质量如何将决定我们的输出会发生什么。

我们需要考虑到数据的趋势受到多个维度的影响。我们需要在保证数据质量的情况下,通过多源数据采集收集尽可能多的数据维度,这样才能获得高质量的数据分析结果。

那么,从数据收集的角度来看,数据来源是什么呢?我把它们分为以下四类。

1)开放数据源(政府、大学和企业)

2)爬虫抓取(web 和应用)

3)日志收集(前端捕获后端脚本)

4)传感器(图像、速度、热量)

这四种类型的数据源包括:开放数据源、爬虫抓取、日志收集和传感器。都有自己的特点。

开放数据源通常是特定于行业的数据库。比如美国人口普查局开放了美国人口信息、地区分布、教育等数据。除了政府,企业和高校也会开放相应的数据集。要知道很多研究都是基于开放数据源的,这一点很重要。你需要相同的数据集来比较算法的质量。

第三种数据源是日志采集,是
统计用户的操作。我们可以在前端跟踪事件,在后端收集脚本和
统计,分析网站的访问情况。

最后是传感器,它主要收集物理信息,如图像、视频或速度、热量、压力等。一个物体。由于本文的主要重点是数据提取,因此将不对该方法进行描述。

现在我们知道有四种类型的数据源,我们如何收集它们呢?

2.如何使用开放数据源?

下表显示了一些权威的开放数据源。

如果你在找某个领域的数据源,比如金融领域,可以看看政府、高校、企业是否有开放的数据源。

3.如何使用爬虫抓取数据?

爬虫抓取应该是最常见的方式,比如你想要的对餐厅的评价数据。当然这里一定要注意版权问题。而且很多网站也有反抓取机制。

最直接的方法就是用 Python 写爬虫代码,当然你需要学习 Python 的基本语法。另外 PHP 也可以写爬虫,但是不如 Python,尤其是多线程操作的时候。

在 Python 爬虫中,基本上要经历三个过程。

1)使用请求抓取内容。我们可以使用请求库来抓取网页信息。Requests 库可以说是 Python 爬虫的绝佳工具,就是 Python 的 HTTP 库。通过这个库抓取网页中的数据非常方便,可以节省我们很多时间。

2)使用 XPath 解析内容。 XPath 是 XML Path 的缩写。它是一种用于确定 XML 文档中某个部分的位置的语言,通常在开发中用作小型查询语言。XPath 可以通过元素和属性进行索引。

3)用熊猫保存你的数据。 Pandas 是一种先进的数据结构,使数据分析变得更加容易,我们可以使用 Pandas 来保存抓取的数据。最后,通过熊猫将其写入数据库,如 XLS 或 MySQL。

对于 Python 来说,请求、XPath 和 Pandas 是三个有用的工具。当然,还有很多其他工具可以编写 Python 爬虫,比如 Selenium、PhantomJS 或者 Puppteteer。

另外,我们也可以不用编程抓取网页信息。下面是三种常用的爬虫。

–import . io

最引人注目也是大家认为最好的功能叫做“Magic”,这个功能让用户只需进入一个网页就可以自动提取数据,无需任何其他设置。

–parse hub

ParseHub 是一个基于 web 的抓取客户端工具,支持 JavaScript 渲染、Ajax 抓取、cookies、会话等。该应用程序可以分析和检索网站上的数据,并将其转换成有意义的数据。它还可以使用机器学习技术来识别复杂的文档,并将它们导出到 JSON、CSV、Google Sheets 等。

–刮刀

Web Scraper 是一个 Chrome 扩展,已经有超过 20 万人安装了它。它支持点击式数据抓取,支持动态页面呈现,并针对 JavaScript、Ajax、下拉拖动和分页进行了优化,具有完整的选择器系统,并支持将数据导出到 CSV 和其他格式。此外,它还拥有自己的云刮刀,支持调度任务、API 管理和代理切换。

4.如何使用日志收集工具?

日志收集最大的作用就是通过分析用户访问情况来提升系统性能,从而增加系统负载。及时发现系统负载瓶颈,也可以方便技术人员根据实际用户访问情况对系统进行优化。

日志记录了用户访问网站的全过程:谁访问了网站,在什么时间,通过什么渠道(如搜索引擎、URL 输入),进行了什么操作;系统是否产生错误;甚至用户的 IP、HTTP 请求时间、用户代理等。

这里的日志收集可以分为两种形式。

1)通过网络服务器收集。比如 httpd、Nginx、Tomcat 都有自己的日志功能。同时,很多互联网公司都有自己的海量数据收集工具,多用于系统日志收集,如 Hadoop 的 Chukwa、Cloudera 的 Flume、脸书的 Scribe 等这些工具是分布式架构,可以满足每秒数百 MB 的日志数据收集和传输需求。

2)定制用户行为。比如用 JavaScript 代码监听用户行为,AJAX 异步请求后端日志等等。

5.什么是事件跟踪?

事件跟踪是日志收集的关键步骤。

事件跟踪就是收集相应的信息,在你设定的地点进行报告。比如一个页面的访问状态,包括用户信息、设备信息;或者用户在页面上的操作行为,包括停留时间的长短。每个事件跟踪就像一个照相机。它收集用户行为数据,并对数据进行多维度分析,能够真实还原用户使用场景和用户需求。

那么我们如何跟踪不同的事件呢?

事件跟踪就是在你需要统计的地方植入统计代码,当然植入代码可以自己写,也可以使用第三方统计工具。我谈到了“不要重复生产一个轮子”的原则。对于事件跟踪工具,市场已经相当成熟。我可以给你推荐一些谷歌分析、Talkingdata 等三方工具。都是用前端追踪的方式,然后在第三方工具里就能看到用户的行为数据。但是如果我们想看到更深层次的用户行为,我们需要定制事件跟踪设置。

综上所述,日志收集有助于我们了解用户的运营数据,适用于运维监控、安全审计、业务数据分析等场景。典型的 web 服务器有自己的日志功能,或者您可以使用 Flume 从不同的服务器集群收集、聚合和传输大量的日志数据。当然,我们也可以使用第三方统计工具或者自定义埋点来获取我们想要的统计数据。

结论

数据提取是数据分析的关键。我们喜欢用 Python 网络爬虫来解决问题。事实上,数据收集方法非常广泛。有时候可以直接使用公开的数据源,比如比特币的价格和交易数据。可以直接从 Kaggle 下载,不需要自己爬。

另一方面,根据我们的需求,需要采集的数据也是不同的,比如交通行业,数据采集会和摄像头或者测速仪有关。对于操作人员来说,日志收集和分析是关键点。因此,我们需要为特定的业务场景选择正确的收购工具。

至于拿到数据后的下一步,数据分析,可以看本帖2019 年 6 大数据分析工具 ,其中推荐类似 Tableau 和 FineReport 的工具。

您可能也会对…感兴趣

初学者财务报表分析指南

2019 年你不能错过的 9 个数据可视化工具

数据可视化中前 16 种图表类型

数据可视化十大地图类型

制作销售仪表盘的逐步指南

标注数据时会犯的四个错误

原文:https://towardsdatascience.com/four-mistakes-you-make-when-labeling-data-7e431c4438a2?source=collection_archive---------9-----------------------

可能出错的事情以及如何修复它们的清单

It’s better to anticipate and fix errors before they reach production

为 NLP 标记数据,就像驾驶飞机一样,乍看起来很容易,但可能会以奇怪而奇妙的方式出现微妙的错误。了解什么可能出错以及为什么出错是检测和修复错误的良好开端。

为 NLP 标记数据乍看起来很容易,但可能会以奇怪而奇妙的方式出现微妙的错误。了解什么可能出错以及为什么出错是检测和修复错误的良好开端。

在 LightTag,我们制作文本注释工具,并与我们的客户密切合作,以了解他们的注释工作中发生了什么,以及我们的产品如何帮助他们更快、更高质量地获得标记数据。在这篇文章中,我们将分享 NLP 实体注释中出现的四个常见问题,讨论它们的根本原因和可能的解决方案。

空格

White space is hard to see and can cause confusion

注释者意见不一致的最常见原因可能是前后空格和标点符号的标注不一致。也就是说,一个注释者可能会标注“Tal Perry”,而另一个注释者会标注“Tal Perry”或“Tal Perry”或“Tal Perry”。这个问题也出现在尾随标点符号上,例如“Tal Perry”

当测量注释者的一致性或决定一个黄金注释源时,这些冲突会导致较低的一致性分数和黄金集合中的模糊性。这些错误尤其令人沮丧,因为注释在概念上是正确的,人们不会真正注意到或关心这种差异。

事实上,这种微妙是这类错误的根源。通常,您的注释器并不关心您的算法如何计算一致性,也不会注意或关心“Tal Perry”和“Tal Perry”之间的区别,除非被明确告知这样做。

就这一点而言,解决方案很简单,您的注释工具应该在注释者捕捉到尾随和前导空格时向他们提供视觉指示,并让他们根据您设置的准则来判断这是否正确。

嵌套注释

A nest is great for complex things like life. For NLP you might want something else

另一个常见的分歧来源是“嵌套注释”。例如,短语“美国总统唐纳德·特朗普”可以有多种不同的标注方式。

A Naive annotation of the phrase says a whole thing is a person

A more pedantic approach breaks it down to title and person

The most pedantic annotation separates the title and country

这种错误的原因是根本性的,语言本质上是分层的,而不是线性的,所以像突出显示跨度这样的线性注释并不总是完美的。

Annotating Nested entities in Brat

Annotating a tree relationship in LightTag

从 UX 的角度来看,一个简单的解决方案是让注释者创建嵌套的注释,比如在 Brat 或 annotate tree structures 中。虽然这些解决方案从 UX 的角度来看是可行的,但它们需要下游模型能够处理模型输入和输出中的这些复杂的非线性结构。

在我们的客户群中,我们还没有看到结构化注释在语言社区之外被大量采用。这主要是因为使用它们需要额外的模型和工程复杂性。我们通常看到的是注释项目,指导他们的团队以尽可能好的分辨率进行注释,并在稍后阶段应用后处理来捕捉固有的结构

Your annotation tool should show you conflicts among annotators and let you resolve them.

中途添加新的实体类型

Always take extra precautions when adding new things together

在注释项目的早期阶段,您经常会发现您需要没有预料到的实体类型。例如,一个比萨饼聊天机器人的标签集可能以标签“大小”、“浇头”和“饮料”开始,然后有人意识到您还需要一个“配菜”标签来捕捉大蒜面包和鸡翅。

简单地添加这些标签并继续处理还没有被标记的文档会给项目带来危险。新标签将从添加新标签之前注释的所有文档中丢失,这意味着您的测试集对于这些标签来说是错误的,并且您的训练数据将不会包含新标签,从而导致模型无法捕获它们。

迂腐的解决方案是重新开始,并确保所有的标签都被捕获。然而,这是非常浪费的,每次你需要一个新标签的时候重新开始是一个不太理想的资源使用。一个很好的折中方法是重新开始,但是使用现有的注释作为显示给注释者的“预注释”。例如,LightTag 的文本注释工具可以让您做到这一点,向注释者显示预注释,他们可以通过单击一个按钮来接受这些预注释。从那里他们可以专注于添加新的标签。

长长的标签列表

Too much choice can be dangerous

增加项目成本和降低数据质量的一个可靠方法是强迫注释器处理非常长的标签列表。众所周知,ImageNet 有 20,000 个不同的类别,如草莓、热气球和狗。在文本中,SeeDev 2019 共享任务定义了“仅”16 种实体类型,这里显示了这些类型,但您可以看到它们是如何迅速变得势不可挡的。

The collection of tags for the SeeDev 2019 shared task

在注释过程中,增加注释者需要做出的选择数量会降低他们的速度,并导致数据质量下降。值得注意的是,标注的分布会受到标注 UX 中标签排序方式的影响。这是由于可用性偏差,在这种情况下,我们更容易识别出头脑中最重要的概念(存在于我们的头脑中)。

拥有 20,000 个类别的 Imagenet 是这个问题的一个极端例子,值得一读关于注释是如何收集的论文。他们的方法包括将一个注释任务分解成更小的任务,其中每个子任务一个注释者将注释某个类的一个实例(而其他工作人员将有单独的验证任务)。这大大减少了注释者的认知负荷,帮助他们更快地工作,减少错误。

结论

数据标注需要大规模、高精度地快速完成,其中任何一个都不能影响另一个。创建质量注释管道的第一步是预测常见问题并解决它们。这篇文章展示了文本注释项目中最常见的四个错误,以及像 LightTag 这样的文本注释工具如何帮助解决它们。

关于作者

Tal Perry 是团队文本注释工具 LightTag 的创始人兼首席执行官。他还是机器学习领域的谷歌开发专家,最重要的是,他是大卫的父亲和玛丽亚的搭档。

Tal and David discussing Labeled Data for NLP

特征工程艺术中不可避免的四个步骤是什么?

原文:https://towardsdatascience.com/four-unavoidable-tips-for-the-art-of-feature-engineering-in-machine-learning-ab4d1ce0cbda?source=collection_archive---------42-----------------------

数据仓库有一种存储数据的独特方式,这取决于组织的法规要求。因此,当发布或获取此数据以训练模型时,它可能不是模型用来以最大可能概率预测目标值的最佳形式。该数据可能具有许多不相关的特征,并且可能缺少用于预测的基本驱动特征。假设,我希望我的模型从包含以下特征的数据集学习预测纽约市的出租车费用: 出租车编号、预订时间(唯一随机标识符)、费用、接送地点、供应商名称、出租车类型、出租车颜色、目的地、预订编号 。你真的认为 cab no,booking_numbercab_color 可以帮助预测车费吗?不,它可能不会,相反,它可能会最终混淆我们的模型,因为 驾驶室编号 预订 _ 编号 可能会有不规则的幅度,而 驾驶室 _ 颜色 显然不是一个因素,因为它几乎不会影响骑车人的体验。这里,出现了伟大的特征工程方法论。特征工程包括我们对数据执行的任何操作,以将其转换为能够在使用训练模型进行预测时产生最高可能精确度的形式,包括选择好的特征、转换它们、导出合成特征、任何预处理等..

要素工程从保留现有的良好要素开始,创建额外的有用要素并从数据集中丢弃不相关的要素。以下四种策略可以帮助我们将数据集塑造成最适合模型的形式。

1。特征应该对模型结果 有影响——例如在上面的例子中,供应商名称取货地点、预订时间、出租车类型、目的地实质上是驱动费用的值。所以,这些都是好的特性。另一方面, cab_color、c ab nobooking_number 不会影响票价,所以这三个很可能被丢弃

2。特征值应该是数值,大小合理——比如上面数据集中的皮卡 _ 位置不是数值,可以是纽约市的任何地址,同样是目的地出租车类型。我们需要将这些非数字特征转换成数字特征。变换位置的一种简单方式是将它们分类成期望粒度的区域(限于五个区或接*地标或在每条街道等)。)然后对它们进行编码;驾驶室类型供应商名称也可以编码。此外, booking_time (从开始收集数据的特定日期起以秒为单位)不具有合理的量值,因此在用于导出合成特征(如 booking_daybooking_hourbooking_month )后,可以将其丢弃。这些综合功能非常有用,因为高峰时段的票价更高,周末也可能更便宜。此外,在假日季节(几个月),许多游客涌入纽约,票价上涨。此外,如果某些旅行的费用比其他旅行的费用高得多,它可能会被视为异常值而被直接拒绝。直方图有助于识别异常值。

  1. 特性应该有足够多的对应例子——例如,如果对于type _ of _ cabcategory(private,shared),我们没有足够的例子来说明‘shared’属性,这个特性就不能成为一个好的指示器。它会偏向于私人出租车的结果。根据经验,每个特性值至少应该有十个例子。

4。特性应该以人类的洞察力和理解力为指导——例如,我们如何理解我们可以创建 booking_hourbooking_month 作为特性。这是因为我们从自己的经验中意识到这种情况的普遍发生。因此,无论是主题专业知识还是一般的人类经验,在特征工程中都是有价值的。

机器学习模型的预测准确性在很大程度上取决于特征工程,数据科学家花费大约 50%至 75%的时间来为模型设计特征。一天结束时,你的模型只会按照你训练它的方式运行。特征工程既是一门艺术也是一门科学,你做得越多,就越擅长。

量化时间序列数据之间同步性的四种方法

原文:https://towardsdatascience.com/four-ways-to-quantify-synchrony-between-time-series-data-b99136c4a9c9?source=collection_archive---------0-----------------------

数据科学教程

计算同步度量的样本代码和数据,包括皮尔逊相关、时间滞后交叉相关、动态时间弯曲和瞬时相位同步。

Airplanes flying in synchrony, photo by Gabriel Gusmao on Unsplash

在心理学中,个体之间的同步可以是一个重要的信号,它提供了关于社会动态和社会互动的潜在结果的信息。人们已经在许多领域观察到了个体之间的同步,包括身体运动( Ramseyer & Tschacher,2011 )、面部表情( Riehle,Kempkensteffen,& Lincoln,2017 )、瞳孔扩张( Kang & Wheatley,2015 ),以及神经信号( Stephens,Silbert,& Hasson,2010 )。然而,术语同步可以有多种含义,因为有多种方法来量化两个信号之间的同步。

在本文中,我调查了一些最常见的同步指标和测量技术的优缺点,包括皮尔逊相关、时间滞后互相关(TLCC)和加窗 TLCC、动态时间弯曲和瞬时相位同步。举例来说,这些指标是使用样本数据计算的,其中微笑的面部表情是从两个参与者进行 3 分钟对话的视频镜头中提取的(如下截图)。要跟进,请随意下载样本提取的面部数据和包含所有示例代码的 Jupyter 笔记本。

概述

  1. 皮尔逊相关
  2. 时间滞后互相关(TLCC)和加窗 TLCC
  3. 动态时间扭曲(DTW)
  4. 瞬时相位同步

Sample data is the smiling facial expression between two participants having a conversation.

1.皮尔逊相关——简单最好

Pearson correlation 测量两个连续信号如何随时间共同变化,并以-1(负相关)到 0(不相关)到 1(完全相关)之间的数字表示线性关系。它很直观,容易理解,也容易解释。使用 Pearson correlation 时需要注意两件事:1)异常值会扭曲相关估计的结果,2)它假设数据是同方差的,因此数据的方差在整个数据范围内是同质的。一般来说,相关性是全局同步性的一个快照度量。因此,它不提供关于两个信号之间的方向性的信息,例如哪个信号在前,哪个信号在后。

Pearson 关联在多个包中实现,包括 Numpy、Scipy 和 Pandas。如果数据中有空值或缺失值,Pandas 中的关联函数会在计算前删除这些行,而如果使用 Numpy 或 Scipy 的实现,则需要手动删除这些数据。

以下代码加载的是样本数据(在同一个文件夹中),使用 Pandas 和 Scipy 计算 Pearson 相关性,并绘制过滤后的中值数据。

再一次,总体皮尔逊 r 是对全局同步性的度量,它将两个信号之间的关系简化为单个值。尽管如此,还是有一种方法可以利用皮尔逊相关来观察瞬间的局部同步。一种计算方法是通过测量一小部分信号中的皮尔逊相关,并沿着滚动窗口重复该过程,直到覆盖整个信号。这可能有点主观,因为它需要任意定义窗口大小,你想重复这个过程。在下面的代码中,我们使用 120 帧(~4 秒)的窗口大小,并在下图中绘制时刻同步。

Sample data on top, moment-to-moment synchrony from moving window correlation on bottom.

总的来说,皮尔逊相关是一个很好的起点,因为它提供了一种非常简单的方法来计算全局和局部同步性。然而,这仍然不能提供对信号动态的洞察,例如哪个信号首先出现,这可以通过互相关来测量。

2.时间滞后互相关——评估信号动态

时间滞后互相关(TLCC)可以识别两个信号之间的方向性,例如领导者-追随者关系,其中领导者发起由追随者重复的响应。有几种方法可以研究这种关系,包括经济学中使用的格兰杰因果关系,但请注意,这些仍然不一定反映真正的因果关系。尽管如此,我们仍然可以通过观察互相关来判断哪个信号先出现。

http://robosub.eecs.wsu.edu/wiki/ee/hydrophones/start

如上所示,TLCC 是通过递增移动一个时间序列向量(红色)并重复计算两个信号之间的相关性来测量的。如果峰值相关性位于中心(offset=0),这表明两个时间序列在该时间最同步。然而,如果一个信号领先于另一个信号,则峰值相关可能处于不同的偏移。下面的代码使用 pandas 功能实现了一个互相关函数。它还可以包装数据,以便仍然通过添加来自信号另一侧的数据来计算边缘上的相关值。

Peak synchrony is not at the center, suggesting a leader-follower signal dynamic.

在上面的图中,我们可以从负偏移推断出受试者 1 (S1)正在引导交互(当 S2 向前推进 46 帧时,相关性最大化)。但这又一次评估了全球水*的信号动态,例如在整个 3 分钟期间谁领先。另一方面,我们可能会认为互动甚至可能更加动态,这样领导者和追随者的角色会随时变化。

为了评估更细粒度的动态,我们可以计算加窗时间滞后互相关(WTLCC)。这个过程在信号的多个窗口中重复时间滞后互相关。然后,我们可以分析每个窗口,或者对窗口求和,这将提供一个分数,比较两个个体之间领导者与追随者之间的互动差异。

Windowed time lagged cross correlation for discrete windows

上面的图将时间序列分成 20 个均匀的块,并计算每个窗口中的互相关。这让我们对交互中发生的事情有了更细粒度的了解。例如,在第一个窗口(第一行)中,右边的红色峰值表示 S2 最初领导交互。然而,在第三或第四个窗口(行),我们可以看到 S1 开始更多地引导互动。我们也可以连续计算,得到更*滑的图,如下所示。

Rolling window time lagged cross correlation for continuous windows

时间滞后互相关和窗口时间滞后互相关是可视化两个信号之间的细粒度动态交互的好方法,例如领导者-追随者关系以及它们如何随时间变化。然而,这些信号是在假设事件同时发生且持续时间相似的情况下计算的,这将在下一节讨论。

3.动态时间弯曲——长度不同的信号的同步

动态时间弯曲(DTW)是一种计算两个信号之间的路径的方法,该方法可以最小化两个信号之间的距离。这种方法最大的优点是还可以处理不同长度的信号。最初是为语音分析而设计的(在这个视频中了解更多),DTW 计算每帧之间的欧几里德距离,以计算将匹配两个信号的最小路径。一个缺点是它不能处理丢失的值,所以如果你有丢失的数据点,你需要预先插值。

XantaCross [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)]

为了计算 DTW,我们将使用dtw Python 包来加速计算。

这里我们可以看到白色凸线中显示的最小路径。换句话说,较早的主题 2 数据与较晚的主题 1 数据的同步相匹配。最小路径代价为 d =.33,可与其他信号相比。

4.瞬时相位同步。

最后,如果您有一个您认为可能具有振荡特性的时间序列数据(例如 EEG、fMRI),您也可以测量瞬时相位同步。这种方法还可以测量两个信号之间的瞬间同步。这可能有些主观,因为您需要将数据过滤到感兴趣的波长,但您可能有确定此类波段的理论原因。为了计算相位同步,我们需要提取信号的相位,这可以通过使用希尔伯特变换来完成,希尔伯特变换将信号分解为相位和功率(点击了解关于希尔伯特变换的更多信息)。这使我们能够评估两个信号是同相(一起上下移动)还是异相。

Gonfer at English Wikipedia [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)]

Filtered time series (top), angle of each signal at each moment in time (middle row), and instantaneous phase synchrony measure (bottom).

瞬时相位同步测量是计算两个信号之间瞬间同步的好方法,无需像滚动窗口相关那样任意决定窗口大小。如果你想知道瞬时相位同步与窗口相关相比如何,点击这里查看我之前的博客文章。

结论

这里我们介绍了四种测量时间序列数据同步性的方法:皮尔逊相关、时间滞后交叉相关、动态时间弯曲和瞬时相位同步。确定同步度量标准将基于您拥有的信号类型、您对数据的假设以及您希望从数据中获得什么同步信息的目标。欢迎在下面留下任何问题或评论!

查看下面 Jupyter 笔记本中的所有代码,并使用此处提供的样本数据。

*新增 2021.05.12:在 Google Colab 中直接打开教程!

如果您觉得本教程很有用,并将在您的研究项目中使用,请考虑引用这篇文章,并附上以下参考:

Cheong,J. H. (2020 年 12 月 8 日)。量化时间序列数据同步性的四种方法。【https://doi.org/10.17605/OSF.IO/BA3NY

谢谢引用!

西蒙,O. B .,布阿尔,I .,罗哈斯,D. C .,霍尔登,S. K .,克鲁格,B. M .,&戈什,D. (2021)。使用最小生成树、边缘切割和脑磁图来理解帕金森认知衰退的新方法。科学报道11 (1),1–17。

Pagay,V. (2021)。用微型张力计揭示植物水势的动态方面。 bioRxiv

Galvis,d .,Zavala,e .,Walker,J. J .,Upton,t .,Lightman,S. L .,Angelini,G. D .,… & Gibbison,B. (2021)。大手术期间和术后全身炎症和下丘脑-垂体-肾上腺(HPA)轴的动态相互作用。 bioRxiv

Bente,g .,Novotny,e .,Roth,d .,和 Al-Issa,A. (2020 年)。超越刻板印象:分析非言语融洽中的性别和文化差异。心理学前沿11

机器学习中的水力压裂特征

原文:https://towardsdatascience.com/fracking-features-in-machine-learning-b8247626e582?source=collection_archive---------29-----------------------

特征空间破解新数据引入潜在有用的新类,如果检测到的话。具有低于可接受的分类置信度的新数据点的增长率的突增表明新的数据区正在特征空间中被划分出来……

唯一不变的是变化。数据也不例外。检测数据演变允许我们进一步分析它对未来的决策意味着什么。例如,我们可能会根据症状周围的一些初始数据,将患者分为简单的死亡或不死亡。但是随着死亡的发展,症状及其适当的治疗方案也在发展。经过轻微症状训练以检测死者存在的模型仍然可以检测到具有急性症状的死者。但是我们希望在对这些新数据进行分类的同时也能检测到异常,发出警报并将其标记为可能需要新的类。预先区分急性、中度和轻度病例,并对患者进行分类,在许多层面上都有巨大的好处。

显然,特征的数量没有改变,用于数据分类的基本概念也没有改变。但是输入数据的分布已经改变。新数据在先前没有数据的同一特征空间中划分出区域。这是特征空间细分,或者更滑稽地说,是特征空间的分裂。

在旧数据/类上训练的模型将按照它知道的类存储任何和所有数据——这并不奇怪。但是将新区域标记和识别为潜在的新兴新类别是非常有用的。这实质上是这篇文章的目标。重点是介绍一种方法。为了做到这一点,我们考虑一个具有两个特性和几个类的简单问题。虽然问题是人为的,但视觉效果可以帮助你理解问题的关键。重现结果的代码可以从 github 获得。

当您在数据中检测到新的类时,该做什么取决于问题。例如,如果我们确实决定一个新的类是有保证的,我们可以标记这个标记的新数据的一部分并重新训练模型

1.特征空间分割

在 N 个类上训练的分类器必须将输入数据放入这 N 个类中的任何一个。包括所有旧的和任何新的数据点的整个特征空间已经被分成 N 个区域。但是训练分类器的数据可能没有完全覆盖这些区域。当新数据开始进入这些先前的空白区时,这表明数据正在演变。

Figure 1. Features have not changed. New data has come in to carve out a distinct zone for itself in the same feature space

例如,一个模型可能已经预先根据诸如“通话”、“移动”等术语的存在/不存在将通信设备分类为台式电话寻呼机..但是这个模型将会对对讲机移动电话感到非常困惑,因为它们已经声称拥有同一个特征空间的不同部分。根据描述中术语的具体丰富程度,模型可能会将其中一些产品标记为寻呼机,而将其他产品标记为台式电话,这正是分类器经过训练要做的事情。但是它不是最佳的。如果我们有能力检测到新数据到达这些以前的空白区域,我们就可以检查这些数据,并可能为它们定义新的类别。添加移动电话和对讲机作为新的类别,并训练分类器来预测它们,这将是对分类器非常有用的增强。

虽然我们可以在较低的维度中可视化新出现的裂缝和新的数据区,但在较高的维度中这是不实际的。我们需要一个全球性的衡量标准,作为正在进行的新数据分类的一部分。这一全球指标的表现应该为我们寻找新兴的区域/类别提供线索。从分类置信度中得出的一个指标就是我们在这里用来识别特征空间压裂的指标。让我们回顾一下什么是分类置信度。

2.分类置信度

大多数分类器本质上是概率性的(有显著的例外,如 SVM,即使有从距离度量导出概率的方法)。也就是说,当要求分类器预测新数据点的类别时,它首先给出该数据点属于任何可用类别的概率列表。然后,它选择概率最高的类。现在考虑下面的论点——大部分是常识。

  1. 每个新数据点都被放在一个类中,即分类器计算出的概率最高的类。概率越高,这个数据点分类的置信度就越大。
  2. 落在具有大量训练数据的区域中的新数据点将以高置信度被分类。
  3. 与上面第 2 点相反。也就是说,落在具有很少或没有训练数据的区域中的新数据点肯定会被分配一个类别,但是具有较低的置信度

下图 2A 用一个玩具 2 特征 2 类问题说明了这一点,该问题使用逻辑回归作为建立在充分分离的数据上的分类器。在线性边界上,点属于任一类的概率为 0.5,即置信度最小。随着我们远离边界并进入包含数据的区域,某个点属于正确类的估计概率会更高,也就是说,置信度会更高。

通常,数据点的分类置信度是该数据点可能属于 N 个类别中的任何一个的 N 个概率中的最大值。

分类置信度

图 2B 显示了在整个特征空间上计算的该模型的分类置信度。

Figure 2. (2A) The classifier is trained with the well segregated data on the left, yielding a perfect decision boundary. (2B) Given the classifier in 2A, the classification confidence of points all across the feature space is shown. The classifier has high confidence in the zones with a lot of training data compared to the zones with little or no training data

水力压裂指示器

从上面的讨论可以得出,当新数据落在先前未填充的区域中时,那些新数据点的分类置信度会较低。因此,我们选择一个阈值置信水*,并保存由模型预测的分类置信度低于该阈值的新分类数据点的计数。当没有划分出新的区域时,该计数将以其正常的背景速率增加,因为总会有一些名义量的数据进入未被占用的区域。但是当数据发展时,新数据的更高(高于背景)部分开始进入那些先前的空白区域。这将表现为该计数的增长率持续(假设数据继续以这种方式发展)激增——当然,其他条件都相同。

粗略地说,我们可以通过寻找低于阈值分类置信度的新数据点数量增长率的突增来识别特征空间压裂

压裂指示器

作为分类任务的一部分,我们计算分类置信度所需的概率已经由分类器提供。因此,在正在进行的分类练习中,低于阈值置信度的数据点的数量及其增长率很容易计算和跟踪。当我们检测到该压裂指标持续激增时,我们可以触发一个任务,以低分类置信度对特定的新数据进行采样,并决定是否为它们创建新的类。我花了一些时间才走到这一步,但这就是方法。我们将用一个例子和代码片段来结束这篇文章

3.模拟

考虑下面图 3.1 中所示的四个数据区和类别(A、B、C 和 D)的初始良好隔离布局。我们特意在每个区域/类别中为传入的数据留出足够的空间,以划分出新的区域/类别。下面是给定三个顶点的情况下将数据注入任意三角形区域的代码片段。

多项式逻辑回归分类器是根据图 3.1 中的数据进行训练的。假设这些类是线性且完全可分的,那么它会得到一个完美的 f1 分数。垂直和水*轴/线实际上是获得的决策边界。具有低分类置信度(< 0.75)的点被获得用于跟踪。

Figure 3. As time passes by the ‘active’ data zones grow from the four A-B-C-D in 3.1 to the eight zones A-B-C-D-A’-B’-C’-D’ in 3.5 in that order

3.1 低分类置信度区域

以下代码片段模拟了成批的新数据(当然没有标签),每批数据都向当时的活动数据区添加了初始点数的大约 1%。活动数据区从 A-B-C-D 开始,按以下顺序发展:A-B-C-D-A ' = > A-B-C-D-A '-B ' = > A-B-C-D-A '-B '-C ' = > A-B-C-D-A '-B '-C '-D '。从上面的图 3.2-3.5 可以清楚地看出,随着时间的推移,新的数据区 A '到 D '在特征空间中被划分出来。

我们跟踪低于阈值分类置信度的数据点。图 4 显示了这些数据点的空间分布。正如所料,没有训练数据显示的区域是这些图表中亮起的区域。

Figure 4. The data points with low classification confidence are right the middle of the zones that offered no training data to the model.

这是一个 2 特征问题,我们可以将特征空间的压裂可视化,如图 4 所示。压裂指标有助于我们在更高的维度上检测同样的问题,因为它是一个全局标量测量。

3.2 压裂指示器

从图 4 中可以清楚地看出,当开始划分新的数据区时,点的数量的增加速率必须有一个突增。因为我们在分类练习中记录了这个数字,所以很容易生成下面的图 5。

Figure 5. A spike in the rate of increase of points with lower than thresold classification confidence occurs when a new data zone starts to be carved out.

4.结论

我们的目标是通过全局测量来识别特征空间压裂,该全局测量可用于触发对受影响的新数据的评估,以评估添加新类的潜在有用性。

  • 我们将数据点的分类置信度定义为所有概率中的最大值,该数据点可能属于训练的任何类别
  • 我们将压裂指标定义为低于某个阈值分类置信度的新数据点数量的增长率
  • 借助于一个理想的、人为的问题(恒定的新数据速率、稳定发展的新数据区等),我们证明了压裂指标的突增指向了潜在新类别的增加。

真实数据包括噪声、可变数据速率、不断发展的数据区和正在消亡的数据区。尽管如此,如图 5 所示的仪表板监控图在生产中正在进行的分类练习中还是很有用的。如果不是为了精确定位一个新类有用的确切时间,而是为了检测什么时候应该拆分一个“非上述”桶。

原载于 2019 年 5 月 6 日【http://xplordat.com

用数据帧构建数据

原文:https://towardsdatascience.com/framing-data-with-dataframes-d9b7ce012be5?source=collection_archive---------24-----------------------

探索性数据分析

将开放数据导入业务框架

The Charging Bull in New York City. Photo: Author

在任何挑战的开始,特别是对于数据科学家经常面临的复杂和模糊的挑战,构建一个思考过程来解决基本问题是最初的任务之一。许多行业雇佣拥有特定领域知识的主题专家,他们不断开发、教授和增强独特的思维范式。

功能性组织结构将具有特定技能的员工划分到不同的部门,如人力资源、销售、营销、财务和工程等。这可能会产生筒仓效应,产生有用的信息,但不一定共享。作为回应,公司组建跨职能团队,以促进整个组织的共享和学习。

这些团队可以提高公司的整体效率,因为他们加强了公司相互依赖的内部网络。例如,可以通过整合(比如)数据科学家推断的信息和见解来改善战略决策。因此,让我们来看看如何将快速增长的数据导入企业领导者熟悉的直观框架中。

探索性数据分析

商业战略家和顾问经常通过进行形势分析来探索一个行业,形势分析考虑了 5C(背景、消费者、公司、竞争和合作)。增长份额矩阵,通常称为 BCG 矩阵,是由波士顿咨询集团在 1970 年推出的,是一个流行的可视化市场分析的商业框架。

波士顿矩阵根据成分增长率和市场份额评估市场,创建了四个象限,分别称为狗、问号、星星和现金牛。多元化公司在成熟、高份额的市场中拥有业务线,这些市场会产生超额现金流,也在具有高增长机会的细分市场中拥有业务线,这些细分市场通常需要大量现金投资。

Dogs 指的是低增长、低份额的市场,通常难以实现收支*衡。分析师的传统智慧是清算这个领域的业务。

问号是高增长、低份额的市场,既有潜力又有风险。新企业通过选择和剥离战略瞄准这一领域。

星号是问号,已被广泛用于成为市场领导者。由于激烈的竞争,持续的增长推动公司投资。

摇钱树是成熟的市场,在这里,根深蒂固的参与者可以用最少的投资维持他们的地位,让他们能够榨取可靠的现金流。

让我们用一个真实的例子来看看我们如何将波士顿矩阵中的概念应用到一个特定的行业。此外,我们可以获取免费的开放数据,并以有意义的方式组织信息来填充图表。最后,我们可以在一个交互式的、基于云的可视化环境中呈现我们的市场分析,可以通过查询来访问分层信息。

宠物护理行业

从蟒蛇到蟒蛇再到熊猫,数据科学家对动物有很强的亲和力。Robbrecht van Amerongen 编制了一份编程语言动物园中最受欢迎的清单。作为启发,我们可以通过搜索快速增长和备受喜爱的宠物护理行业的可用开放数据源来生成 BCG 矩阵(注意:市场研究的成本高达$9,450⁴).

美国宠物用品协会(APPA)预计,2019 年宠物护理行业将超过 750 亿美元,比上年增长 3.9%。⁵消费者支出类别主要是宠物食品(320 亿美元)、兽医护理(190 亿美元)和用品及非处方药(160 亿美元)。现在,让我们在网上搜索信息来源,以发展我们自己的市场分析。

纽约街区

我们可以在 Kaggle 上搜索数据集,但只会找到七个关于宠物的结果,尽管有无数的狗图像库。⁶最权威和完整的数据集是纽约市狗许可数据集,它跟踪 15 列和 122k 记录,作为纽约市开放数据倡议的一部分。⁷

该数据集包括纽约有执照的狗的区和邮政编码信息,这提供了按位置旋转数据的可能性,但区似乎太粗糙,邮政编码似乎太精细。因此,让我们参考纽约州卫生部对纽约市社区的邮政编码定义,它将纽约市细分为 42 个可管理的社区。⁸

First 10 neighborhoods in New York, mixed format (wide and long). Image: Author

最初的 Pandas 数据帧被安排在一个多层次的索引中,除了邮政编码,它被打包成一个宽格式。不过,该表的目标是将 NYC Dog Licensing 数据集中的每个记录的邮政编码映射到其各自的邻域。因此,第一项任务是将表重新调整为长格式,以便于处理,可以通过邮政编码进行索引。

First 10 neighborhoods in New York, long format. Image: Author

竞争对手集中度

除了代表纽约消费市场的特许狗数据,我们还可以收集有关商业竞争的信息。Yelp Fusion API 拥有纽约各种商业的综合数据库。⁹通过搜索宠物店宠物服务,我们可以收集到 1502 家在 2019 年积极迎合宠物护理行业的独特商家。

First 10 New York pet stores and pet services actively operating in 2019. Image: Author

市场集中度是衡量行业竞争力的一个基本指标,市场可以介于完全竞争和垄断竞争之间。没有每个商店的收入或客户流量数据,我们不得不做出一个很大且不切实际的假设,即每个商店都是等效的。话虽如此,我们可以用每家连锁店的数量来代表总市场份额。

集中度汇总了该行业顶尖公司的总市场份额。以⁰为例,我们四大公司的 CR4 仅占 8.9%,而 CR8 占 11.9%,这表明市场高度分散。或者,美国司法部在反垄断案件中使用的赫芬达尔-赫希曼指数在 0(完全竞争)和 10,000(垄断)的范围内是 31。

Concentration Ratios for the top 8 firms in the New York pet care industry. Image: Author

类似地,我们可以将竞争对手的数据按邻居分组,并测量地理集中度或密度。我们测量 CR4 为 30.6%,CR8 为 49.9%,这意味着一半的宠物店和服务位于八个社区。所有邻域份额的*方和为 448 的邻域 HHI 仍然被认为是不集中的。

Concentration Ratios for the top 8 neighborhoods in the New York pet care industry. Image: Author

市场尺寸

纽约市开放数据方便地让我们下载整个纽约市狗许可数据集作为一个 CSV 文件,我们可以导入到熊猫数据框架。我们注意到它有许可证颁发的年份和许可证到期的年份,这使我们能够统计在给定的年份中有多少有效的许可证狗。这个指标与数字营销中的月活跃用户(MAU)非常相似。

First 10 of 121,713 New York licensed dogs from 2014–2022. Image: Author

现在,我们已经收集了我们的邻居、宠物企业和特许狗数据集,我们可以将它们插入到 SQL 数据库中,并通过一些强大的查询将它们连接到单个数据框架中。通过只选择每个日历年中有效的狗许可证,我们可以计算每个街区从 2014 年到 2019 年的 5 年复合年增长率(CAGR) ⁴。

Market share and growth rate (2014–2019) of pet care industry for first 10 neighborhoods in New York. Image: Author

现在,我们已经计算了纽约每个街区的许可狗的市场份额和增长率,我们可以在 Plotly 等数据可视化引擎中以 BCG 矩阵的形式呈现我们的分析。⁵我们可以通过将数据点划分为每个社区的宠物商店的数量,并用每个商店的特许狗的数量来给这些数据点添加阴影,从而增加图表的丰富性。

纽约许可养狗的增长份额矩阵展示了一种引人注目的邻里模式,它遵循着一条从最初的狗,发展到问号,成为明星,成熟为摇钱树的轨迹。我们可以很容易地看到,四个社区享有很高的市场份额,其中两个提供了机会,因为它们没有得到宠物企业的充分服务。

Growth-Share Matrix of licensed dogs in New York. Source: Author¹⁶

为该分析编写的源代码可在 github 上获得,其中包括从 Yelp 和 NYC Open Data 收集数据集,用 Python、Pandas 和 SQL 处理数据,并在 Plotly 中呈现 BCG 矩阵。整个 Plotly 代码很短,可以由 Plotly 自动上传和托管,Plotly 为修改和可嵌入的链接提供了一个仪表板。

Visualizing the BCG Growth-Share Matrix with Plotly. Source: Author¹⁸

小心缝隙

宠物企业的市场份额只能通过给定社区内企业或公司拥有的实体店数量来计算,这可以通过收入或客流量数据来提高。

纽约市经济发展公司估计,纽约只有 20%的狗获得许可,因此需要注意的是,纽约市许可的狗数据集只是整个狗种群的样本。

狗数据集于 2014 年开始跟踪数据,因此在随后的几年里,注册量出现了明显的峰值。注册数量的增长不应与实际养狗数量的增长相混淆。

狗的数据集最后一次更新是在 2017 年,所以最*颁发的许可证没有被捕获,而正在进行的到期将在 2022 年前使狗的数量减少。这种数据上的差距会影响 CAGR 比率,取决于所考虑的年份。

鉴于任何数据集的局限性,我们现在应该有信心收集开放的数据源,进行市场分析并可视化 BCG 矩阵,以便我们的数据可以轻松地与企业领导者相关联。

参考

  1. T.J. Steenburgh 和 J. Avery,“营销分析工具包:形势分析”,哈佛商学院背景说明 510–079,2010 年。
  2. A.Ovans,“改变世界的图表”,《哈佛商业评论》,2011 年。
  3. R.van Amerongen,“欢迎来到受动物王国启发的编程语言动物园”, AMIS,数据驱动博客,2018 年 1 月 14 日。
  4. “2018-2025 年按宠物类型(狗、猫、鱼、鸟)、产品、竞争格局和细分市场预测的宠物护理市场规模、份额和趋势分析报告”,大观研究,2018 年。
  5. J.巴克斯特,“美国人在宠物上的支出比以往任何时候都多:720 亿美元,”美国宠物产品协会,2019 年 3 月 21 日。
  6. 卡格尔,https://www.kaggle.com,2019。
  7. 心理健康和卫生部,“纽约市狗许可数据集”,载于纽约市 OpenData,https://data . cityofnewyork . us/Health/NYC-Dog-Licensing-Dataset/nu7n-tubp,2019 年 7 月 25 日更新。
  8. “纽约市街区的邮政编码定义”,纽约州卫生部,https://www . Health . ny . gov/statistics/cancer/registry/appendix/Neighborhoods . htm,2006 年更新。
  9. Yelp Fusion,【https://www.yelp.com/fusion】T2,2019。
  10. Y.谭,“中国银行业效率与竞争的测度”,载《中国银行业的效率与竞争》,昌多斯出版社,2016 年。
  11. C.R. Laine,“Herfindahl-Hirschman 指数:从消费者角度看集中程度”,《反托拉斯公报,1995 年 6 月 1 日。
  12. “赫芬达尔-赫希曼指数”,美国司法部,https://www.justice.gov/atr/herfindahl-hirschman-index,2018 年 7 月 31 日更新。
  13. 米(meter 的缩写))Knoop,“应用洞察:MAU 究竟是如何计算的?“《广告周刊》,2009 年 1 月 12 日。
  14. J.Fernando,“复合年增长率— CAGR”, Investopedia ,2020 年 11 月 13 日更新。
  15. 剧情,https://plotly.com,2019。
  16. A.C. Dick,“纽约各街区许可养狗的增长份额矩阵”,载于 Plotly,https://chart-studio . plot ly . com/~ Adam . c . Dick/2/Growth-Share-Matrix-of-Licensed-Dogs-in-New York-by-Neighborhood,2019。
  17. A.C. Dick,“用 DataFrames 构建数据”,载于 GitHub,https://github.com/acdick/framing_data_with_dataframes,2019 年。
  18. A.C. Dick,《在 Plotly 中可视化 BCG 矩阵》,载于 GitHub,https://gist . GitHub . com/AC Dick/52 eef 3c 723 a 2361 a 187 e 78 ff 808 EB 14,2019。

法国 2019 年人工智能大会:从学生的角度看

原文:https://towardsdatascience.com/france-is-ai-conference-2019-from-a-student-point-of-view-2826274315b2?source=collection_archive---------39-----------------------

The amazing team of organizers!

我知道距离我的上一篇文章已经过去了很长时间,发生了很多事情,我有其他的优先事项,我的一些其他文章仍然需要结束,但这次不是,所以我们带着一些新的东西再来一次!

今天,我将讲述我上周参加的一个非常有趣的活动,我将尝试综合我所理解的内容,并给你一些我在研究后发现的有用链接,如果你想深入了解的话。

长话短说:去年 6 月作为一名计算机系统工程师毕业,现在我在巴黎攻读计算机视觉硕士,在大城市的一个优势是你可以找到的活动和会议的数量和质量,我很幸运地发现了“法国是 AI ”。

法国是人工智能,是 2016 年发起的一项倡议,旨在支持和促进法国人工智能生态系统。活动在巴黎市中心的创业园区站 F 举行。

STATION F, Paris (France)

老实说,我想去的主要原因是为了见见伟大的 Yoshua Benjio ,但不幸的是,他因腿骨折而无法参加活动,然而,其余发言者的质量正如我所期待的那样好,在大多数情况下,我必须实时学习许多新单词才能赶上。

我将尝试从我的角度对我所看到的给予反馈,并给你一些链接,以防你想看得更深。你可以在这里找到会议的日程。正如你所看到的,这是非常激烈的,所以我将只谈论我可以跟随的人,我想提一下,我喜欢他们使用的细节和技术词汇的水*,这在其他活动中通常不会出现。

我记得的第一个演讲是“关于多智能体学习的评估和培训”,由 Google DeepMind 的一位研究科学家做的,在那里他展示了他们的最新成果: α-Rank ,这是一种在大规模多智能体交互中对智能体进行评估和排序的方法。演讲者鼓励寻找更古老的方法,并举了一个强化学习的例子,这是一种古老的方法,但在过去几年里引起了科学界的极大兴趣。然后,他给出了使用纳什均衡的 3 个缺点(详情请查阅论文),以及为什么他们使用马尔可夫-康利链。

下一位演讲者是 NAVER LABS 的研究员 Naila Murray,她谈到了“在虚拟世界中学习视觉模型”,她展示了他们在过去几年中一直在做的一系列工作,这里我要打断一下,我不知道这意味着什么,但根据我的理解:使用合成数据训练模型时存在过度拟合的问题,他们找到了一些使用合成视频生成真实世界数据的解决方案,如果我错了,请纠正我。

然后我们与谷歌大脑研究员 Nicolas Papernot 讨论了对抗性攻击(和著名的“熊猫”照片),以及基于 DNN 的解决方案中的隐私保护,以及在使用私人训练数据时如何使用有效的方法。

If you reverse-engineer a model, you can easily trick it to have this kind of results

然后由 Cretio 做了一个关于他们如何大规模使用广告推荐系统的演示,并使用了一个 SVD 变换*似(随机化 SVD)和非常大的矩阵。在这里你可以看到他们系统的简要描述。

Criteo recommender systems presentation

下一个发言人伤害了我的感情😂我的意思是我去年的毕业设计是关于特征选择的,听她的演讲让我觉得:

更严重的是,他们正在处理一个“高维小样本”的问题,当你有这么多特征,但没有足够的数据来训练一个稳健的模型时,这就是基因组学的主要困难之一。她提出了三个建议:1)使用结构化的先验知识 2)对每对特征和表型之间的关联进行统计测试 3)使用核。

我喜欢下一位演讲者,让·庞塞,Inria 的研究主管,不仅仅是因为这完全直接关系到我的研究领域,还因为他用来说服你这些挑战的重要性的论据和方法。

更多关于对抗性攻击的演讲是由巴黎多菲纳大学教授兼 MILES 的负责人 Jamal Atif 提出的。我以前没有这方面的知识,我听不懂他在说什么,但他介绍了他的团队开发的许多方法,这些方法似乎非常有效。

然后,就在午餐前,我们听取了来自纽约一家专注于 NLP 的初创公司humping Face的 Thomas Wolf 的演讲,他在演讲中介绍了迁移学习,其工具,以及趋势。我认为这是一家非常有前途的初创公司,尤其是在开发了他们的版本BERTdistil BERT 之后。

休息之后,我们听取了夏羽·马利特关于“深度神经网络的数学解释”的演讲,以及他如何在学习的重要性上输给了(他试图证明你不需要有一个大的数据集来获得好的结果)。

在那之后,Google 的工程主管 Noe Lutz——Brain Applied Zurich 向我们介绍了 TensorFlow 2.0,我不得不说他们所做的改进是惊人的,尤其是因为我有很多东西要赶上(我猜从 1.7 开始就没有使用 tf 了)。

“使用机器学习管理城市移动性”是 Dominique Barth 做的一个非常有趣的演讲,因为它完全是关于使用强化学习( 1 、 2 、 3 、 4 、 5 和 6 )来解决这个问题,并且在一定程度上理解演讲者所谈论的内容总是一件令人愉快的事情。

接下来的演讲由脸书人工智能研究所的研究科学家 Natalia Neverova 进行,她指出视觉人类理解的下一个里程碑是获得图像中每个像素的语义含义以及它们到物体特定部分的映射,以及从 2D 重建 3D 姿势和形状的问题。跟踪最先进的问题是很重要的,因为即使你只是一名学生或来自行业,你也可以为解决这些问题做出贡献,因为你有自己的观点,可能连像 FAIR 这样的大实验室都没有考虑到。

下一位演讲者是微软法国公司的 CTO & CSO Bernard Ourghanlian,他再次谈到了人工智能中的隐私、对抗性攻击和伦理,以及全同态加密方法如何解决许多问题,并解释了其背后的动机,还说这是一种有前途的方法,即使它可能会产生潜在的性能成本。他还展示了用于此目的的微软编译器 CHET。

在这个休息时间,我有机会与谷歌苏黎世机器学习研究负责人 Olivier Bousquet 面对面交谈,我问他他们正在研究的热门话题,不出所料,强化学习再次出现在桌面上,这使得讨论更加有趣,因为我可以保持对话活跃(不幸的是,我不太擅长与女士们交谈😥).

说到 Olivier,他是下一个演讲者,他的演讲是关于“解决许多任务的模型”。他首先展示了人工智能在具体任务方面有多好,如 ImageNet 分类,以及它们如何超越了人类现在的误差容忍水*(最高 1%误差< = > 99%+准确率)。但是他说我们仍然远没有解决视觉或语言的实际问题,为什么我们不考虑一个模型来解决许多任务。怎么做呢?他认为有一个秘方可能行得通(提示:是自我监督和转移学习)他举了 BERT 的例子(不是芝麻街的那个)。最后,他谈到了一种方法他们正在研究制作多任务模型:通过使用多个基本模型。

下一个演讲是关于“将纵向形状数据集聚类成独立或分支轨迹的混合物”,由我们大学的教授 Stephanie Allassonniere 主讲😎。他们的贡献是从一组患者中重组疾病的进化,以提供整个群体的进化。怎么会?我不会比她解释得更好( 1 、 2 、 3 、 4 、 5 ),但总的来说,我所理解的主要思想是根据特征子集来推断疾病的演变。

Test, learn then Scale, I really like this “motto”

下一位演讲者是史蒂夫·贾勒特,他介绍了人工智能在法国跨国电信公司 Orange Group 的应用,他是人工智能、数据工程和人工智能战略的负责人。我真的很喜欢他将今天的人工智能与 1995 年的手机进行比较,以及 Orange 对非洲国家的愿景,这些国家不一定能接入互联网。

下一个演讲是由来自 Criteo 的研究员 Vianny Perchet 所做的“竞争与合作的人工智能”。这让我看到了数据的一个非常关键的用例:你如何确保你用来训练你的模型的数据的完整性,尤其是在竞争中?你怎样才能找到一个双赢的局面或者一个“纳什均衡”?

贾丝汀·卡塞尔的演讲与我们一整天所看到的有所不同,她谈到了“社交人工智能”,以及这些系统的目标如何不是达到人类的水*,而是,特别是在与孩子们互动时,不要愚弄他们,并给他们能力说这不是一个真正的人类,但即使在这种情况下,利用它的帮助。

我错过了下一位演讲者(来自 INRIA/ENS 的 Francis Bach)的大部分演讲,他谈到了“机器学习的分布式优化”,但你可以从他的结论中看到他,给出了他们得到的一些结果以及关于如何优化分布式 ML 算法的其他观点。

来自 CentraleSupelec 的 Maria Vakalopoulou 向我们介绍了他们最*在医疗保健以及人工智能和医学成像方面的工作,以及她对该领域未来的看法。

现在,大家都在等待的演讲开始了:2018 年图灵奖得主(严和辛顿)因其对人工智能进步的卓越贡献而获奖,Yoshua Bengio,正如我们之前提到的那样不能来,但仍然通过视频电话发表了他的演讲。他提到了很多方面,其中之一是目前的系统 1 和系统 2 认知类别,最后,他谈到了他将如何定义达到“人类水*的人工智能”的下一步,并缩小两个系统之间的差距。他在两周前做了一个类似的演讲,内容完全相同,所以你可以在这里查看。

然后,我们有一个有趣的小组,讨论如何在欧洲进行人工智能监管,以及各国如何合作,在当地监管的基础上增加一个共同的、更强有力的监管。

Nicolas 和 Emmanuel 透露,就人工智能投资而言,法国显然是欧洲第一国家,主要是因为英国因英国退出欧盟困境失去了一些兴趣,但欧洲仍有很长的路要走,才能赶上美国。

最后,我知道这是一篇很长的文章(你可以想象我们当时的日子),我要感谢主办方:法兰西数码,感谢他们邀请我参加这次会议。我来到法国才一个月,我不知道其他会议/活动如何,但我喜欢大多数演讲中的技术含量。

如果你在那里,你有什么要补充的,或者你想纠正什么,请留下评论,我接受所有的反馈,因为我还在学习。

你正在阅读 Amine 的一篇文章,他是一名年轻的计算机视觉学生,他是这样进行机器学习的:

Credits: instagram.com/neuralnetmemes

利用成本敏感的机器学习进行欺诈检测

原文:https://towardsdatascience.com/fraud-detection-with-cost-sensitive-machine-learning-24b8760d35d9?source=collection_archive---------1-----------------------

依赖于实例的成本敏感分类算法的概念

在传统的两类分类问题中,我们的目标是最小化错误分类,并使用准确性、F-score 或 AUC-ROC 曲线等指标来衡量模型性能。然而,在某些问题上,为了降低总成本,允许更多的错误分类是最好的。如果与错误分类相关的成本因样本而异,我们应该应用依赖于示例的成本敏感学习方法。但是让我们从头开始…

在本文中,我将通过在信用卡欺诈数据集上训练和测试各种模型来解释示例依赖成本敏感机器学习的概念。请注意,我选择这个任务的模型是为了说明这个概念,而不是为了获得最佳的预测结果。本文提供了部分代码,完整的代码可以在我的 GitHub 上找到。

什么是成本敏感学习?

传统的分类模型假设所有的误分类错误具有相同的成本,而成本敏感模型考虑了因分类类型和样本而异的成本。

让我们来看看信用卡交易的案例。未经真实持有人授权的交易被认为是欺诈性的(通常占所有交易的很小一部分)。信用卡欺诈检测系统应该自动识别和阻止这种欺诈交易,同时避免阻止合法交易。

每种分类的相关成本是多少?让我们假设下面的场景。如果系统没有识别出欺诈性交易,钱就会丢失,持卡人需要得到全部交易金额的补偿。如果系统将交易标记为欺诈,则交易会被阻止。在这种情况下,会产生管理成本,因为需要联系持卡人并更换卡(如果交易被正确标记为欺诈)或重新激活卡(如果交易实际上是合法的)。让我们也做一个简化的假设,即管理成本总是相同的。如果系统正确地将交易标记为合法,则交易会被自动批准,并且不会产生任何费用。这导致了与每个预测场景相关的以下成本:

请注意,“正”是预测为欺诈的交易,“负”是预测为合法的交易。“真”和“假”分别指正确和不正确的预测。

因为交易成本取决于样本,假阴性的成本可以低到可以忽略不计(例如,对于 0.10 美元的交易),在这种情况下,阳性预测的管理成本将超过补偿成本,或者非常高(例如,对于 10,000 美元的交易)。

成本敏感学习背后的思想是将这些依赖于示例的成本考虑在内,并做出旨在最小化总成本而不是最小化错误分类的预测。

成本敏感型培训与成本依赖型分类

让我们考虑两种不同的方法。第一个是用损失函数训练模型,该损失函数最小化实际成本($)而不是误分类错误。在这种情况下,我们需要为损失函数提供与四种情况(假阳性、假阴性、真阳性和真阴性)中的每一种相关联的成本,以便模型可以学习相应地做出最佳预测。

第二种方法是训练常规模型,但是在根据最低预期成本进行预测时对每个样本进行分类。在这种情况下,不需要训练集的成本。然而,这种方法只适用于预测概率的模型,然后可以使用概率来计算预期成本。

在下文中,我将使用成本敏感损失函数的模型称为“成本敏感模型”,将在进行预测时使预期成本最小化的模型称为“成本分类模型”

实施和评估模型

在这个案例研究中,我使用了一个信用卡欺诈数据集(可在 Kaggle 上获得),有 284,000 个样本和 30 个特征。目标变量指示交易是合法的(0)还是欺诈的(1)。数据高度不*衡,只有 0.17%的欺诈交易。我对以下五个模型进行了训练和评估。

  1. 常规 逻辑回归(来自 scikit-learn)
  2. 常规人工神经网络(内置于 Keras)
  3. 成本敏感人工神经网络 (Keras)
  4. 成本分类逻辑回归
  5. 成本分类人工神经网络

在实践中,人工神经网络(“ann”)可能不是欺诈检测的首选。基于树的模型,例如随机森林和梯度推进机器,具有可解释性的优势,并且通常执行得更好。为了说明的目的,我使用了人工神经网络,因为成本敏感损失函数的实现相对简单。此外,正如我将要展示的,一个简单的人工神经网络可以产生非常好的结果。

为了评估结果,我使用了两个不同的指标。第一个是传统的 F1-score,它衡量精度和召回率,但不考虑错误分类的示例依赖成本。

为了评估模型在成本方面的表现,我首先根据模型是预测假阳性、假阴性、真阳性还是真阴性,以及与每个案例相关的成本,来计算由预测产生的所有成本的总和。

然后,我计算了在所有情况都被预测为负的情况下会发生的总成本(“cost_max”),并将成本节约定义为实际预测减少成本的部分。

为了评估模型,我使用了五重交叉验证,并将数据分成五个不同的训练集(80%)和测试集(20%)。下一节给出的结果指的是五个测试集的*均结果。

逻辑回归

因为基本模型服务于 scikit-learn 库中的常规逻辑回归模型。下图显示了预测概率和交易金额之间的分布。如果没有对成本敏感的分类,欺诈概率和交易金额之间就没有明显的关联。

逻辑回归表现相当好,*均测试集 F1 得分为 0.73,成本节约为 0.48。

人工神经网络

接下来,我在 Keras 中构建了一个 ANN,它具有三个完全连接的层(50、25 和 15 个神经元)和两个脱离层。我运行了两个时期的模型,并使用了 50 的批量大小。使用 Keras 的顺序模型 API,Python 中的实现如下所示:

from keras.models import Sequential
from keras.layers import Dense, Dropoutdef ann(indput_dim, dropout=0.2):
    model = Sequential([
    Dense(units=50, input_dim=indput_dim, activation='relu'),
    Dropout(dropout),
    Dense(units=25, activation='relu'),
    Dropout(dropout),
    Dense(15, activation='relu'),
    Dense(1, activation='sigmoid')])
    return modelclf = ann(indput_dim=X_train.shape[1], dropout=0.2)
clf.compile(optimizer='adam', loss='binary_crossentropy')
clf.fit(X_train, y_train, batch_size=50, epochs=2, verbose=1)
clf.predict(X_test, verbose=1)

下面是用人工神经网络预测的欺诈概率的分布。类似于逻辑回归模型,欺诈概率和交易金额之间没有明显的关系。

在 F1 分数和成本节约方面,人工神经网络优于逻辑回归模型。

成本敏感人工神经网络

现在事情变得更有趣了。成本敏感型人工神经网络与常规人工神经网络相同,不同之处在于成本敏感型损失函数。之前的两个模型都使用对数损失(“二元交叉熵”)作为损失函数:

这个损失函数同等地惩罚假阴性和假阳性。现在让我们来看看一个对成本敏感的损失函数。在这里,所有四种可能的结果(假阳性、假阴性、真阳性和真阴性)都被考虑,并且每种结果都带有特定的成本。成本敏感损失函数如下所示:

请记住第一部分,真阳性和假阳性被认为是同样昂贵的(阻止事务的固定管理成本)。真否定的成本是 0 美元(无行动),假否定的成本是交易金额(假设我们必须偿还整个交易)。注意,在这四个成本中,只有假阴性的成本是依赖于实例的。这具有这样的效果,随着交易金额的增加,相对于正面预测的管理成本,对未识别的欺诈交易的惩罚增加。因此,损失函数应该训练一个模型,当交易金额较高时,该模型更有可能拒绝可疑交易。交易金额从 0 美元到 25,691 美元不等,*均值为 88 美元,我假设固定管理成本为 3 美元。

在 Python 中,我们相应地定义了假阳性、假阴性、真阳性和真阴性的代价。因为假阴性的代价是依赖于实例的,所以它们用长度等于样本数的向量来表示。

cost_FP = 3
cost_FN = data['Amount']
cost_TP = 3
cost_TN = 0

在 Keras 中实现一个示例依赖损失函数很棘手,因为 Keras 不允许将除 y_true 和 y_pred 之外的参数传递给损失函数。通过将损失函数包装到另一个函数中,可以将常量变量传递给损失函数。然而,假阴性的代价取决于实例。因此,我使用了一个技巧,将假阴性的成本作为逗号后的数字添加到 y_true,并在自定义损失函数中提取它们,同时将 y_true 舍入到原始整数值。Keras 中转换 y_true 的函数和自定义损失函数的实现如下所示:

import keras.backend as Kdef create_y_input(y_train, c_FN):
    y_str = pd.Series(y_train).reset_index(drop=True).\
            apply(lambda x: str(int(x)))
    c_FN_str = pd.Series(c_FN).reset_index(drop=True).\
            apply(lambda x: '0'*(5-len(str(int(x)))) + str(int(x))
    return y_str + '.' + c_FN_strdef custom_loss(c_FP, c_TP, c_TN):
    def loss_function(y_input, y_pred):
        y_true = K.round(y_input)
        c_FN = (y_input - y_true) * 1e5
        cost = y_true * K.log(y_pred) * c_FN + 
               y_true * K.log(1 - y_pred) * c_TP) +
               (1 - y_true) * K.log(1 - y_pred) * c_FP +
               (1 - y_true) * K.log(y_pred) * c_TN)
        return - K.mean(cost, axis=-1)
    return loss_function

然后,我调用定义的函数来创建 y_input 向量,训练对成本敏感的人工神经网络并进行预测:

y_input = create_y_input(y_train, cost_FN_train).apply(float)
clf = ann(indput_dim=X_train.shape[1], dropout=0.2)
clf.compile(optimizer='adam', loss=custom_loss(cost_FP, cost_TP,
            cost_TN))
clf.fit(X_train, y_input, batch_size=50, epochs=2, verbose=1)
clf.predict(X_test, verbose=1)

在下面的分布图中,我们可以看到成本敏感学习的效果。随着交易金额的增加,预测的总体分布向右扩展(欺诈概率更高)。请注意,在这种情况下,由于问题的性质和损失函数的定义,“预测的欺诈概率”意味着“我们应该将交易识别为欺诈吗?”而不是“交易是否欺诈”。

评估显示了成本敏感学习的预期效果。成本节约增加了 5 %, F1 分数下降了相似的幅度。成本敏感分类的结果是更多的误分类,而总误分类成本较低。

成本分类模型

与使用定制损失函数训练的成本敏感模型相反,成本分类模型基于预测概率计算预期成本。预测合法交易和欺诈交易的预期成本计算如下:

然后,分类器选择预计会导致较低成本的预测。

因此,我使用了常规逻辑回归和人工神经网络的概率预测结果,并根据预期成本对预测进行了重新分类。下图以逻辑回归模型为例,展示了成本相关分类的效果。请注意,预测概率的分布与常规逻辑回归模型产生的分布没有变化。然而,通过成本相关分类,随着交易金额的增加,该模型倾向于将欺诈概率小的交易识别为欺诈。在图的右侧,我们看到即使欺诈概率接* 1,金额非常小的交易也被预测为合法。这是由于假设真阳性携带 3 美元的管理成本。

根据预期成本对预测进行分类会在成本节约方面产生更好的结果(在 F1 分数方面会产生明显更差的结果)。虽然对人工神经网络实施成本敏感损失函数可降低 5%的成本,但成本分类人工神经网络可降低 10%的成本。

结论

本文阐述了两种根本不同的方法,例如基于成本敏感分类的信用卡欺诈预测。成本敏感训练模型需要自定义损失函数,而成本分类模型只需要每个类别的概率和与每个结果相关联的成本来对交易进行分类。在我的示例案例中,成本分类模型以大量的错误分类为代价实现了稍微好一点的成本节约。此外,成本分类模型更容易实现,因为它不需要用于训练的定制损失函数。然而,成本分类方法仅适用于预测概率的模型,而逻辑回归和人工神经网络可以方便地预测概率。然而,更广泛用于欺诈检测的基于树的模型通常将预测直接分成类别,使得成本分类方法不可行。基于树的模型的成本敏感方法虽然在概念上类似于本文中介绍的方法,但在实现上更加复杂。如果你对这个话题感兴趣,我建议你看看下面提到的文章。

感谢阅读这篇文章。请随时通过下面的评论区发表评论或提出问题,或者通过 LinkedIn 与我联系。

为这个插图创建的代码可以在我的 GitHub 上访问

信用卡欺诈数据集可在 Kaggle 上获得

如果你有兴趣学习更多关于基于树的模型的成本敏感学习,我推荐这篇来自 A. C. Bahnsen,D. Aouada 和 B. Ottersten 的论文以及 costcla GitHub 库

使用本福德定律(Python 代码)进行欺诈检测

原文:https://towardsdatascience.com/frawd-detection-using-benfords-law-python-code-9db8db474cf8?source=collection_archive---------4-----------------------

本福德定律的发现

你有没有注意到一个给定的数字有多少机会以数字 1 开头?数字 1 成为前导数字的概率和 9 一样吗?让你知道一个数字的前导数字代表它的非零最左边的数字。例如,在 29 和 0.037 中,它们分别是 2 和 3。嗯,上一个问题的答案是否定的……根据本福特定律,也称为第一位数字定律,自然发生的数字分布中前导数字的出现频率是可预测的,不均匀的,但更接*幂律分布。事实上,一个给定的数字以 1 开头的可能性是以 9 开头的 6 倍!这是非常不合逻辑的,因为大多数人会期望均匀分布 U(1,9),其中所有数字在第一个槽中出现的可能性相同,因此他们期望概率为 1/9,即约 11.1%。让我们考虑 Pr(D1=d)是一个给定数字有第一个数字 d 和 Pr(D2=d)有前两个数字的概率,下表提供了 1881 年纽康观察到的所有十进制数字 probs。

Probabilities of leading numbers

The frequency of occurrence of leading digits according to Benford’s law

纽康注意到最前面的页面,用于从最低数字开始的数字,比后面的页面更磨损,这就是为什么前导数字更有可能是小的而不是大的。然后,在 1938 年,物理学家弗兰克·本福特通过收集超过 20,000 个真实世界数字的样本,重新发现了纽科姆定理,使用的数据来源包括河流、街道地址、读者文摘杂志中包含的数字、分子量、棒球统计数据、死亡率等等。因为他普及了这项科学发现,他得到了所有的荣誉。根据他的 Benford 的说法,在这些看似完全不同的数据集中出现了一种轶事模式,这些数据集中的前导数字 d 遵循对数衰减分布:

Pr(D1=d) = log10(1 + 1/d)

而不是像人们可能天真地猜测的那样均匀分布。

应用

建模:本福德定律最广为人知的一个主要应用领域是直觉建模。它基于以下非常简单的想法:

***If a certain set of values follows Benford's Law then model's for the corresponding predicted values should also follow Benford's Law.***

它可用于人口增长、金融指数和任何本福特数据集的模型中。

欺诈检测:这是与数据挖掘、专家系统和神经网络等领域相关的最流行的应用程序。它来自于这样的观察:

***Manipulated or fraudulent data do not trend to confirm to Benford's Law, whereas unmanipulated data do.***

根据上面的陈述,本福德定律可以被宣布为一个重要的规则,以便在已经计算了分类值的字段(如医疗测试结果、所得税收入或客户退款)中调查数据集的欺诈模式。该标准还可以检测非虚假相关应用程序中受大量低价值交易、数据收集和缺失数据问题、缩减值和偏差影响的缺陷。

应用本福特定律

本文的下一个重点是本福特的法律批判角色。这些科目是与自然存在的数字相协调的财务和会计数据。如果我们假设某人拥有价值 1000 美元的股票共同基金。他的基金要达到 2,000 美元的收益率,就必须增长 100%才能翻倍。除此之外,要从 2,000 元进一步增加到 3,000 元,只需增加 50%。正如我们之前提到的第一个数字是 4,它需要再增长 33%。正如本福特定律预测的那样,为了让第一位数字 1 变成 2,需要比 3 变成 4 有更多的增长,以此类推。事实上,本福特分布是一个“分布”,金融项目有一种安慰的倾向。

安然公司:这是本福特定律的一个重要例证,它揭露了大企业在财务数据上的偏差。这个例子来自安然公司,它对会计欺诈进行了规范,如下图所示。2001 年安然的灾难是当时历史上最大的灾难,其结果导致许多首席执行官入狱。

Frequency of first digits from Enron’s financial data vs certain frequency based on Benford’s law (after the Wall Street Journal)

在这篇文章中,我选择了最*选举中公开的两个特定数据集。第一个是【2016 年美国总统选举第二个来自【2018 年俄罗斯总统选举。

对于我的第一个项目,我从不切实际的 Python 项目中获取数据。我只考虑了唐纳德·特朗普和希拉里·克林顿的选票,这是伊利诺伊州 102 个县的选票。曝光的谣言声称有 500 多万人非法投票。伊利诺伊州选举官员证实,黑客访问了数千份记录,但据称他们没有损害任何数据。第二个数据集可以在 Kaggle 上找到。

本福特拟合优度测试

假设

1.这些数字需要是随机的,没有分配,没有强加的最小值或最大值。

2.这些数字应该覆盖几个数量级,数据集应该很大。文献中的建议要求至少有 100 到 1,000 个样本,尽管本福特定律已被证明适用于仅包含 50 个数字的数据集。

卡方检验

为了用 Benfardw 定律进行模拟,通常使用的拟合优度检验是卡方检验,这是一种经常使用的方法,用于确定经验(观察到的)分布是否与理论(预期的)分布显著不同。让我们假设零假设:

何:观测分布和理论分布相同

使用的显著性水*(p 值)为 0.05。

【2016 年美国大选

首先,我们导入一些库

#import libraries
import numpy as np
import pandas as pd
import sys
import math
import matplotlib.pyplot as plt

而且,我们加载我们的数据,提供一部分 EDA。

def load_data(filename,var):
        df=pd.read_excel(filename)
        data=df[var]
        return df,data

#Data exploratory       
data.describe()
df.info()
df.describe().transpose
df.isnull().sum()

下一步是创建一个函数,该函数将列的字符串名称作为参数,例如“Trump”。输出结果是观察数据的第一个数字,1,2,3,4,5,6,7,8 和 9,总量和每个前导数字出现的百分比。

def count_first_digit(data_str):
    mask=df[data_str]>1.
    data=list(df[mask][data_str])
    for i in range(len(data)):
        while data[i]>10:
            data[i]=data[i]/10
    first_digits=[int(x) for x in sorted(data)]
    unique=(set(first_digits))#a list with unique values of     first_digit list
    data_count=[]
    for i in unique:
        count=first_digits.count(i)
        data_count.append(count)
    total_count=sum(data_count)
    data_percentage=[(i/total_count)*100 for i in data_count]
    return  total_count,data_count, data_percentage# Benford's Law percentages for leading digits 1-9
BENFORD = [30.1, 17.6, 12.5, 9.7, 7.9, 6.7, 5.8, 5.1, 4.6]

如你所知,在这一步之后,我们列出了本福特定律的预期百分比,然后继续进行卡方检验。

def get_expected_counts(total_count):
    """Return list of expected Benford's Law counts for total sample count."""
    return [round(p * total_count / 100) for p in BENFORD]
expected_counts=get_expected_counts(total_count)def chi_square_test(data_count,expected_counts):
    """Return boolean on chi-square test (8 degrees of freedom & P-val=0.05)."""
    chi_square_stat = 0  # chi square test statistic
    for data, expected in zip(data_count,expected_counts):

        chi_square = math.pow(data - expected, 2)

        chi_square_stat += chi_square / expected

    print("\nChi-squared Test Statistic = {:.3f}".format(chi_square_stat))
    print("Critical value at a P-value of 0.05 is 15.51.")    
    return chi_square_stat < 15.51
chi_square_test(data_count,expected_counts)

我们测试的第一位候选人是唐纳德·特朗普,正如你在下图中看到的那样,通过更仔细地观察卡方检验结果,我们很遗憾地拒绝了零假设,并理解在 5%的风险下,投票似乎没有错。然后我们创建主定义为了汇总所有结果,你可以在我的GitHub-eleprocha/Ben Ford-s-Law _ python _ code中找到代码。

【2018 年俄罗斯总统选举

数据。我们在第二个数据集中使用相同的方法,可以在 Kaggle 上找到。首先,我们必须使用 df.head()显示数据帧的形状;输出如下所示:

EDA。为了探究这个数据集,我们使用了一个非常流行的 Python 库, Plotly 更具体地说,我们为一些参赛者的选票分布创建直方图、箱线图和散点图。

#Plot.ly
#standart plotly imports
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import iplot,init_notebook_mode

import cufflinks
cufflinks.go_offline(connected=True)
init_notebook_mode(connected=True)

df3['Grudinin Pavel Nikolaevich'].iplot(kind='hist',xTitle='Grudinin Pavel Nikolaevich ',
yTitle='count votes',title='Votes Distribution of Grudinin Pavel Nikolaevich')

df3['Putin Vladimir Vladimirovich'].iplot(kind='hist',xTitle='Putin Vladimir Vladimirovich ',yTitle='count votes',
                                          title='Votes Distribution of Putin Vladimir Vladimirovich',colors='blue')

df3[['Baburin Sergei Nikolaevich','Grudinin Pavel Nikolaevich',
     'Zhirinovskiy Vladimir Volfovich','Putin Vladimir Vladimirovich']].iplot(kind='hist',histnorm='percent',barmode='overlay',
                                                                              xTitle='Votes',yTitle='(%) of candidates',title='Votes Distribution')

df3[['Baburin Sergei Nikolaevich','Grudinin Pavel Nikolaevich',
     'Zhirinovskiy Vladimir Volfovich','Putin Vladimir Vladimirovich']].iplot(kind='box',yTitle='Votes',title='Boxplots')

df3[['BaburiSergeiNikolaevich','',
     'Zhirinovskiy Vladimir Volfovich','Putin Vladimir Vladimirovich']].iplot(kind='scatter',yTitle='Votes',title='Boxplots')

对本福德定律的模拟。老实说,与美国大选的数据集相比,找到一个给出完全相反结果的数据集并不容易…但在这种情况下,我们检查了其中一名跑步者的选票,为了避免任何公开争议,我不会透露他的名字——令人惊讶的是,输出是负面的。换句话说,我发现了一个具有统计显著性的 p 值,因此拒绝了零假设——这意味着分布彼此相差如此之大,以至于存在操纵数据的巨大可能性!!!

ouput:Chi-squared Test Statistic = 9570.310
Critical value at a P-value of 0.05 is 15.51.
Out[8]: False

感谢您的宝贵时间!

机器学习的免费数据集

原文:https://towardsdatascience.com/free-data-sets-for-machine-learning-73e74554cc21?source=collection_archive---------8-----------------------

查找公开可用数据集的 5 大资源

Photo by William White on Unsplash

我非常喜欢通过实际应用来学习。我发现,在研究机器学习时,获得一些公开可用的数据集来应用我学到的最新技术真的很有用。或者,在处理真实数据集之前,您可能需要一个非常简单的数据集来测试解决方案或比较不同的算法。

在下面的帖子中,我将列出我发现的获得机器学习应用程序完全免费数据集的最佳资源。

UCI

UCI 机器学习库目前有 476 个公开可用的数据集,专门用于机器学习和数据分析。数据集被有用地标记了类别,例如分类、回归、推荐系统等,因此你可以轻松地搜索数据集来实践特定的机器学习技术。

几乎所有的数据集都来自真实世界(与玩具数据集相反),这意味着你将遇到与真实机器学习项目中面临的挑战类似的挑战。有非常广泛的主题可供选择,并且所有的数据集都已经过研究,这意味着它们有可能在模型中产生良好的结果。

UCI Machine Learning Repository

卡格尔

Kaggle 是机器学习数据集的另一个重要资源。目前,在这个页面上列出了 19515 个数据集。Kaggle 的一个优点是,在每个数据集的登录页面上都有数据预览。因此,您可以在下载之前快速想象您将要处理的数据类型。

使用 Kaggle 的好处是,您经常会发现许多与每个数据集相关的内核。在这些区域中,其他用户会显示处理数据的代码示例,这是一个很好的入门方式。此外,许多数据集在过去与排行榜的比赛相关联或曾经相关联。这提供了一个很好的资源来衡量你的模型相对于其他用户的表现。

Kaggle

sci kit-学习

Scikit-learn 拥有各种各样的玩具和现实世界的数据集。它们可以使用通用数据集 API 获得。它们非常容易获得和操作,可以准备好训练模型,并且可以是在将它们用于真实世界数据之前对解决方案进行基准测试或评估不同算法的好方法。

玩具数据集可以通过以下方式获得(以波士顿房价为例)。

from sklearn.datasets import load_boston
boston = load_boston()

下面是一个简单的例子,说明如何使用这个数据集来训练和评估一个模型。

from sklearn.linear_model import LinearRegression
from sklearn.metrics import median_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_bostonboston = load_boston()X_train, X_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=1)regr = LinearRegression()
regr.fit(X_train, y_train)
y_pred = regr.predict(X_test)
print(r2_score(y_test, y_pred)) 
print(median_absolute_error(y_test, y_pred))

真实世界的数据集可以被获取,如下图下面的所示。

from sklearn.datasets import fetch_20newsgroups
dataset = fetch_20newsgroups()

Drivendata.org

这个网站主办旨在解决社会问题的机器学习竞赛。每个竞赛都附有一个数据集,可以从网站上下载。它们从非常简单的(献血)到更复杂的(有故障的水泵)不等,并且可以是从各种领域和复杂程度的数据中获得实践的好方法。

Drivendata.org

五三八

以发表基于分析数据的文章而闻名的 538 已经通过 Github 公开了他们的数据集。这里有广泛的数据集,涵盖了许多不同的领域。每个数据集都有一个自述文件,其中包含一个数据字典和一些关于数据源的信息。这是一个访问一些不同寻常的数据集进行实践的好地方。

FiveThirtyEight

还有很多其他地方可以获得机器学习项目的数据,包括政府网站、研究中心和大学(这是一个很棒的列表)。然而,我上面列出的资源可能是获得专门为机器学习目的而整理的数据集的最佳地方。

感谢阅读!

生成机器学习中的恶魔决定论

原文:https://towardsdatascience.com/free-will-clairvoyant-demons-and-determinism-45904c354124?source=collection_archive---------24-----------------------

数据科学之道

决定论,生成机器学习,以及人类(或机器)的自由意志是否可能

数据科学之道 专栏探讨了几个世纪以来哲学家们是如何攻克机器学习和数据科学的关键问题的。

Laplace provided an interesting insight into generative machine learning

拉普拉斯的恶魔

皮埃尔·西蒙·拉普拉斯认为一切都是由原子组成的,牛顿物理学支配着原子的运动。作为一个思想实验,拉普拉斯想象了一种拥有两种知识的超视力恶魔:

  • 恶魔知道宇宙中所有粒子的所有位置和速度的初始条件;
  • 恶魔知道所有的(牛顿)物理定律。

拉普拉斯认为,有了这种知识,恶魔可以正确地预测宇宙中所有物质身体的任何事情,包括你。它通过从初始条件开始,并使用确定性物理定律向前投射来实现这一点。

在机器学习模型中构建恶魔决定论

生成机器学习用概率对不确定性建模。回想一下落在牛顿头上的苹果,它启发了他的物理学概念。假设我们想知道那个苹果的重量。

下面是一个简单的生成式机器学习模型对苹果称重的过程,我们可以用它来估计重量:

苹果 _ 重量~正常(μ,σ)
测量~正常(苹果 _ 重量,ε)

这里的“正态”是指正态(高斯)概率分布。如果这对你来说是新的,就把它想象成一个特定味道的随机发生器。如果你不熟悉“~”符号,它表示左手边的对象“来自”右手边的概率分布。要从该模型生成,您可以通过模拟右侧的分布,为左侧的对象分配一个值。为了估计苹果的重量,你需要进行实际测量,并使用这个模型来推断苹果的重量,也许使用类似贝耶法则的东西。

把这个模型读作英语,我们用秤来测量苹果的重量。由于没有秤经过完美校准,我们区分报告的测量值和真实的苹果重量。我们对这个关于真实的苹果重量的不确定性来源(通常称为技术噪声)进行建模,给出以真实的苹果重量为中心的正态分布的测量值,并带有一些噪声参数ε。而且,我们也不确定 apple_weight 本身。所以我们用一个先验来模拟这种不确定性——一个基于所有苹果的一些*均重量和重量变化的概率分布。在这种情况下,先验是具有均值μ和标准差σ的正态分布。

这个模型违背了拉普拉斯的宇宙决定论观点。如果测量值偏离 apple_weight ,这是因为秤本身的物理特性产生了某种确定性过程。即使我们不知道这些特征是什么,我们仍然应该能够看到这种确定性机制在模型中出现。

让我们用一个简单的数学变换来改变这个模型。

初始条件

Z1 ~正常(0,1)
Z2 ~正常(0,1)

确定性

apple _ weight =σ* Z1+μ
measurement =ε* Z2+apple _ weight

如果您不熟悉数学,所有这些转换都是利用了数学事实,即任何正态(高斯)随机变量都只是标准化正态随机变量(Normal(0,1))的线性转换。换句话说,这个模型在数学上等同于第一个模型。然而,这在哲学上是非常不同的。这里 apple_weight 和 measurement 是一些初始条件的确定性函数,用 Z1 和 Z2 表示。我们用先验正态(0,1)表示的不确定性,只在初始条件的上下文中表达。因此,我们有决定论,但仍然承认我们不如魔鬼那样有洞察力。

事实上,这种建模方法(称为结构因果模型)允许直接在模型中构建更微妙的确定性物理。例如,也许不使用线性变换,我们可以详细描述导致测量值稍微偏离真实值的物理机制。让我们用函数 g(来表示这个。).

初始条件

Z1 ~正常(0,1)
Z2 ~正常(0,1)

确定性

apple_weight = σZ1 + μ
度量= g(apple_weight,Z2)

同样,如果您是一名在 Fitbit 工作的工程师,您可能知道人体解剖结构的变化导致的不确定性如何与设备中的机械和数字组件相结合,从而导致报告的步数偏离实际步数。

概括地说,这里的 g 可以将不确定的初始条件与某种确定的自然关系结合起来,例如欧姆定律(V = IR)或质能等效性(E = MC)。我们甚至可以把它扩展到抽象的“物理学”比如经济学中的供求定律,或者围棋这样的游戏规则。

自由意志呢?

许多哲学家认为决定论与自由意志不相容。如果宇宙的初始条件决定了你身体的运动,那么你是做俯卧撑,还是写一篇中等文章,还是口型说“我爱你”,怎么可能由你决定?他们的结论是,要么决定论是错误的,要么自由意志是一种幻觉。

但是量子力学呢?

许多人认为现代物理学告诉我们,量子力学的基本定律不是确定性的,而是概率性的。一些哲学家认为量子力学定律不仅解决了自由意志的问题,甚至为意识提供了基础。量子力学对机器学习和人工智能的哲学意义值得单独发表。

然而,就预测建模方法的选择而言,我相信奥卡姆剃刀适用——对你的模型来说,最好假设宇宙是确定性的,除非你明确地建模一些量子级变化很重要的现象。你当然不需要理解量子引力来模拟一个苹果的重量。

相关阅读

  • 哥德尔不完全性定理及其对构建强人工智能的启示 —数据科学之道
  • 概率因果模型 —斯坦福哲学百科全书
  • 因果决定论 —斯坦福哲学百科全书
  • 年轻的思想家现在认为自由意志是真实的——思想很重要
  • 是的,决定论者,有自由意志。即使你的原子没有做出选择,你也会做出选择。 —鹦鹉螺

将数据科学家从矢量化的魔咒中解放出来

原文:https://towardsdatascience.com/freeing-the-data-scientist-mind-from-the-curse-of-vectorization-11634c370107?source=collection_archive---------10-----------------------

朱莉娅来救我们了。

Photo by Debby Hudson on Unsplash

现在,大多数数据科学家使用 Python 或 R 作为他们的主要编程语言。这也是我的情况,直到今年早些时候我遇到了朱莉娅。Julia 承诺了与静态类型编译语言(如 C)相当的性能,同时保持了解释语言(如 Python、R 或 Matlab)的快速开发特性。这种性能是通过实时(JIT)编译实现的。Julia 在运行时编译代码,而不是解释代码。虽然 JIT 编译已经存在一段时间了(例如, Matlab 在 2002 年引入了它),但 Julia 是为 JIT 编译的性能而设计的。类型稳定性和多分派是 Julia 中的关键设计概念,使其在竞争中脱颖而出。如果你想了解更多,加州大学数据科学倡议有一本非常好的笔记本,它解释了这些概念。

在某个时候,我们开始使用解释语言来处理大型数据集(我猜数据集变得越来越大,我们一直使用相同的工具)。我们了解到,为了提高性能,我们希望避免循环和递归。相反,我们希望使用矢量化的操作或专门的实现,将数据结构(如数组、数据帧)作为输入,并在一次调用中处理它们。我们这样做是因为在解释语言中,我们每次执行一条指令都要付出额外的开销。虽然我很喜欢用 R 编写代码,但这涉及到一套避免循环和递归的策略,而且很多时候我的努力都指向了“如何避免解释语言的陷阱?”。我开始编写 C 函数来解决 R 脚本中的瓶颈,虽然性能明显提高了,但是使用 R 的优势却消失了。那时我开始寻找替代品,我找到了朱莉娅。

在这篇文章中,我们将从解决一个简单的 R 问题开始,在这里我将试着说明用解释型语言编程时的思维模式和局限性。然后,我们将解决与 Julia 相同的问题,展示思维模式如何完全不同,以及如何实现开箱即用的类似 C 的性能。

矢量化途径

有时不清楚如何使用矢量化获得最佳性能。

让我们考虑这样一个问题:给定一个点的矢量,求所有点对组合之间的距离。为了简单起见,点是一维的,我们将使用 L1 距离。给定输入[5,3,9,1],预期输出为[2,4,4,6,2,8](由| 5–3 |,| 5–9 |,| 5–1 |,| 3–9 |,| 3–1 |和| 9–1 |产生)。

这个问题在 R 中使用stats包的dist函数解决了:

> as.vector(**dist(**c(5, 3, 9, 1), method=”manhattan”**)**)
[1] 2 4 4 6 2 8

r 的实现返回一个距离矩阵,我们将它转换成一个向量。

Distance matrix: gray cells are redundant

让我们假设dist不可用。你如何用 R 来编码它?

用基于循环的方法解决这个问题很简单:我们需要一个外部循环来迭代对中的第一个元素,需要一个内部循环来迭代第二个元素。由于 L1 距离是对称的(| a-b| = |b-a| ),我们只需要对一半的组合这样做,同时避免计算点到它们自己(矩阵的对角线)的距离。R 中基于循环的实现如下所示:

如果你用 R 编程,你会说这不是合适的 R 代码…循环很慢,产生非常冗长的代码…应该有一种向量化的方法。

丢弃环路的一种方法是用所有对的组合生成向量。基本上,我们正在寻找距离矩阵的下三角形的(行,列)坐标。然后,我们可以通过一次矢量化运算来计算距离。我们知道我们付出了内存代价,但是我们希望矢量化能够有所回报。

另一种选择是使用 R 的outer函数来生成具有两点的所有组合(包括冗余组合)之间的差异的矩阵。然后,我们只需要检索矩阵的下三角部分的绝对值。我们可能会感到不情愿,因为我们正在进行大约 2 倍多的操作(并将它们存储在内存中),但这确实会产生更干净、更可读的代码。

随着我们沿着向量化的道路前进,代码变得越来越紧凑,但是它变得更快了吗?我们通过更多的内存和更多的操作来交换紧凑性…预测这些实现中哪一个是最有效的并不容易。

当我们已经有了一个简单的基于循环的解决方案(在编译语言中很难超越)时,我们可以继续尝试找出避免 R 陷阱的最佳方法。因此,如果这个函数是性能关键的,那么用 C、CPP 或 Fortran 实现它可能是有意义的。原始实现的 CPP 翻译,通过 Rcpp 库与 R 集成,如下所示:

实验

我用 10.000 个随机数的向量运行了不同的实现 3 次(需要 49.995。000 的距离计算,否则为 100.000.000)并取 CPU 时间和内存消耗的中间值。我用的是 2017 款 MacBook Pro,2.3 GHz 英特尔酷睿 i5,16 GB 内存运行 Mac OS 10.14,R 3.6.0,Julia 1.0.3,XCode 10.1。

正如所料,R 中基于循环的实现是最慢的(在 JIT 可用的 3.4 版之前会慢得多)。通过矢量化,我们减少了计算时间,但增加了内存消耗,随着输入大小的增加,这可能会成为一个问题。即使在我们的矢量化努力之后,我们仍然远远没有达到 R 的dist函数的性能。

Rcpp 允许减少计算时间和内存需求,优于 R 的核心实现。这并不奇怪,因为 R 的dist函数更加灵活,增加了几个选项和输入验证。虽然我们可以将 C/CPP 代码注入到 R 脚本中是一件好事,但现在我们正在处理两种编程语言,我们已经失去了 CPP 代码的交互式编程的好处。

朱莉娅的方式

Julia 的编程思维与 R 的完全不同。最有效的解决方案是通过基于循环的方法来预分配内存。

如果你想写更少的代码,你可以牺牲计算效率。压缩代码的一种方式是通过理解。

上述理解比基于循环的实现更紧凑,同时体现了相同的逻辑。这种方法的主要缺点是输出向量不是预先分配的。由于编译器无法预测输出的大小,因此输出会根据需要动态增长。

最后,如果您喜欢矢量化方法,在 Julia 中也可以选择。基于outer函数翻译 R 的实现如下所示:

与 R 不同,我们认为这是效率最低的方法,因为它需要更多的内存和不必要的(冗余)操作。

结果

Julia 通过提供开箱即用的类似 C 语言的性能而脱颖而出。代码紧凑性和效率之间的权衡非常明显,类似 C 的代码提供类似 C 的性能。理解是一个很好的折衷方案,因为它们更容易编码,更不容易出错,并且对于这个问题同样有效。

当使用 R 处理计算密集型任务时,我们希望找到一个专门的函数来解决我们的问题。如果一个专门的函数不可用,我们要么需要用 C/CPP 编程,要么通过矢量化途径。如果我们选择第二种,我们可能会远远达不到第一种方法的效果。

结束语

矢量化、理解、地图过滤-简化都是很好的工具,可以节省您的时间,并提供更紧凑和可读的代码。然而,程序员不应该因为编程语言的性能限制而被迫使用它们。当有一个简单而有效的实现时,您不希望花费时间尝试几种方法来实现解决方案。

Julia 允许您在代码紧凑性和计算效率之间进行选择,使得这种权衡非常明显。您可以实现类似 C 的循环、类似 R 的向量化或类似 Python 的理解。这取决于你。您可以优化解决方案编码所需的时间和解决方案运行所需的时间之间的比率。你可以实现自己的算法,而不需要依赖第二语言。

由于比 Python 和 R 年轻得多,Julia 正在数据科学社区中奋力拼搏。我喜欢 13 年前开始使用 Matlab 的时候,因为我可以与数据交互。我现在喜欢如何更快地编写更快的代码,以及如何在 Julia 中自由地实现几乎任何算法。试试吧,我相信你也会喜欢它的!

代码可在:【github.com/dcmoura/blogposts

你可以在推特、 LinkedIn 和 Vimeo 上找到我(查看我的数据 vizs!)

2018 年伦敦 Frieze 展(第三部分):计算机视觉

原文:https://towardsdatascience.com/frieze-london-2018-part-3-computer-vision-50314f2f4b1?source=collection_archive---------15-----------------------

第 3 部分:使用计算机视觉分析 9k 社交媒体图像

介绍

在这一系列的最后一篇博文中,我应用计算机视觉技术来理解 2018 年 10 月 4 日至 7 日举行的 Frieze 伦敦艺术博览会的 9000 张图像。

Frieze 是每年十月在伦敦摄政公园举办的大型当代艺术博览会,吸引了成千上万的人。来自 20 多个国家的 150 多家画廊参加了盈利性艺术博览会。在过去的几年里,Frieze 还在公园里开创了一个雕塑展。

在本系列的第二部分和第一部分中,我展示了对 9000 篇关于展会的社交媒体帖子的自然语言处理和探索性数据分析。本文的目的是使用计算机视觉分析来理解和联系9000 张关于 2018 年伦敦奥运会的图片。

请向下滚动查看分析!

数据和方法

这一事件的官方标签是#frieze。在事件发生时,我通过 Twitter API 和 Instagram API 收集了 9000 个包含这个标签的帖子。阅读第 2 部分了解更多。

然后,使用谷歌云的视觉 API 提取每张图像的标签。Cloud Vision API 利用“谷歌庞大的机器学习专业知识网络”(g reat article 作者 Sara Robinson )来检测图像的特征和标签。总共有 1045 个不同的标签被赋予了 3300 张图片。

被称为特征提取反向图像搜索的机器学习技术然后使用基因科岗的代码完成,以基于视觉相似性找到图像。首先,使用预训练的卷积神经网络来提取每幅图像的“特征”,然后,计算这些特征的余弦相似度,以“搜索”与查询图像相似的少量图像。

特征在计算机视觉中的主要作用是“将视觉信息转换到向量空间”。相似的图像应该产生相似的特征,我们可以利用这些特征进行信息检索。基于这些特征,我们还可以使用一种叫做 t-SNE 的方法通过相似性对图像进行聚类。

图像分析

在这一节中,我将展示我的计算机视觉分析的结果。下面,我报告以下三个指标:

  1. 图像的标签检测;
  2. 基于视觉相似性的图像搜索:
  3. 基于视觉相似性的图像聚类。

标签检测

每张照片的标签都是使用谷歌云视觉 API 生成的。这背后的想法是将图片分类,这样我就可以识别相似的图片。下面的条形图显示了 3,300 张图片的前 10 个标签。

我们看到,“艺术”是最常见的标签,其次是“现代”、“绘画”和“艺术品”。但是看到“树”、“草”和“天空”出现也很有趣,因为它表明许多图像是关于雕塑公园的(我们将在后面看到更多)。

然而,这些标签并没有明确描述艺术品本身——我对稍微详细一点的上下文理解感兴趣——这凸显了一些 API 标签检测技术的缺点。

图像搜索—视觉相似性

我们可以通过编程让计算机学习图像之间的视觉相似性,而不是使用标签来理解图像。一种叫做特征提取反向图像搜索的技术就是这样做的。

使用在 TensorFlow 后端上运行的 Keras VGG16 神经网络模型,我首先为数据集中的每张图像提取了一个特征。一个特征是每个图像的 4096 元素的数字数组。我们的期望是“该特征形成图像的非常好的表示,使得相似的图像将具有相似的特征”(吉恩·科岗,2018 )。

然后使用主成分分析(PCA)降低特征的维度,以创建一个嵌入,然后计算一个图像的 PCA 嵌入到另一个图像的距离余弦距离。我终于能够向计算机发送随机查询图像,它选择并返回数据集中具有相似特征向量的五个其他图像。

以下是四个例子:

Richard Woods, ‘Holiday Home’ Alan Cristea Gallery (left) and Conrad Shawcross, ‘Optic Labyrinth (Arrangement I)’, Victoria Miro (right) at Sculpture Park

David Shrigley, Distractions (2018) and “My Artwork is Terrible and I am a Very Bad Person”, Stephen Friedman Gallery at Frieze London Art Fair 2018

当试图从一个包含许多图片的相册中找到相似的图片时,这种技术非常有用,事实上我就是这么做的!

图像聚类—相似性

既然我们在向量空间中嵌入了每个图像,我们可以使用一种流行的叫做 t-SNE 的机器学习可视化算法来聚类,然后在二维空间中可视化向量空间。

“tSNE 的目标是聚集相似数据点的小“邻域”,同时减少数据的整体维度,以便更容易可视化”(谷歌人工智能博客,2018 年)

下面我们看到基于视觉相似性的聚类形成。

在下面的图片中,我突出了一些来自博览会的艺术品——大卫·施莱格利的分心,塔蒂亚娜·特鲁夫的萨满和来自弗里兹雕塑公园的各种雕塑——以及它们的集群简介。

The clustering of images of works of art at Frieze London 2018. Source: Instagram, Twitter, Flickr

结论

所以你有它!我只是刚刚涉足计算机视觉的奇妙世界。还有很多东西需要我去学习,但这对我来说是很好的第一步。

我的发现表明,使用机器学习和计算机视觉技术来理解和联系 Frieze air fair 的图像是可能的。

对我来说,下一步显然是计算在数据集中出现了多少艺术装置,以衡量“受欢迎程度”。我将继续研究这个数据集。

结束了

这是我关于 Frieze London 2018 的博客系列的结尾!这个系列是我正在进行的关于使用数据科学来理解和衡量城市文化影响的长期讨论的一部分。

今年,我将开始新的项目,主要是 JavaScript。敬请期待!

感谢阅读!

Vishal

Vishal 是伦敦 UCLThe Bartlett的文化数据科学家和研究生。他对城市文化的经济和社会影响感兴趣。

从 0 到持续交付的机器学习

原文:https://towardsdatascience.com/from-0-to-continuously-delivered-machine-learning-971a707345cf?source=collection_archive---------35-----------------------

行之有效的循序渐进的方法

Photo by Raoul Croes on Unsplash

我大概是机器学习工程师。这个领域很新,所有的职位对我来说都是一个笑话。数据科学家、人工智能专家或人工智能工程师之间的界限非常模糊,你选择放在 LinkedIn 上的人实际上遵循了个人偏好或雇佣你的人的个人偏好。无论你第一次向人们介绍自己时说什么,都不会改变你在绝大多数公司的日常工作:你收集数据,训练模型,测试它们的表现,最终,如果你幸运的话——是的,不止是好——你会部署它们,可能是在云上。不过,在过去的几个月里,我越来越关注我公司的机器学习产品的技术方面,而不是它们特定任务的性能。我和我的团队已经付出了很多努力来使它们处于良好的状态,但往往没有对它们的最终用户或我们的业务产生真正的影响(至少是直接的影响)。

如果我回顾整个旅程开始的时候,考虑到我们作为一个团队在运营中的影响以及我们的产品和人员的技术成熟度,我们目前的状况确实令人印象深刻。但事情并不是这样开始的,为了达到这一点,我们经历了一个非常线性的过程,让我们获得了牵引力、支持和知识。这篇文章不会涵盖所有的初步步骤需要准备好部署的东西,我已经这样做了这里,这里和不知何故还有这里,而是会试图揭示接下来发生的事情,以及什么对我们达到我们现在高兴的阶段很好。

部署模型

尽快起步是关键。第一阶段的目标应该是允许利益相关者评估模型的影响,并且部署不需要很花哨就能实现。唯一不能忽视的是,一旦模型投入使用,收集和比较业务指标的可靠流程。如果不存在一种方法来证明它是有用的,即使是机器学习历史上最好的模型也不会在行业中取得任何成功。通常,这些指标甚至不是的技术指标,而是更可能与团队或部门的效率相关。例如,在我们的案例中,我们允许 CS(客户解决方案)部门在一项任务上花费的时间减少了 50%,而他们的效率提高了 80%。而且那个时候的分类器 F1 还挺差的,说实话。理想情况下,我们希望在完全可控和可测量的环境中拥有一个完美部署的模型,但是这从来都不是事实,尤其是在数据团队的早期阶段。在这种讨价还价的情况下,前者比后者更好。

理想情况下,我们希望在完全可控和可测量的环境中拥有一个完美部署的模型,但是这从来都不是事实,尤其是在数据团队的早期阶段。

您可以忽略的良好工程实践的数量很大程度上取决于您公司的工程文化。我的意思是,机器学习模型是一个 Python 函数。通过在路由器上启用端口转发,理论上您需要 30 秒的时间在本地机器上将它公开为 Flask API。幸运的是,我们的运营团队非常强大,他们做得非常好,让我们能够非常轻松地采用一些尖端的云技术。

我们的第一次部署是在 Kubernetes 上的一个单独的吊舱。pod 包含三个不同的容器:API、一个异步任务队列(Celery)和一个 Redis 数据库,以允许两者之间的通信。

预测任务中使用的模型存储在一个 Docker 图像中。我们没有任何可靠的流程来重新培训它,在这种情况下,我们需要重新构建和推动整个映像。我们没有收集任何技术指标(已执行作业的数量、预测作业延迟等),也没有在生产中直接发布任何暂存环境。我并不以此为荣。但老实说,我们从未觉得有更多的需求。如果我们试图在第一次部署之前解决所有这些可能的问题,我们可能永远不会有我们所拥有的影响,并且我们会在这个过程中失去动力和牵引力。

成为业务关键型

如果一切顺利,并且你关于已经部署了实际有用的东西的所有假设都是真的,那么很有可能你的模型(现在是产品——fancier)将成为商业关键。此外,业务关键是一个相当时髦的词。理解这种情况的最简单的方法是试着想想如果你的产品因为某些原因搞砸了会发生什么。如果情况不好,你在某种程度上是业务关键型的。当我们将我们的技术与我们的核心*台整合后,我们就跨越了那条线。如果你在*台上弄坏了什么东西,用户能感觉到。

了解你的产品是否对业务至关重要的最简单的方法是,试着想想如果它因为某种原因搞砸了会发生什么。

我们做的第一件事是开始在一个暂存环境中发布。测试机器学习产品是棘手的,在安全地发布到生产中之前,可能无法完全覆盖用例,但确保所有的技术组件和基本流程正常工作对于避免严重问题至关重要。如果什么东西坏了,没有人会注意到它。当然,听起来显而易见,确实如此,但是当我们甚至不确定我们的部署是否能撑过这个月时,设计这样的东西是没有用的。有趣的是,在过去 30 年中开发的工程最佳实践不仅完全适合这个新领域,而且我们实际上感觉到在这个过程中需要它们。我们没有雇用他们,只是因为有人要求我们这样做。

有趣的是,在过去 30 年中开发的工程最佳实践不仅完全适合这个新领域,而且我们实际上感觉到在这个过程中需要它们。

同一条线上是监控。如前所述,我们已经有了一个非常稳健的战略来评估业务相关的绩效,但我们完全不知道我们的部署状态工程方面的。完成一项预测工作需要多长时间?我们需要向 pod 添加更多资源吗?每天执行多少个作业?预测标签的百分比是恒定的吗?对于一个经典的 API 来说,这些度量是从一开始就收集的,没有它们就发布任何东西都是非常糟糕的做法。我们感受到了过程的紧迫性,我们得到了同样的最终结果。

One of the graphs we have created on Grafana to monitor performances.

在我们公司,我们已经在使用 Prometheus 和 Grafana 进行监控,当然,在我们的项目中也使用这些工具是有意义的。不过,这些工作的短暂性需要一点工程上的努力,必须部署并控制 Prometheus Pushgateway 来存储这些指标,并将它们暴露给共享的 Prometheus 服务器。在 QA 团队的帮助下,我们定义了警报并创建了一些漂亮的图表。为了不搞砸,我们现在采用了最好的策略,但如果真的发生了,至少我们是第一个知道的。

解耦模型

数据产品最大的资产是驱动它的模型。在几次不同的 ML 部署之后,我们意识到,除了主要与样本创建过程相关的一小部分定制代码之外,设置服务器和预测过程所需的大部分代码几乎是相同的。在另一个层面上,用 Docker 部署模型也导致了大量无用的工作,不得不构建复杂 Dockerfile 中定义的大映像,仅仅是为了改变资源的一个非常小的子集,这个子集并不严格依赖于它的实际使用方式。模型和预测逻辑可以解耦,它们的发布过程应该是不同的,而不是同步的。

模型和预测逻辑可以解耦,它们的发布过程应该是不同的,而不是同步的。

因此,我们决定将 API 和任务队列从模型和相关文件中分离出来。我们改进了代码,以便在预测过程开始时异步检索这些资源,从云对象存储(在我们的例子中是 GCS)中获取它们。当然,这种改进也需要一个新的图像来处理逻辑,但从那以后我们没有发布任何新版本。服务一个新的模型现在实际上就是将它存储在桶中,并在我们的配置存储库中提出一个 PR,使用我们在这个项目的整个发展过程中使用的相同的 GitOps 方法。

这一步使我们能够不费吹灰之力地按照自己的意愿对模型进行多次重新训练。然而,发布模型版本的任务正是这个领域中的部署与传统工程部署的不同之处。描述流程和编写测试是非常简单的(即使有些复杂和无聊)。如果一个发布候选通过了它们,那就可以开始了。对于数据产品是非常不同的。当然,检查作业调度逻辑是否如预期的那样运行是可能的,但是判断一个列表是否是一个骗局是完全不同的事情。

在这一点上,我们需要的是一种方法来确保(足够)重新训练的模型在实时数据上的表现与当前部署的一样好,甚至更好。当然,并行地为模型服务几天并监控它们的性能工作得很好,但是执行任务所需的时间和精力经常开始成为我们团队的瓶颈。在我们的大多数设置中,简单的离线性能估计不足以验证模型,因为发送用于预测的数据可能不同于几天后从我们的数据源中检索的数据。我们设计了一个特定于任务的测试框架,将重新训练的模型暴露给部署模型使用的相同数据。在定义培训日期时采用一个聪明的策略,我们可以模拟模型的发布,并在 10 秒钟内,而不是 2 天内,对重新培训版本的实际性能进行非常可靠的评估。一个非常细粒度的日志记录策略对于实现这一目标至关重要:预测过程的所有阶段和结果都被存储起来,并可以在需要时访问。

我们安排了一个两周一次的 cronjob,创建一个 pod 并重新训练模型,如果发布模拟进行得很顺利,可能会保存它,并通知团队结果。然后发布新的模型(先试运行,后生产),编辑 Kubernetes 上的配置文件。包含预测逻辑的 pod 重新启动,并从存储桶中获取重新训练的版本,完全不知道其内容。

我们当前的设置允许我们完全专注于改进实际的机器学习引擎,并有非常明确的责任分离。整个过程花费了大约 8 个月的时间,我们成功地为我们的用户提供了良好的服务,没有任何停机或延迟。所有这些有多少被他们注意到了?可能是零。机器学习工程,如果存在的话,可能是这样的:在最终用户不会注意到的数据产品上做一些事情,但这些事情让世界变得更适合居住。

机器学习工程,如果存在的话,可能是这样的:在最终用户不会注意到的数据产品上做一些事情,但这些事情让世界变得更适合居住。

没有 【德安沛 的帮助,很多事情都不可能实现。

用 R 从 0 到机器学习

原文:https://towardsdatascience.com/from-0-to-machine-learning-with-r-d339a8be6004?source=collection_archive---------12-----------------------

R 编码,数据帧,应用模型之旅。

我最*参加了一个使用 R 的项目,我来自 Python,不得不花几天时间研究 R 文档。对于初学者来说,R 文档不像 Python 那样友好,一开始把它们放在一起可能会很痛苦。

然而,网上有很多很棒的资源:

  • 文档是我最常用的网站,一旦你熟悉了语法和搜索引擎,它就是一座金矿。
  • Datacamp 是从 R(甚至 Python)开始的好地方。每周都有新的内容,还有一些不错的特色,比如项目和挑战。

本文收集了从原始数据文件应用机器学习模型的所有元素和概念,其中 r。

让我们从 R 开始,选择一个数据集并开始沿着代码片段工作。

入门指南

在你的电脑上安装 R 语言。
安装一个免费完整的 IDE : RStudio 。

图书馆

R 基本安装并不附带每个库,就像 Python 中的 pip 一样,新的库是用这个命令安装的,在 R 终端中:

install.packages(tidyverse) # For installing tidyverse

安装软件包后,以下是对库的一些操作:

library(readr) # Load library# Load multiple libraries
p.names <- c(‘xgboost’, ‘caret’, ‘dplyr’, ‘e1071’)
lapply(p.names, library, character.only = TRUE) installed.packages()                # List available packages
remove.packages("tidyverse")   # Uninstall a package# Getting help and documentation
?functionName
help(functionName)
example(functionName)

写一些代码

变量

定义变量非常简单,我们同样使用" = "或"

# Create new variables
my_var <- 54
my.data.vector = c(34, 54, 65)# Clean a variable
my_var <- NULL

Functions

Functions in R are similar to Python functions :

  • Assign the function like you would assign a variable.
  • Use the 函数 关键字,参数在括号内。
  • 使用 回车 作为退出点

下面这个名为 prod_age,的小函数以 creation_date 为参数。对于 if 语句,我们处理空情况,否则我们将值转换为 date。

prod_age <- function(creation_date) {
 if (is.na(creation_date)) {return(as.numeric(-1))}
 else {return(as.Date(creation_date))}
}

使用数据框架

加载数据,读取文件

readr 库中的 read_delim 函数提供了很多工具来读取大多数文件类型。

在下面的例子中,我们指定了每一列的数据类型。该文件有 56 列,我们希望所有列都作为字符读取,所以我们使用带有“c…c”的 col_types 参数,每个字符对应一列。

# Load the library
library(readr)# Create dataframe from CSV file
my_dataframe <- read_delim(“C:/path/to/file.csv”,
   delim = “|”,
   escape_double = FALSE,
   col_types = paste(rep(“c”, 56), collapse = ‘’))

设置数据帧的子集

不仅在导入数据集时会遇到数据帧。有时函数结果是数据帧。子集的主要工具是括号操作符。

  • 要访问特定的列,使用$运算符,非常方便。
y_train <- my.dataframe$label
  • 为了访问特定的行,我们使用[]操作符。您可能熟悉这个语法:【行,列】
# Works with numeric indices
y_train <- my.dataframe[c(0:100), 8]# Works with negative indices to exclude
y_test <- my.dataframe[-c(0:100), 8]
  • 这是另一种仍然使用括号语法的技术。和命名的运算符的用于子集化行和列。
filtered.dataframe <- my.dataframe[
   which(my.dataframe$col1 == 2),     # Filter rows on condition
   names(my.dataframe) %in% c("col1","col2","col3")] # Subset cols
  • subset 函数:第一个参数是 dataframe,然后是行的过滤条件,然后是要选择的列。
filtered.dataframe <- subset(
   my.dataframe, 
   col1 == 2, 
   select = c("col1","col2","col3"))

dplyr 图书馆

plyr 是一个流行的数据操作库。由此产生了 dplyr 包,它为最常见的数据操作挑战引入了一种语法。

如果您来自 Python,您可能熟悉用点号链接命令。在这里,你可以用一个特殊的管道做同样的事情: % > %。以下是文档中的一些示例:

starwars %>% 
  filter(species == "Droid")starwars %>% 
  select(name, ends_with("color"))starwars %>% 
  mutate(name, bmi = mass / ((height / 100)  ^ 2)) %>%
  select(name:mass, bmi)starwars %>% 
  arrange(desc(mass))starwars %>%
  group_by(species) %>%
  summarise(
    n = n(),
    mass = mean(mass, na.rm = TRUE)
  ) %>%
  filter(n > 1)

dplyr 其实对于数据的筛选和探索非常方便,语法也很直观。

修改列值

包,它为最常见的数据操作挑战引入了一种语法

修改列值

创建 dataframe 对象时,我们使用$操作符访问特定的列。

# Filtering rows based on a specific column value
my_datarame <- subset(my_dataframe, COLNAME != ‘str_value’)# Assign 0 where column values match condition
non_conformites$REGUL_DAYS[non_conformites$REGUL_DAYS_NUM < 0] <- 0# Create new column from existing columns
table$AMOUNT <- table$Q_LITIG * table$PRICE# Delete a column
my_dataframe$COLNAME <- NULL

将函数应用于列

一旦我们准备好了数据帧和函数,我们通常需要对列应用函数,以应用转换。

这里我们使用应用操作符。我们用它对结构化数据的 blob 进行操作,所以它不局限于数据帧。当然,每个点必须具有相同的类型。

# Product age function
prod_age <- function(creation_date) {
 if (xxx) {return(as.numeric(-1))}
 else { return(as.Date(creation_date))}
}# Apply function on column
mytable$PRODUCT_AGE <-
 apply(mytable[,c(‘DATE_CREA’), drop=F], 1, function(x) prod_age(x))

使用日期

当处理日期时,第一步是从日期字符串到日期对象。为。Date 函数正是这样做的,并使用指定的格式进行解析。在本文的最后,你会发现每一种日期格式都可以用于格式的自变量。

# Convert a column into date format
sales$date_f <- as.Date(sales$date, format = ‘%d/%m/%Y’)# Create column from time difference
mytable$REGUL_DAYS = as.numeric(difftime(
 strptime(mytable$closing, “%Y-%m-%d”),
 strptime(mytable$opening, “%Y-%m-%d”),
 unit=”days”))

导出数据框架

几个内置函数允许将数据帧作为文件写入。一种非常常见的格式是 CSV。但是,RDS 格式被优化(序列化+ Gzip 压缩)以存储任何 R 对象。

# Write to CSV
write.csv(non_conformites,
 ‘C:\\Users\\path\\export.csv’,
 row.names = FALSE)# Write to RDS
saveRDS(
 feature_importance_values,
 file=”c:/path/folder/feature_importance.RDS”)

测绘

就像 Python 一样,R 附带了几个用于绘制数据的库。 plot 函数其实和 python 的 plt.plot 差不多。

RStudio 对于绘图非常方便,它有一个专用的绘图窗口,可以返回到以前的绘图。

折线图

plot(
 ref_sales$Date, ref_sales$Sales,
 type = ‘l’,
 xlab = “Date”, ylab = “Sales”,
 main = paste(‘Sales evolution over time for : ‘, article_ref)
)

各种图表

r 是统计学家的语言,它带有各种绘制数据分布的图表。

values <- c(1, 4, 8, 2, 4)
barplot(values)
hist(values)
pie(values)
boxplot(values)

机器学习:XGBoost 库

xgboost 包是一个很好的起点,因为它有很好的文档记录。它使我们能够快速了解数据集,如特征重要性,我们将在下面看到。

对于这部分,我们需要那些具体的库:

  • xgboost :让我们围绕 XGB 著名算法展开工作。
  • 脱字符:分类和回归训练,包括许多数据处理函数
  • dplyr :一个快速、一致的工具,用于处理内存中和内存外的类似数据帧的对象。

列车测试分离

准备好数据帧后,我们使用索引(inTrain)将其分为训练集和测试集:

set.seed(1337)
inTrain <- createDataPartition(y = my.dataframe$label, p = 0.85, list = FALSE)X_train = xgb.DMatrix(as.matrix(my.dataframe[inTrain, ] %>% select(-label)))
y_train = my.dataframe[inTrain, ]$label
X_test = xgb.DMatrix(as.matrix(my.dataframe[-inTrain, ] %>% select(-label)))
y_test = my.dataframe[-inTrain, ]$label

XGBoost 的参数搜索

下面的函数做什么:
-把我们的训练/测试集作为输入。
-定义交叉验证的列车控制。
-定义参数网格。
-设置包含参数搜索的 XGB 模型。
-评估模型的准确性
-返回最佳参数集

param_search <- function(xtrain, ytrain, xtest, ytest) {# Cross validation init
 xgb_trcontrol = trainControl(method = “cv”, number = 5, allowParallel = TRUE,
 verboseIter = T, returnData = FALSE)# Param grid
 xgbGrid <- expand.grid(nrounds = 60, #nrounds = c(10,20,30,40),
 max_depth = 20, #max_depth = c(3, 5, 10, 15, 20, 30),
 colsample_bytree = 0.6,#colsample_bytree = seq(0.5, 0.9, length.out = 5),
 eta = 0.005, #eta = c(0.001, 0.0015, 0.005, 0.1),
 gamma=0, min_child_weight = 1, subsample = 1
 )# Model and parameter search
 xgb_model = train(xtrain, ytrain, trControl = xgb_trcontrol,
 tuneGrid = xgbGrid, method = “xgbTree”,
 verbose=2,
 #objective=”multi:softprob”,
 eval_metric=”mlogloss”)
 #num_class=3)# Evaluate du model
 xgb.pred = predict(xgb_model, xtest, reshape=T)
 xgb.pred = as.data.frame(xgb.pred, col.names=c(“pred”))
 result = sum(xgb.pred$xgb.pred==ytest) / nrow(xgb.pred)
 print(paste(“Final Accuracy =”,sprintf(“%1.2f%%”, 100*result)))return(xgb_model)
}

一旦参数搜索完成,我们可以直接使用它来定义我们的工作模型,我们用$操作符访问每个元素:

 best.model <- xgboost(
 data = as.matrix(my.dataframe[inTrain, ] %>% select(-IMPORTANCE)),
 label = as.matrix(as.numeric(my.dataframe[inTrain,]$IMPORTANCE)-1),
 nrounds = xgb_model$bestTune$nrounds,
 max_depth = xgb_model$bestTune$max_depth,
 eta = xgb_model$bestTune$eta,
 gamma = xgb_model$bestTune$gamma,
 colsample_bytree = xgb_model$bestTune$colsample_bytree,
 min_child_weight = xgb_model$bestTune$min_child_weight,
 subsample = xgb_model$bestTune$subsample,
 objective = “multi:softprob”, num_class=3)

计算并绘制特征重要性

同样,xgboost 包中提供了许多函数。文档展示了其中的大部分。

xgb_feature_imp <- xgb.importance(
   colnames(donnees[inTrain, ] %>% select(-label)), 
   model = best.model
)gg <- xgb.ggplot.importance(xgb_feature_imp, 40); gg

下面是一个功能重要性图的示例,如 Rstudio 中所示。用 xgboost 生成的聚类只是按照相似的分数对特性进行分组,没有其他特定的含义。

Feature importance with ggplot

进一步阅读

我希望这是对 R 的简单介绍,我相信进步是通过操作和实验取得的。这里有一些资源可以让你继续学习,自己飞翔:

  • R-bloggers :关于 R 的新闻和教程,收集大量博文。
  • 我总是会回到这个问题上来
  • R 简介:如果你需要 R 编码的刷新者
  • xgboost(R API)入门
  • 数据营课程和文章
  • Kaggle R 内核

感谢您的关注,感谢您的反馈,一路*安!

从 94%到 95%

原文:https://towardsdatascience.com/from-94-to-95-b4bf149beb27?source=collection_archive---------32-----------------------

我将分享各种技术;理论上,我曾经在 IMDB 数据集上将我的 NLP 情感分析从大约 94%提高到 95%。

Image source — Google

技巧— 1

  • 半监督学习——有一个学习分支叫做半监督学习,它允许我们使用未标记的数据来训练我们的语言模型。fastai 提供的 IMDB 数据集在upsup文件夹下为我们提供了未标记的数据,我们可以使用这些数据来训练我们的模型。大多数公司花费数年时间来完全标记数据,但半监督学习允许我们在不标记完整数据的情况下训练模型。我们也可以使用未标记的数据来训练我们的语言学习者关于任何语言的细节。因此,无论何时你找到一个,也使用未标记的数据。

unsup folder included

  • 由于我们也使用了未标记的数据,我们有了更多的数据,因此也就有了更多的历元。
  • 混合精度——不要使用单精度浮点数,而是使用半精度浮点数。以前,浮点运算需要 32 位,因为只有我们才能达到精度。但是,对于深度学习模型,我们需要大约。一些 GPU 支持半精度浮点。NVIDIA 的 GPU 和 Google 的 TPU 增加了支持半精度浮点的软件,并且加快了结果的速度。虽然 16 位浮点不准确,但在神经网络的某些地方,它是可行的。但是在某些领域,比如计算梯度和损耗,我们需要单精度浮点数,因为半精度浮点数的值是 0。因此,在实践中,我们使用混合精度,我们的模型根据操作类型使用单精度和半精度。那是一个艰难的选择。不过没问题。 Fastai 很幸运在内部支持这一点。但肯定的是,我们可以明确地定义它,也像下面这样。感谢 Fastai。

  • drop_mult —我们用于迁移学习的语言模型使用 AWD_LSTM,这是一种递归神经网络,它定义了 5 种不同类型的辍学。宣布每一种类型的辍学并对这些价值观进行实验变得非常烦人。Fastai 已经说明了辍学的基本值,我们提供的是 drop_mul,它是内部每个辍学人数的倍数。如果模态严重过度拟合,可以增加该值,即更加正则化。我们的目标是创建更准确的语言模型,通常,我们定义较低的 dropout 值,因为较高的正则化值会导致较差的语言模型,从而导致对下一个单词的较差预测。

但这里有一个抓手

  • 在 Fastiers 最*的研究中,如果我们增加正则化的值,我们会得到差的语言模型,但我们肯定会得到更准确和更好的情感分类器模型。让我们等待这项研究发表吧。通常,值在 0.1 到 1 之间。

诡计— 2

  • 向后—根据最后一个单词,预测前一个单词,一些不寻常但有帮助的东西。Fastai 允许我们反向训练情态动词,这样我们的学习者也可以反向预测单词。然后,我们可以集成建立在前向学习器上的向上分类器和建立在后向学习器上的后向分类器,从而提高准确率。我们所做的是创建与实际数据相反的数据库,然后在此基础上训练语言学习者。

如果我发现更多的技巧,我会继续分享。在那之前,继续探索 fastai。

从单一决策树到随机森林

原文:https://towardsdatascience.com/from-a-single-decision-tree-to-a-random-forest-b9523be65147?source=collection_archive---------6-----------------------

作者:罗莎丽亚·西里波和凯瑟琳·梅尔彻

决策树是一组非常流行的监督分类算法。它们之所以非常受欢迎,有几个原因:它们在分类问题上表现得相当好,决策路径相对容易解释,构建(训练)它们的算法又快又简单。

决策树还有一个集合版本:随机森林。随机森林本质上代表 N 个决策树的集合,因此增加了预测的鲁棒性。

在本文中,我们将简要概述决策树增长背后的算法、其质量度量、避免过度适应训练集的技巧以及决策树随机森林带来的改进。

什么是决策树?

决策树是一个类似流程图的结构,由节点和分支组成(图 1)。在每个节点处,基于输入要素之一对数据进行分割,生成两个或更多分支作为输出。在即将到来的节点中进行越来越多的分割,并且生成越来越多的分支来分割原始数据。这种情况一直持续到生成一个节点,其中所有或几乎所有的数据都属于同一个类,并且不再可能进行进一步的拆分或分支。

这整个过程产生了一个树状结构。第一个分割节点称为根节点。末端节点被称为叶子,并且与类别标签相关联。从根到叶的路径产生分类规则。如果只有二叉分裂是可能的,我们就说二叉树。然而,在这里,我们想要处理非二进制决策树的更一般的实例。

让我们用一个例子来形象化这一点。我们收集了一个人过去航海计划的数据,即这个人是否出去航海,基于各种外部条件——或“输入特征”——如风速(以节为单位)、最高温度、前景以及船只是否在冬季储存。输入要素通常也称为非目标属性或独立变量。我们现在想要构建一个决策树,它将预测航行结果(是或否)。航行结果特征也称为目标变量或因变量。

如果我们知道准确的分类规则,我们可以手动构建一个决策树。但这种情况很少发生。我们通常拥有的是数据:一边是输入特征,另一边是要预测的目标特征。许多自动程序可以帮助我们从数据中提取规则来构建这样的决策树,如 C4.5、ID3 或 CART 算法 (J. Ross Quinlan)。在所有这些方法中,目标都是训练一个决策树来定义预测目标变量的规则,在我们的例子中,目标变量是我们是否会在新的一天去航海。

Figure 1. Example of a decision tree (on the right) built on sailing experience data (on the left) to predict whether or not to go sailing on a new day.

构建决策树

让我们探索如何按照上面列出的算法之一自动构建决策树。

任何这些算法的目标是将训练集划分成子集,直到每个划分在目标类别方面是“纯的”或者足够小。要明确的是:

  • 纯子集是只包含一类样本的子集。
  • 每个分区操作都是通过一个规则来实现的,该规则根据其中一个输入要素的值来分割输入数据。

总而言之,决策树由三个不同的构件组成:节点、分支和叶子。节点识别分裂特征,并对数据的输入子集实施划分操作;分支从一个节点出发,并识别由划分操作产生的不同数据子集;路径末端的叶子标识数据的最终子集,并将类别与特定的决策路径相关联。

例如,在图 1 的树中,第一个节点中的拆分涉及“Storage”特性,并将输入子集划分为两个子集:一个是“yes ”,另一个是“no”。这里,输入数据集分为两个数据集:一个是“风”> 6 的数据集,另一个是“风”<= 6. How does the algorithm decide which feature to use at each point to split the input subset?

The goal of any of these algorithms is to recursively partition the training set into subsets until each partition is as pure as possible in terms of output class. Therefore, at each step, the algorithm uses the feature that leads to the purest output subsets.

质量度量的数据集

在每一次迭代中,为了决定哪个特征导致最纯净的子集,我们需要能够测量数据集的纯度。过去已经提出了不同的度量和指数。我们将在这里描述其中的几个,可以说是最常用的:信息增益、基尼指数和增益率。

在训练期间,为所有候选特征计算选定的质量测量,以找出哪一个将产生最佳分割。

熵是一个用来衡量信息或无序的概念。当然,我们可以用它来衡量一个数据集有多纯。

如果我们将目标类视为数据集中一个点的可能状态,那么数据集的熵可以在数学上定义为所有类的概率之和乘以它的对数。因此,对于二元分类问题,熵的范围落在 0 和 1 之间。

其中 p 是整个数据集,N 是类的数量,pi 是类 I 在同一数据集中的出现频率。

为了更好地理解熵,让我们处理两个不同的数据集示例,两个数据集都有两个类,分别用蓝点和红叉表示(图 2)。在左侧的示例数据集中,我们混合了蓝点和红叉。在右边数据集的例子中,我们只有红叉。第二种情况——只有来自一个类的样本的数据集——是我们的目标:一个“纯”数据子集。

Figure 2. Two classes: red crosses and blue dots. Two different datasets. A dataset with a mix of points belonging to both classes (on the left) and a dataset with points belonging to one class only (on the right).

现在让我们计算这两个二元数据集的熵。

对于左边的例子,红叉类的概率是 7/13,蓝点类的概率是 6/13。请注意,这里一个类的数据点几乎与另一个类的数据点一样多。上面的公式导致熵值为 0.99。

在右边的例子中,红叉类的概率是 13/13 = 1.0,蓝点类的概率是 0/13 = 0.0。请注意,这里我们只有红十字点。在这种情况下,上面的公式导致熵值为 0.0。

熵可以是纯度、无序度或信息量的度量。由于混合的类,左边的数据集不太纯净并且更加混乱(更加无序,即更高的熵)。然而,更多的无序也意味着更多的信息。事实上,如果数据集只有一个类的点,那么无论您尝试多长时间,都无法从中提取多少信息。相比之下,如果数据集具有来自两个类的点,则它也具有更高的信息提取潜力。因此,左侧数据集的较高熵值也可以被视为更大量的潜在信息。

决策树中每次分裂的目标都是从一个混乱的数据集转移到两个(或更多)更纯净的子集。理想情况下,分割应该产生熵为 0.0 的子集。然而,在实践中,如果分割导致子集的总熵低于原始数据集,这就足够了。

Figure 3. A split in a node of the tree should move from a higher entropy dataset to subsets with lower total entropy.

信息增益(ID3)

为了评估一个特征对于分裂有多好,计算分裂前后的熵差。

也就是说,我们首先计算分割前数据集的熵,然后计算分割后每个子集的熵。最后,在分割之前,从数据集的熵中减去由子集的大小加权的输出熵的总和。这种差异衡量的是信息的增加或熵的减少。如果信息增益是一个正数,这意味着我们从一个混乱的数据集转移到一些更纯粹的子集。

其中“before”是拆分前的数据集,K 是拆分生成的子集数,(j,after)是拆分后的子集 j。

在每一步,我们将选择分割信息增益值最高的特征上的数据,因为这将产生最纯粹的子集。应用此度量的算法是 ID3 算法。ID3 算法的缺点是偏向于具有大量值的特征,从而生成更大的决策树。

增益比(C4.5)

C4.5 算法中使用的增益比测量引入了 SplitInfo 概念。SplitInfo 被定义为权重的和乘以权重的对数,其中权重是当前子集中的数据点数相对于父数据集中的数据点数的比率。

然后,通过将 ID3 算法的信息增益除以 SplitInfo 值来计算增益比。

其中“before”是拆分前的数据集,K 是拆分生成的子集数,(j,after)是拆分后的子集 j。

基尼指数(CART)

CART 算法使用的另一个衡量纯度——或者实际上是杂质——的指标是基尼指数。

基尼系数是根据基尼系数计算的。基尼系数定义为 1 减去数据集中类别概率的*方和。

其中 p 是整个数据集,N 是类的数量,pi 是类 I 在同一数据集中的出现频率。

然后,基尼指数被定义为分割后不同子集的基尼系数的加权和,其中每一部分由子集大小相对于父数据集大小的比率来加权。

对于有两个类的数据集,基尼系数的范围在 0 和 0.5 之间:如果数据集是纯的,则为 0;如果两个类*均分布,则为 0.5。因此,具有最低基尼指数的特征被用作下一个分裂特征。

其中 K 是由分裂产生的子集的数量,而(j,after)是分裂后的子集 j。

识别劈叉

对于名义特征,我们有两种不同的分割选项。我们可以为训练集中所选特征的每个值创建一个子节点,也可以进行二进制分割。在二进制分割的情况下,测试所有可能的特征值子集。在最后一种情况下,该过程在计算上更加昂贵,但是仍然相对简单。

在数字特征中,识别最佳分割更加复杂。所有的数值实际上都可以是分裂的候选者。但是这将使质量度量的计算成为过于昂贵的操作!因此,对于数字特征,分割总是二进制的。在训练数据中,候选分裂点取在所选数字特征的每两个连续值之间。再次,采用产生最佳质量度量的二元分裂。然后,分割点可以是该特征的两个分区之间的*均值,即较低分区的最大点或较高分区的最小点。

尺寸和过度配合

决策树像许多其他机器学习算法一样,可能会过度拟合训练数据。太深的树会导致模型太详细,不能根据新数据进行归纳。另一方面,太浅的树可能会导致过于简单的模型,不适合数据。你看,决策树的大小至关重要。

Figure 4. The size of the decision tree is important. A tree that is large and too detailed (on the right) might overfit the training data, while a tree that is too small (on the left) might be too simple to fit the data.

有两种方法可以避免过度特殊化的树:修剪和/或提前停止。

修剪

在训练阶段之后,修剪被应用于决策树。基本上,我们让树自由增长到它的设置允许的程度,而不施加任何明确的限制。最后,我们继续删除那些没有被充分填充的分支,以避免过拟合训练数据。事实上,没有被充分填充的分支可能过度集中在特殊的数据点上。这就是为什么移除它们有助于对新的未知数据进行归纳。

有许多不同的修剪技术。在这里,我们要解释两个最常用的:减少错误剪枝和最小描述长度剪枝, MDL 简称。

在减少错误修剪中,在每次迭代中,修剪低填充分支,并且再次将树应用于训练数据。如果对分支的修剪没有降低训练集的准确性,则该分支将被永久移除。

MDL 修剪使用描述长度来决定是否修剪一棵树。描述长度被定义为对树进行编码所需的位数加上对训练集的误分类数据样本进行编码所需的位数。当修剪树的分支时,计算并比较未修剪树和修剪树的描述长度。如果被修剪的树的描述长度较小,则保留修剪。

提前停止

另一个避免过度拟合的选择是根据停止标准提前停止。

一个常见的停止标准是每个节点的最小样本数。当创建的节点包含的数据样本数量少于或等于最小集合数量时,分支将停止增长。因此,这个最小值的值越大,树越浅,而值越小,树越深。

决策树的随机森林

正如我们在开始时所说的,决策树的进化提供了更健壮的性能,从而产生了随机森林。让我们看看创新的随机森林模型与原始的决策树算法相比如何。

多人胜于一人。简单地说,这就是随机森林算法背后的概念。也就是说,许多决策树可以比一个单独的决策树产生更准确的预测。事实上,随机森林算法是一种监督分类算法,它构建 N 个略有不同的训练决策树,并将它们合并在一起,以获得更准确和稳定的预测。

让我们再次强调这个概念。整个想法依赖于多个决策树,这些决策树的训练略有不同,并且在最终决策时会考虑所有这些决策树。

Figure 5. The random forest algorithm relies on multiple decision trees that are all trained slightly differently; all of them are taken into consideration for the final classification.

训练集的引导

让我们把重点放在“训练略有不同”

用于随机森林的训练算法将打包的通用技术应用于树学习者。在整个训练集上单独训练一个决策树。在随机森林中,N 个决策树中的每一个都在通过原始数据集的自举获得的原始训练集的子集上被训练,即,通过带有替换的随机采样。

此外,作为原始特征集的随机子集,输入特征也可能因树而异。通常,如果 m 是原始数据集中输入要素的数量,则在每个决策树的训练过程中,每次分割时都会考虑随机提取的[m 的*方根]个输入要素的子集。

Figure 6. The decision trees in a random forest are all slightly differently trained on a bootstrapped subset of the original dataset. The set of input features also varies for each decision tree in the random forest.

多数决原则

对于相同的输入向量,N 个稍微不同的训练树将产生 N 个稍微不同的预测。通常,多数决原则适用于做出最终决定。由 N 棵树中的大多数提供的预测被采用作为最终预测。

这种策略的优势是显而易见的。虽然来自单个树的预测对训练集中的噪声高度敏感,但是来自许多树的大多数的预测则不敏感,只要这些树不相关。自举采样是通过在不同的训练集上训练树来去相关的方法。

出袋(OOB)错误

测量随机森林预测误差的一个常用度量是袋外误差。

Out-of-bag error 是对 xᵢ的所有训练样本计算的*均预测误差,仅使用在其引导训练集中没有 xᵢ的树。袋外误差估计避免了对独立验证数据集的需要,但可能会低估实际的性能改进。

结论

在本文中,我们回顾了决策树的几个重要方面:如何训练决策树来实现分类问题,使用哪些质量度量来选择要分割的输入特征,以及避免过拟合问题的技巧。

我们还试图解释随机森林算法的策略,使决策树预测更加稳健;也就是说,限制对训练集中噪声的依赖性。事实上,通过使用一组 N 个去相关的决策树,随机森林增加了最终分类的准确性和鲁棒性。

现在,让我们使用它,看看我们明天是否会去航行!

Figure 7. The workflow implementing the training and evaluation of a decision tree and of a random forest of decision trees. This workflow can be inspected and downloaded from the KNIME Hub at https://kni.me/w/Eot69vL_DI5V79us.

参考

J.罗斯·昆兰,“C4.5:机器学习程序”,摩根·考夫曼出版公司,旧金山,加利福尼亚州,美国 1993 年

附录

你可以在 https://kni.me/w/Eot69vL_DI5V79us 的 KNIME 开源中心找到一个如何训练和评估决策树和决策树随机森林的例子。这个工作流程也显示在图 7 中。

如首次发表于data versity

从学术界到 Kaggle:物理学家如何在数据科学中找到爱

原文:https://towardsdatascience.com/from-academia-to-kaggle-how-a-physicist-found-love-in-data-science-d57bdc500d04?source=collection_archive---------9-----------------------

与 Bojan Tunguz 的对话:数据科学家,Kaggle 双特级大师,理论物理学家

我没有选择卡格尔生活。Kaggle 生活选择了我:Bojan Tunguz。

从别人那里学习和获取灵感总是有帮助的。这在数据科学领域更有意义,因为每天都有新的课程、MOOCs 和推荐不断涌现。如此多的选择不仅让人不知所措,有时还令人困惑。带着这种想法,我们在 H2O.ai 上揭示了知名数据科学家和 Kaggle 大师的故事,他们与我们分享了他们的旅程、灵感和成就。这些采访旨在激励和鼓励那些想了解成为一名 Kaggle 特级大师的人。

这次我有机会与双卡格大师、物理学家 博扬·东古兹 互动。Bojan Tunguz 出生在波斯尼亚黑塞哥维那的萨拉热窝,1993 年移居美国。他拥有伊利诺伊大学的物理学博士学位和斯坦福大学的应用物理学硕士学位。他还在斯坦福大学、德堡大学、罗德学院和伊利诺伊大学等知名大学教授各种物理课程。

博扬离成为三级大师只差一枚单人金牌了,我们希望他能尽快实现这一壮举。

以下是我与 Bojan 对话的摘录:

  • 你有理论物理背景。从学术界到工业界的转变是如何发生的?

Bojan: 套用海明威的话,先突然,后逐渐。学术工作很难找到,尤其是在理论物理等过饱和的领域。当你是一个移民的时候,这要困难十倍。有一次,我认为安定下来并建立一个家庭比追求难以捉摸的学术任命重要得多。所以我被迫寻找替代方案。最初,我涉足科技写作和小规模桌面制造,但一旦我发现了数据科学,我就迷上了它。数据科学提供了我一直在寻找的科学和技术之间的*衡。

  • 成为双 Kaggle 宗师有多难。最初是什么吸引了你,第一次胜利是什么时候?

Bojan: 我目前是内核和讨论方面的特级大师,距离成为竞赛特级大师还有一枚单人金牌。这些类别中的每一个都需要不同的技能和敏感度。就技术技能而言,比赛是迄今为止要求最高的。对于讨论和核心,其他技能,如沟通、社交技能、写作和数据可视化是必不可少的。同样重要的是理解 Kaggle 竞赛的动态:什么时候发布什么;以及其他 Kagglers 觉得有价值/有趣/好玩的内容。

Bojan’s Kaggle Profile

自从我决定从事数据科学,我就听说了 Kaggle。认真对待数据科学而不了解它几乎是不可能的。然而,我最初对加入犹豫不决,因为我认为这需要很高的技能水*。然而,一旦我加入了,我意识到这个*台上有很多有价值的资源。讨论,内核,过去的竞争解决方案,在线博客帖子等。可以帮助初学者快速上手。一旦我变得相当优秀,我也开始更频繁地组队,到目前为止,我从每个团队中学到了很多。

大约一年半前,我在 IEEE 相机传感器识别比赛中赢得了我的第一枚金牌。我还在一年前的家庭信用违约风险竞赛中获得了第一名。这是迄今为止对我来说最难忘和最棒的卡格尔体验。

我最初对加入犹豫不决,因为我认为这需要很高的技能水*。然而,一旦我加入,我意识到这个*台上有很多有价值的资源

  • 你如何决定参加哪些比赛?

Bojan: 这很简单:我全部输入!😃不过,我一般都是一次挑一两个。在选择比赛时,我会考虑许多不同的因素。我已经有多少建模管道,需要多少努力才能获得一个好的基线,本地分数和排行榜之间的预测有多稳定,以及对我来说非常重要的是,我可以从集成中获得多大的提升。

  • 你通常如何处理一个难题?你有什么喜欢的 ML 资源想分享吗?

我通常会先从小处着手,然后逐步积累。我不会试图马上得到“最好”的解决方案。

我的工具包对 Kaggle 来说是相当标准的:熊猫numpysklearnXGBoostLightGBMKeras 。我在 Jupyter 笔记本工作,我是 J upyter Lab 的超级粉丝。

  • 作为 H2O.ai 的数据科学家,你的角色是什么,在哪些具体领域工作?

Bojan: 大多数时候,我专注于外向角色,帮助我们的客户解决他们正在处理的数据科学和 ML 问题。我也为 无人驾驶 AI 做出贡献,在那里我专注于各种特征转换“食谱”和无监督学习。

  • 如果你要和 H2O.ai 的大师们组队,他们会是谁,为什么?

Bojan: 全部!甚至在我加入 H2O 之前,我就已经能够与 Olivier Gralier 合作了,现在我参加的比赛是与 Dmitry Larko 合作。H2O.ai 的许多人都是我多年来一直敬仰的人。现在能够称他们为同事是一种难以置信的荣誉。我的梦想是和尽可能多的人合作。

  • 你在 H2O.ai 的专业工作中运用到的通过 Kaggle 学到的最好的东西有哪些?

Bojan: 你从参加 Kaggle 比赛中学到的最重要的“元”技能之一就是能够快速适应和尝试许多不同的事情。此外,由于你的大多数“伟大”想法都有失败的可能性,你要学会至少有一个应急计划,通常是六个。

Bojan(2 from L) during SF Kaggle days ’19. Seen at extreme right is Dmitry Larko, another Kaggle Grandmaster associated with H2O.ai

  • 数据科学领域正在快速发展。你是如何设法跟上所有最新发展的?

Bojan: 这是我一直参加 Kaggle 比赛的主要原因之一。对于每个新的竞争,我可以应用至少一个新的技术、库或框架。Kaggle 竞赛可能是保持你的应用 ML 技能敏锐和与时俱进的最佳方式。

  • 你希望在 ML 的哪些特定领域或问题上运用你的专长?

Bojan: 我喜欢 NLP,希望能在这类问题上多花些时间。在某些方面,这些问题最接*“经典”人工智能应该解决的问题。

我也喜欢研究金融科技问题,但以我的经验来看,金融科技仍然比科技更好。我觉得我们仍然只是触及了 ML 在这个领域所能完成的事情的表面。

最*我有幸在 Kaggle 上做得很好的一件事是“纯”科学问题。这些问题从蛋白质分类到仅使用 ML 技术预测标量耦合常数。“纯”科学是另一个先进的人工智能技术可能产生巨大影响的领域。

  • 给刚刚开始或希望开始数据科学之旅的数据科学有志者一句忠告?

Bojan: 现在是开始从事数据科学领域工作的最佳时机。在我看来,数据科学是当今最开放的专业领域。无论您是新手还是“经验丰富”的数据科学老手,都有大量资源可以帮助您踏上征程:信息丰富的教科书、博客和网络研讨会;KaggleMOOCs 在线论坛;开源软件;*易*人的从业者。熟悉所有这些资源。想出一个合理的适合你的计划。培养你的技术技能是很重要的,但是也要投入时间来培养你的“软”技能:写作、交流、网络等等。对自己有耐心,给自己时间成长和发展。不要害怕失败。强调从失败中吸取教训。最重要的是,尽可能地享受旅行的乐趣。

现在是开始在数据科学领域工作的最佳时机。在我看来,数据科学是当今最开放的专业领域。

成为一名 Kaggle 大师绝非易事,需要大量的努力、坚持和专注。话虽如此,也不可否认,没有什么是不可能的。我们只需要用正确的工具把我们的努力引向正确的方向。

阅读本系列的其他采访:

  • 罗汉饶 :一个数据科学家从数独到 Kaggle 的旅程
  • 希瓦姆·班萨尔 :数据科学家,负责 Kaggle 上的“数据科学为善”竞赛。

原载于 H2O.ai 网站。

从苹果到波士顿布鲁因斯,一个数据专家如何将个人兴趣和职业兴趣结合起来

原文:https://towardsdatascience.com/from-apple-to-boston-bruins-how-one-data-professional-combined-his-personal-and-professional-b28f0336d5d7?source=collection_archive---------27-----------------------

Josh Pohlkamp-Hartt 分享了他在波士顿布鲁因斯获得梦想角色的五个技巧

波士顿布鲁因斯队是全美曲棍球联合会第五大最有价值的球队,据《福布斯》杂志估计,其价值约为 1B 美元。凭借六次斯坦利杯的胜利,该队年收入超过 2 亿美元。

乔希·波尔坎普-哈特从记事起就是冰球迷。因此,说服他离开苹果公司的统计员职位并不难,他加入了波士顿布鲁因斯公司,成为一名数据分析师。在苹果工作 3 年多之前,Josh 在皇后大学完成了统计学本科、硕士和博士学位。

在这篇文章中,Josh 分享了他在职业生涯中学到的五个技巧。这包括把兴趣和技术能力结合起来,心中有目标,学会有效沟通,知道自己的问题空间,培养对学习的热爱。

#1 想学什么就学什么,但要确保你把个人兴趣和技术兴趣结合起来

哪个学位能培养出最好的数据科学家,这个问题在很大程度上与 Josh 无关。在他的职业生涯中,他遇到过各种教育背景的数据科学家。区分最好的人的东西总是他们把他们的兴趣和技术能力结合起来的能力。

对乔希来说,这就是曲棍球。在攻读博士学位期间,他有机会在金斯敦的 OHL 团队工作。它开始是为曲棍球运动员估价的独立研究收集数据的机会。过了一段时间,它变成了创建球员表现的回归模型,并向教练和管理层报告统计数据。对他来说,这是一个很好的方式,可以看到他在课堂上学到的东西转化到现实生活中。这个早期的机会也是他在波士顿布鲁因斯担任目前职务的原因。

如果你对某件事充满热情,你就已经理解了数据以及在这种情况下什么是有意义的。这为您构建模型和执行数据分析提供了优势。

#2:心中有一个目标

在研究生院的时候,乔希知道他没有兴趣成为一名学者。相反,培养解决问题的技能和学习的兴趣是他继续研究生学习的动力。

他一直知道他最终会进入工业界。这就是为什么他开始将在学校学到的东西与现实生活中的经历结合起来,比如与 OHL 团队合作。这也意味着在毕业前一年,乔希没有像同龄人一样申请博士后职位,而是开始准备行业面试。由于做了充分的准备,他得到了美国银行的一份工作。有了这份工作,他在苹果公司的面试变得容易多了,因为他知道他有一个备份。由于这种心态,他能够在毕业后在苹果公司找到一份工作。

当他在苹果工作并获得了重要的行业经验时,他总是把在曲棍球工作的梦想藏在心底。这就是为什么当波斯顿布鲁因斯联系他寻求一个职位时,乔希毫不犹豫地答应了。由于他之前在 OHL 团队工作的背景,以及他在苹果公司的专业资历,他被视为值得追求的高价值候选人。

#3:学会有效沟通

有效沟通的关键在于尽可能简洁明了。“少即是多”这句格言在大多数情况下都适用。

这也适用于模型领域,正如乔希在苹果公司的经历中所学到的。假设较少的简单模型通常在商业环境中更好,因为它们具有可解释性,尽管它们的性能可能会下降。商业利益相关者更有可能信任他们理解的模型,而不是你难以解释清楚的黑箱。

另一个重要的提示是避免以结论开始你的陈述和分析而埋没了线索。换句话说,要有一个清晰的叙述,在叙述中使用金字塔结构(即从最重要的开始,一步步往下)。

然而,同样重要的是要记住,没有尝试和错误,你就无法建立沟通技巧。这就是为什么建议你尽早开始通过博客学习写作,通过加入像演讲会或论文/研究分享小组这样的组织学习公开演讲。

#4:了解你的问题空间

为了更有效地履行你的职责,你需要深入了解你所工作的问题空间。做到这一点的最好方法是学习如何提出好的问题,并成为一个积极的倾听者。这一点尤其重要,因为人们很少能很好地记录文档。在这种情况下,你必须像侦探一样工作,找出隐藏的部落知识。

加入一家公司或过渡到一个新的角色是练习这些技能的特别重要的时间。一个很好的类比是成为一个运动队的新成员。在这种情况下,在你开始持有观点和说出你的想法之前,最好坐下来,观察和了解团队内部的动态。

对于数据科学家来说,很大一部分职责是帮助决策者做出明智的决策。因此,你需要了解他们来自哪里,他们想去哪里。有了这样的背景,你更有可能交付有影响力的结果。

了解您的问题空间的另一个重要领域是数据清理,这是您正在处理的任何问题的重要组成部分。有了领域专业知识,您将更倾向于在数据清理阶段采取某些步骤,这将增加数据集对未来工作的效用。

#5:培养对学习的热爱

数据科学是一个不断发展壮大的领域,因此培养对学习的热爱对你的成功至关重要也就不足为奇了。乔希建议从基础开始,阅读像《统计学习的 T2 元素》这样的书以及你感兴趣领域的基础论文。记住,没有人生来就知道如何阅读研究论文;这些是你通过刻意练习获得的技能。

一旦你有了一个坚实的基础,你就可以扩展到外围,深入研究最先进的技术。 Arxiv 是一个很好的地方,因为它拥有来自世界各地的学者和从业者的大量预印论文。重现这些论文也是理解和加速你学习的一个好方法。

要记住的另一个技巧是避免使用教程提供的玩具示例,而是使用您感兴趣或计划在某个时候使用的真实数据。这将使你更容易度过学习过程中的艰难阶段,并可能激励你将教程扩展到新的应用和见解。

《数据思维》是一个系列,介绍处理数据的专业人士。在这个系列中,你将了解他们的日常故事,以及给别人的建议。

之前的采访包括来自红牛、开门、 Snapchat 、网飞和 Lyft 的数据科学家。

我成为数据科学家的旅程:如何构建一条迭代的职业道路

原文:https://towardsdatascience.com/from-archaeology-to-data-science-the-joy-of-iterative-career-paths-632b07f763f5?source=collection_archive---------18-----------------------

发现我对数据的热爱

在学校的时候,我并没有打算做什么特别技术性的职业。我参加了数学 A-level 考试,很大程度上是为了摆脱历史和英国文学的论文写作,以及耗时的美术创作。我去了剑桥大学学习考古学和人类学(另一个反复的决定过程,但不是现在),然后去了牛津大学攻读考古学硕士和博士学位。

Three examples of me as an archaeologist. Left: Monte Polizzo, Sicily, 2006. Centre: Atapuerca, Spain, 2010. Right: Lakaton’i Anja, Madagascar, 2012 (right, foreground).

作为一门学术学科,考古学的一个伟大之处在于它是一个多么广阔的教堂。你可以研究任何东西,从罗马花瓶的美学到放射性同位素年代测定,但仍称自己为考古学家。我发现自己更倾向于技术层面(毕竟我非常感谢数学 A-level)。

我感兴趣的领域是人类进化和我们物种在世界各地的最早扩散。我意识到我们对这个话题的很多想法都是定性的——“这个石器看起来有点像另一个石器,所以他们可能是同一个人”。在这里,我决定,这是一个很好的机会来尝试使用,你知道,实际的定量分析,也许可以尝试得到一些实际的答案。

这就是我如何发现自己在考古统计学这个令人难以置信的利基领域的。与其说是一片田野,不如说是一小片肮脏的土地,里面住着我和另外两个考古学的书呆子。但是突然之间,通过将统计学应用到一个全新的领域,我能够发现所有我们以前无法获得的关于过去的重要信息。我的研究反驳了一些之前关于我们认知和文化进化的经典信念,以及关于我们物种首次走出非洲时发生了什么的信念。我对在考古学中严格使用统计学的好处深信不疑。我教考古学的同学统计学。我在会议上发言。我出版了一本关于这个主题的书和一堆论文。

试图找出如何拥有一份有影响力的职业

然而,尽管我热爱我的主题领域,我发现自己对缺乏真实世界的影响感到沮丧。利基研究领域(至少是那些没有明显商业或工业应用的领域)的一个问题是,大多数时候,只有少数专家真正从你的工作中受益。

我觉得(现在仍然觉得)有动力去做一些真正有益于现实世界中人们的事情,而不是在学术象牙塔里。正是这种动力让我决定离开学术界。我喜欢我工作中的分析部分,我想继续与数据打交道,但我想去一个能帮助人们解决现实世界问题的地方工作。

这就是为什么我接下来决定加入英国公务员队伍,成为一名统计学家,参加“快速流”(他们为毕业生提供的加速发展计划)——我将继续与数据打交道,但我将利用它来帮助我的国家变得更好。我的第一份工作是在卫生部,为 NHS 研究金融和经济模型。我喜欢着手解决重大的有形问题,但很快发现了其中的权衡——解决全国性的重要问题意味着要应对国家规模的官僚机构,而我发现工作节奏慢得令人沮丧。我已经设法勾掉了我的“数据和分析”和“现实世界影响”框,但还缺少一些东西。

自从搬到伦敦后,我开始发现创业公司的奇妙世界,在参加聚会和会见各种各样的了不起的人建立惊人的新事物后。我想更接*现实,所以当财政部出现一个就风险资本政策向政府提供建议的职位时,我马上就申请了。在这份工作中,我保留了所有我喜欢的关于数据分析的东西,并继续对国家政策产生影响,现在我开始对主题领域增加真正的兴趣。我还将统计和分析应用到一个新的领域,成为我的政策领域 20 年历史中的第一人(企业投资计划(EIS)对启动投资的税收减免,以及相关计划及其缩写(SEIS、VCTs、SITR 和 CITR)),对这些计划进行统计上严格的评估,部分评估结果发表在政府的患者资本审查的咨询中。

寻找合适的工作环境

我再次发现我的工作很有趣。然而,我仍然觉得这种工作文化并不适合我,而且我离行动还差得很远。我决定尝试在创业公司工作。

我加入了一家 proptech 初创公司,从定价分析师一路晋升到收入和分析主管,再到混合数据产品经理兼首席分析师。我在这里学到了这么多,它可能值得自己的博客帖子。我最自豪的一件事是从零开始建立公司的分析和报告能力,从运行一个混乱的电子表格集合和为其他目的构建的数据库的一部分,到拥有一个为公司每个人服务的报告基础架构,并帮助人们每天做出数据支持的决策。在我最*的职业生涯迭代中,我添加了几个新的复选框——在一个你可以随时尝试新想法的地方工作,这种快节奏的合作文化适合我。然而,我开始觉得我离我真正想去的地方还有一小段距离。

走向数据科学

通过与开发人员合作,并更深入地钻研技术世界,我开始发现在数据分析之外还有一个全新的世界,在那里,你可以结合使用数学和编码,通过构建更加智能的模型来解决复杂的问题。有一段时间,我一直觉得在我所处的位置(例如,我设计了一个最*邻模型来估计 Airbnb 房产的夜间价格,但我无法建立一个像我脑海中那样复杂的模型)和我可以看到其他人在做的所有很酷的事情之间存在技能差距,这是我想去的地方(例如,能够自己设计和建立一个预测 Airbnb 未来价格的模型,测试它,然后与开发人员合作将其投入生产)。我发现包含我为自己确定的技能差距的术语是“数据科学”。

我开始尝试在业余时间自学数据科学,但最终我决定参加一个数据科学训练营,让自己尽快熟悉并开始使用数据科学工具。很多人问我,为什么我决定走(更昂贵的)训练营路线,而不是自学;诚实的回答是兴奋加上不耐烦!截至撰写本文时,我正在熨斗学校参加一个全日制数据科学训练营。这是一项艰巨的工作,但我每天都学到很多东西,并且非常享受。

对我来说,我不认为数据科学是一个特定的职业决策。相反,我认为我的整个职业生涯是一个多年的数据科学之旅,我从每一个迭代步骤中学到了很多。不仅仅是关于不同领域的技术技能和知识,还有关于我如何工作以及在职业生涯中对我很重要的价值观。关于这个迭代的职业旅程,每一步都变得更小。我非常兴奋能够完成数据科学技能提升的最后一小步,并开始我作为数据科学家的未来。

从销售代表到数据科学家

原文:https://towardsdatascience.com/from-being-a-sales-rep-to-being-a-data-scientist-4bb1da79ba3f?source=collection_archive---------17-----------------------

我从销售专员到数据科学家的转变&最大的挑战是什么。

Photo by Brendan Church on Unsplash

寒冷呼唤恐怖

我无法用语言来表达我有多讨厌陌生来电。我不想这么做,电话那头的人也不想让我这么做。95%的时间里,电话那头都是失败和拒绝。我不是那种天生超级友好和健谈的打电话的人,所以每个电话都要我付出很多努力。但总得有人去做,我不得不继续尝试。

从事业务开发不仅仅包括电话推销,大部分是客户和关系管理。当我在销售在线营销活动时,我工作的一小部分涉及活动表现的分析和统计。令人惊讶的是,我真的很喜欢向我的客户展示和解释数据。我热爱我工作中的技术部分,尽管它并不那么重要,而且主要依赖于谷歌分析。

你不能这样做,他说

在意识到销售不适合我之后,我进入了荷兰的硕士预科。我真的不知道如果我通过了考试,我会选择什么样的硕士课程。硕士预科是一个相当全面的准备项目,可能会导致几个关于在线营销、数据新闻或奇怪的是,新的数据科学课程。由于我对这个话题了解不多,我甚至还没有考虑过数据科学方向。有一天,我的一个同学在午餐时提到他要去那条赛道。他提到硕士对我来说有多难,我有多可能会因为没有 Python 或编程经验而失败。老实说,我讨厌别人告诉我什么能做什么不能做。在我听来,这常常像是证明他们错了的黄金邀请。所以几个星期后,在对这个话题进行了详细的研究之后(事实上我很喜欢我的统计学课程),我做出了一个决定。

数据科学,我来了”。

作为完全初学者学习编程

Photo by Hitesh Choudhary on Unsplash

从头开始学习编程不是在公园散步。它需要花费无数的时间在基本的编程练习上,面对红色的错误信息&想知道学习黑魔法是否会比学习 Python 更容易。我也开始理解程序员有时对一门语言表达的爱恨交加的关系。

回想起来,我意识到我的 Python 编程老师所说的话背后的深刻真理:“如果你练习得不够,你就会失败。”。是的,这似乎很符合逻辑,任何新技能都需要练习。他真正的意思是,编程不是你在考试前最后一刻看几行代码就能通过的科目。你需要教会自己像程序员一样思考,这需要对不同类型的练习进行数小时的练习。

我们班只有 30%的人通过了第一次 Python 考试,经过无数个小时的练习,幸运的是,我也通过了。在编程中,当你读到它时,答案似乎总是很容易。当你必须完全自己设计和编写解决方案时,那就是另一回事了。简而言之,不断练习,不要只是复制粘贴 StackOverflow 的答案,尽管这很有诱惑力。

机器学习听起来很性感

我记得从第一次听到“机器学习”的定义时,我就喜欢上了这两个词。我对这个话题感到非常兴奋,迫不及待地想了解更多。我想我可以通过告诉我的家人我在教计算机如何学习东西来给他们留下深刻印象,尽管直到今天,他们仍然对我的工作一无所知。

起初,机器学习概念并不难。然而,某些模型背后的统计数据很难留在我的脑海里。应用公式并理解它们背后的逻辑从来都不是我的强项。为什么我最后又去了数据科学?为了全面理解某些模型的内部工作原理,我经常花额外的时间研究算法是如何工作的。我并不总是需要知道细节,我只是想知道。我研究得越多,就越意识到我知道的是多么少,而这个话题是多么丰富。

当我陷入某个模型或概念时,可视化也发挥了很大的作用。例如,我强烈倾向于使用图表来了解梯度下降优化的细节,或者神经网络架构之间的差异。

利用我的背景作为优势

商业开发背景可能看起来很薄弱,因为它缺乏技术技能,并且与数据科学相关的两个最大的学科:编程和统计没有什么联系。当然,任何拥有计算机科学学位或计量经济学学位的人在高效编程或机器学习模型的统计方面显然都有某种优势。

然而,许多人似乎忘记了数据科学家的软技能是极其宝贵的。除了应用强大的机器学习模型,数据科学家还必须讲述数据隐藏的故事,没有人愿意听一个无聊的柏拉图式的故事。

令人惊讶的是,在我的硕士论文期间,我意识到我在陈述方面相当不错,我可以很容易地将我的模型转化为非数据科学家可以理解的简单概念。我会编造杂货店的故事来解释推荐系统和潜在的场景来解释我获得的测量结果。作为一名销售专员,我花了两年时间向人们展示产品,给他们讲故事,把产品放在上下文中,限制在对他们重要的内容上,使用对他们有意义的词语。解释数据科学项目的结果并没有太大的不同。

此外,经历过任何产品或项目的商业方面的事实也可以在弥合业务和技术需求之间的差距时提供很大帮助。拥有某种翻译可以防止说同一种语言,只是略有不同的人之间的混淆。

知道我的极限

当做出如此大的改变时,人们必须准备付出很多努力,并审视自己的极限。我非常在意自己的弱点,任何人都应该如此,即使是在任何人知道神经网络到底是什么之前就已经在编写神经网络程序的天才。我不擅长统计,也不擅长编写漂亮高效的代码。然而,当我看到有人拥有更好的编码技能或者在统计方面看起来非常舒服时,我知道如何抓住机会学习,向谁学习。无论一个数据科学家有多少经验,这个领域都在不断发展,没有一个数据科学家应该学习完。

数据科学的美也是组成这个领域的不同背景的美。数据有如此多的内容要讲,数据可以从如此多的不同角度进行分析和处理。尽管某些背景会让你比其他人更容易进步,但任何背景都会给这个领域带来新的东西。根据您可能处理的数据类型,这甚至会成为一种真正的优势。职业转换的成功往往只取决于一个人付出了多少努力。

成功并不总是意味着伟大。这是一致性的问题。持续的努力工作会带来成功。伟大终将到来。德伊夫·约翰逊

从商业智能到数据科学和机器学习

原文:https://towardsdatascience.com/from-business-intelligence-to-data-science-94a1fd866231?source=collection_archive---------11-----------------------

记录我从商业智能领域到数据科学和机器学习的转变

我是一名数据科学和机器学习经理,专门为企业的分析需求设计和构建由 DS & ML 支持的解决方案。我现在在这个领域有超过 5 年的丰富经验,和许多人一样,我的职业生涯不是从数据科学和机器学习开始的。当我决定投身数据科学时,我是一名拥有* 10 年经验的商业智能专家。我想分享一下我转行到这个领域的经历,希望能对一些想转行的人有所帮助。

It’s definitely not this hard

I’d imagine it to be something like this

对于那些不熟悉商业智能(BI)的人来说,它是一个技术分支,使组织能够收集所有可用的历史企业数据,并开始使用它们来制定战术和战略业务决策。由于数据科学和机器学习领域在本世纪初刚刚起步(多亏了在 hbr 发表的文章“数据科学家:21 世纪最性感的工作”https://HBR . org/2012/10/Data-Scientist-The-sexy-The-Job of-The-21 世纪),我感到一种强烈的冲动去驾驭这股浪潮。但后来我觉得这是一个我迟早要做的转变,因为在我看来,这是商业智能领域的逻辑延伸。虽然数据科学&机器学习领域是通过提供关于未来的可操作的见解和情报来给企业带来优势(有些人可能会认为这也是关于现在的),但商业智能领域也是如此,但使用过去的数据,通过仪表板和可视化技术使用不太复杂的技术。

Or Maybe, little harder

也就是说,我想与所有想要成为数据科学/机器学习专业人士的人分享以下几点

  1. 几乎每个数据科学家都是公民数据科学家

鉴于在行业人才不足的情况下,对数据科学家和机器学习专业人员的需求突然激增,大多数需求都是由从艺术巴赫、心理学等不同领域过渡到 ML & DS 的人满足的。所以永远不要觉得自己在游戏中迟到了。事实上,如果您来自 BI 领域,您可以在 DS/ML 中利用许多现有的数据技能(Pandas Dataframe 操作可以很好地在使用普通 SQL 的关系表上完成)。

显然,即使在达尔文时代,许多科学家都是出于好奇和兴趣从事科学研究的普通人,因此被称为公民科学家。因此,如果你有兴趣和动力,你也可以成为一名公民数据科学家。

2。拥有结构化的学习路径

如今 DS & ML 上的 MOOCs 很多。我选择了几门课程的认证。

Its okay to be slow, but be steady

  1. 华盛顿大学机器学习专业(Coursera)【https://www.coursera.org/specializations/machine-learning T2

这是 Carlos Guestrin 和 Emily Fox 的 4 门专业课,他们创建了 Turi,后来被 Amazon 收购,涵盖了机器学习的所有重要领域——使用 python 进行分类、回归和聚类,这也是我选择这个项目的原因之一

2.deep learning . ai(Coursera)【https://www.deeplearning.ai/deep-learning-specialization/ T4

这是一个深度学习的 5 部分专业,由 Andew Ng 自己提供,解释热门话题的概念——深度神经网络、CNN、序列模型等

3.深度学习专业的 Udacity 纳米学位https://in.udacity.com/course/deep-learning-nanodegree-nd 101

这是一个为期 4 个月的深度学习概念专业,使用 Pytorch,这是当今深度学习研究社区中新兴和广泛使用的 DL 框架之一。我选择这个主要是因为我想坚持使用 Python 风格的框架,以获得更好的适应性。

顺便说一句,这并不是我尝试过的课程的全部,还有很多课程我只完成了一部分,但没有在这里列出。稍后我会在一个独家故事中讲述我所有的课程经历。

3。做好动手准备

Be ready to code, regardless of your title

虽然这些课程通过一些实际操作项目帮助您获得概念基础,但为了积累专业知识,实践这些概念是很重要的。帮助我的一个活动是参加热门比赛网站的比赛,如 Kaggle,Analytics Vidhya,以了解你的学习情况。例如,我参加了 Analytics Vidhya 的竞赛“贷款预测挑战 III ”,并在总排行榜上获得了第 31 名。https://data hack . analyticsvidhya . com/contest/practice-problem-loan-prediction-iii/lb

尽管这是一场操场上的比赛,但它有助于你建立对所学技能的信心。

4。打开其他学习渠道

课程是学习的来源之一,但不能是学习的唯一来源。挖掘其他学习资源也是很重要的,这样可以拓展广阔的视野。以下是我从事的其他学习活动。

a)其他在线学习内容——订阅 Udemy 上一位新加坡国立大学研究员的“PyTorch 实用深度学习”。https://www . udemy . com/practical-deep-learning-with-py torch/learn/v4/content"

我喜欢他解释卷积滤波器概念的方式,卷积滤波器是一种在图像中寻找特定形状/模式的滤波器。这为上述课程中学习的概念提供了一个不同的视角。

b)关注该领域最有影响力的人的作品——我关注杰里米·霍华德(Jeremy Howard)的作品——我关注 fast.ai 的瑞秋·托马斯(Rachel Thomas)的作品

你可以在 twitter 上关注他们,或者阅读他们的博客,随时关注他们的作品。因为我选择了基于 python 的框架来学习,所以上面几乎所有的都使用 Pytorch 作为 ML & DS 的框架或基于 python 的库。因此,我的列表可能会有所偏差,但本质上的要点是,你需要追随那些在该领域有最大影响力的人,以便与他们正在做的事情保持一致。

c)阅读博客——关注在 ML & DS 领域做开创性工作的顶级技术公司的博客。我通过 Feedly 选择了以下公司的博客。

脸书人工智能研究(FAIR),fast.ai,谷歌人工智能博客,AWS ML 博客,开放人工智能博客。无论如何,这都不是一个详尽的列表,但我只是称之为最重要的

5。不要等着“完美”的 ML/DL 项目落地

一旦学习完成,甚至当学习开始时,通过在解决方案设计中提出 ML、DL 概念,尝试在当前项目中实施学习内容。根据我与财富 500 强客户打交道的经验,大多数客户不会特别要求 ML/DL 项目。他们的优先事项总是满足业务目标,解决方案的设计和方法完全留给我们。所以,我建议你寻找机会,把你学到的东西运用到实际中去。例如,在我的项目中,我开始使用 ML 实现文本分类任务,使用 DL 实现简单的情感分类器。

6。做自己喜欢的项目

除了为客户做项目之外,做自己喜欢的项目对你和公司来说也是一个很好的学习机会。对于 DL 来说尤其如此,因为大多数项目都是文本和图像形式的非结构化数据。因此,从事一些喜爱的项目不仅可以帮助你增长知识,还可以让你的组织注意到你带来的技能,并让你的团队迷上这些概念。

例如,我承担了构建一个原型的任务,使用对象检测技术自动检测汽车牌照。稍后会有更多的介绍,但下面是我和我的团队制作的工具的快照。

License Plate Detection

从业务需求到数据科学任务

原文:https://towardsdatascience.com/from-business-needs-to-data-science-tasks-f23ab2780ec8?source=collection_archive---------22-----------------------

使用数据科学解决业务问题时需要考虑的事项

Image by Gerhard Gellinger from Pixabay

W 如果我请你考虑数据科学工作,你会怎么想?笔记本、数据图表、算法和编程片段的图像很可能会突然出现在你的脑海中。当谈到这类工作时,我们经常关注对特定任务有用的工具和技术,从分类或 NLP,到酷的新 python 库和一些有效的计算技巧,再到最新的 jupyter 笔记本趋势。这幅图似乎在很大程度上遗漏了:需要解决的实际建模任务是如何形成的?

如果我们退后一步思考典型的数据科学家试图实现的高级目标,就会发现两种截然不同的工作流。

探索未知

首先是探索性数据分析。在这种情况下,重点是理解你的数据集,从中发现一些有趣和有用的模式,并以某种方式呈现它们,这将有助于做出决策。在这类工作中,数据集的“所有者”通常很少或根本不提供指导,除了一般的指导,如发现一些异常、寻找低效、重复出现的模式等。您通常会去道路指引您的地方,您的主要任务只是深入了解实际生成数据的过程。工作通常在你用完指定的时间段后就结束了。

构建预测模型

另一种类型的工作涉及创建某种预测模型,该模型将用于以前看不到的数据。如果目的只是向董事会介绍和讨论所获得的结果,这可能是一次性的事情。这也可能最终导致你的模型进入一个工作的计算系统,在那里它将长期存在并繁荣发展。不管是哪种情况,要求你做这种任务的人可能在他们的头脑中有(或多或少)特定的东西,所以即使在开始工作之前,你也需要精确地定义你实际上要做什么。

因为数据科学工作实际上可能是由一些粗略定义的业务需求产生的——我们有两个领域的冲突。前者在精确和严谨的环境中工作得最好,而后者源于经常混乱和模糊的现实世界需求。为了成功,你需要在这两者之间进行转换。

基本上,您需要用业务领域语言来制定需求,将它们转化为定义良好的分析任务,并确定可衡量的成功标准。听起来很抽象?让我们看一些例子。

定义明确的数据科学任务的三个部分

有时候,发现你真正需要做的事情很简单。如果要求您为给定的电子邮件客户端创建一个垃圾邮件过滤器插件,您可以快速地将其转换为二进制分类任务,并假设您的模型可以访问电子邮件内容和元数据。定义成功标准需要假设一些可接受的度量范围,如准确性、真阳性和假阳性等。—您可以根据当前可用解决方案的表现来评估这些。

其他时候事情会变得复杂一些。假设您正在运营一个电子商务网站,您希望在主页上包含产品推荐。这是您的业务需求,可以转化为两个建模任务:

  • 创建一个协同过滤模型,为您有购买历史的登录用户生成推荐,
  • 提供一个基线畅销书推荐,也为刚到你主页的全新用户提供服务。

现在我们仍然需要一个成功的标准来告诉我们我们的结果是否足够。在这种情况下,如果推荐者给我们的主页增加了一些价值,我们就想使用他们。一个简单的标准是:如果推荐者能够获得比当前为主页计算的点击率更高的点击率,就使用推荐者。所以在这种情况下,你要评估你的新方法是否改善了现有的状态。另一个角度是比较你的模型的性能,例如与只使用基线畅销书部分进行比较。无论哪种方式,你在某种意义上引导你的成功标准

结论

在现实世界中,数据科学任务不能想当然,您需要定义它们。要创建一个有用的定义,请记住将业务语言转化为建模任务,并创建清晰且可衡量的成功标准。没有这一点,就很难决定你所创造的东西是否完整,是否真正有用。

从化学家到数据科学家

原文:https://towardsdatascience.com/from-chemist-to-data-scientist-2403de0a5e5e?source=collection_archive---------11-----------------------

Photo by Chokniti Khongchum on Pexels

从小到大,我一直对科学感兴趣。我记得在五年级的时候,我做了一个科学项目,其中包括自制胶水。中学时,我花了一个月的时间阅读有关冰川侵蚀的书籍,并制作了一个小演示,展示给我的地球科学课。2005 年,我开始在布鲁克林的米德伍德高中上学。在我大二的时候,我选修了 AP 化学,这为我以后的学术和职业生涯奠定了基础。我对化学很着迷。化学的规则有逻辑意义,比其他科学课程需要更少的死记硬背。在我高中二年级的时候,我努力参与了学校现有的科学项目。Midwood 提供了 Medsci 和英特尔科学计划等项目,我也加入了这两个项目。Medsci 是为计划被判医学预科的学生准备的,而 Intel 是为想在研究实验室工作的学生准备的。

通过加入英特尔,我开始在长岛大学的一个有机化学研究实验室做志愿者(刘)。在那里,我研究了一种化学治疗剂 Prunustatin A 的合成,但没有成功。够搞笑的是,我看到 2015 年(6 年后)发表了一篇关于这种药物的完整合成。

My First of mostly Research Failures (Source)

2009 年,我开始在布兰代斯大学读本科,在那里我学习化学,辅修数学,并自称辅修物理。我最后写了一篇关于合成 N-杂环卡宾(NHC)用于温室气体小分子活化的毕业论文。这个想法是使用这些 NHC 过渡金属络合物来捕获天然气水合物气体,如甲烷和二氧化碳,用于清洁能源。

One of the few NHC complexes that wasn’t uncrystallizable rust (Source)

这导致了第二个作者的出版(我知道,实际上是加冕)。虽然我在大学时的重点是合成化学,但我对数学和物理产生了浓厚的兴趣,这促使我在康奈尔大学阿南思小组攻读化学物理博士学位。

在康奈尔大学时,我致力于开发用于模拟光合作用过程的数学模型。我主要是用笔和纸做数学,用 Fortran 写代码。我研究了量子力学、经典力学、量子化学、统计力学,钻了那么多抽象的数学兔子洞,这就像是美国的一个场景。

虽然我很享受在康奈尔大学的时光,但我很早就知道我想在工业界从事定量学科。我热爱我在学术界做的工作,但我根本不觉得我的工作对现实世界有任何影响。我研究的方法是利用量子玻尔兹曼分布的路径积分表示的量子动力学*似的延伸。没错。

或者更简洁地说:

Try pronouncing this

Clearly

Proceed with Caution

世界上大约有 5 个人(包括我自己)关心上面的方程式。所以一毕业,我就知道我想要一份对现实世界有一些可实现的影响的工作。鉴于我的定量背景,我考虑了行业中的定量分析师和数据科学家的角色。

从学术界到工业界的转变过程并不容易。毕业后,我在一系列定量分析师、定量研究员和数据科学职位的面试中失败了。尽管我在研究生院学到了很多,但我没有足够的 python 和数据科学经验来在面试中表现出色。我对 Fortran 和 Feynman 路径积分的知识还不够。在工业界,Fortran 就像拉丁语,我只能用它来烦它,费曼路径积分只能和暴力相提并论。

我尽力兼顾论文写作、研究和自学数据科学。我知道数据科学和 python 的基础知识,但我没有足够的应用经验来做好面试。采访中有那么几个瞬间,我觉得自己就像《费城永远阳光灿烂》中的查理一样,在宣扬鸟类法律。

经过两三个月的失败面试,我终于在纽约的一家初创公司找到了一份数据科学的工作。虽然我找到了一份工作令人兴奋,但情况并不理想,因为我基本上是免费工作,并承诺未来的薪酬和公*。我知道从经济上来说这不是一个很好的选择,但从职业上来说,这是最好的选择。我在一家初创公司工作,开发一种工具来检测加密货币交易中的欺诈行为。这份工作节奏快,压力大,迫使我迅速学习 python 和数据科学方法。经过 6 个月的工作,我开发了一个欺诈检测系统,可以实时发出市场操纵警报。

在初创公司工作期间,我积极寻找另一份工作。在那里工作了 6 个月后,“也许有一天我会承诺可能是股票”的价值接*于零。

最终,我以前的化学顾问刘让我联系到了他以前的同事,他当时正在为另一家创业公司招聘研究人员。经过一系列面试,对我的个性、数据科学知识和 python 编程测试进行筛选后,我收到了一份工作邀请。我兴高采烈。免费工作了 6 个月之后,我觉得自己的努力工作和职业成长得到了极大的认可。我受雇于一家重视我现有技能的公司,并投资于我未来的职业发展。一年半后,我有了更多的经验。虽然我还有很多东西要学,但我非常感谢这两家初创公司在没有人愿意的时候给了我一个成长和学习的机会。事后看来,我应该在读研期间采取更多措施来发展我的 python 和数据科学技能。无论如何,我在促成这一转变的过程中感到很有成就感,并对任何经历类似过程的人深表同情。

从杯子到意识(第一部分):杯子和智力有什么关系?

原文:https://towardsdatascience.com/from-cups-to-consciousness-part-1-how-are-cups-related-to-intelligence-8b7c701fa197?source=collection_archive---------28-----------------------

cups 中的哲学,语言基础和 3D 环境的调查

在 MTank ,我们朝着两个目标努力。 (1)在人工智能内部建模和提炼知识。(2)在创造真正智能的机器方面取得进展。作为这些努力的一部分,MTank 团队发布了关于我们工作的片段,供人们欣赏和学习,完全免费。如果你喜欢我们的工作,那么请表明你的支持。提前感谢!

  • 第一部分:杯子和智力有什么关系?
  • 第二部分:从模拟到现实世界
  • 第 3 部分:用 SLAM 绘制你家的地图

“意识哲学”的争论

“真正的幸福是在杯底找到的”

Mtank 团队聚集在一起的一个核心想法是我们对构建“有意识机器”的兴趣——这是几年前我们开始一起谈论的一个模糊说法。如果有足够的时间,我们团队中的每一组成员,无论配置如何,最终都会将他们的谈话集中在这个想法上。一个我们不会与之抗争的对话重力井。

这些对话并不是我们独有的,关于思想和意识的争论无处不在——勒内·笛卡尔' ' 我思故我在',艾伦·图灵的 ' 计算机械与智能'约翰·塞尔的 ' 中文房间辩论',大卫·查默斯' ' 意识的难题',等等。它们是现代和古典哲学思想的主要内容。它们也是现代媒体的主要内容,尽管最初的细微差别经常被压缩成一个通用的终结者盒子。这些想法与推特炒作和现代科技新闻对“机器意识”和“人工通用智能(AGI)”等主题的说法之间有相当大的差异。

当我们看到研究人员认为可以创造一般智力的不同方法时,情况就更是如此了——例如,看到 Yann LeCunGary Marcus 无数次地争论 AGI 需要什么,或者 苦涩的 vs 甜蜜的 vs 更好的一课 。可以说,对于机器是否会等于或超过人类能力的问题,有*无数的想法、理论、定义和假设的答案。

很难确定是什么让一个情报具有普遍性;就单一定义达成一致几乎是不可能的。智力定义不断变化的目标是这个领域本身最有趣的方面之一。哲学家们不断地争论意识是什么,声称它可能是宇宙中最神秘的概念之一,如果不是唯一的话。重力井把我们带到了它的中心。

所以所有这些关于意识的东西都非常令人兴奋,但是我们并不打算为这些最深层的问题提供任何答案。我们也无法阐明智力或意识。但是我们能做的是:

A cup in the hand is worth two in the sink, by instagram handle mizumitodepapu

教机器人以惊人的速度捡起杯子

现实世界中的。教它对杯子进行推理,用杯子来衡量它的价值,并了解杯子,以及数百个不同家庭中与杯子相关的事情。是的,甚至你的

哲学“在每个杯子的底部”

一开始,上帝创造了天堂&地球。最后,MTank 创造了收集杯子的机器人。

True happiness is found at the bottom of a cup, by instagram handle mizumitodepapu

对,那为什么是杯子呢?

从 cups 开始,我们可以抽象出与“意识”相关的困难,并专注于创造真正普遍智能所需的简单、实用的任务(可能是)。对我们来说,AGI 的一个恰当而实用的定义应该是一台能够完成人类所能完成的大部分任务的机器。这可以通过环境领域(即所有家务)或一般角色(如农业、烹饪、会计、体育指导等)来缩小。

还是那句话,为什么是杯子?

因此,正如我们指出的,意识是几个世纪以来,甚至几千年来一直困扰着人类的东西。但是杯子——我们几年前就发现的杯子。在人类发展的整个过程中,杯子一直保持着相对稳定的 T2,它是抵御变化的世界的壁垒,是在时间和地理上稳定的代表。我们喜欢人们紧握着一个不起眼的杯子沉思最大的问题;我们喜欢杯子随处可见

尽管智力是个体的,但它也建立在社会交往的基础上。智能机器将不得不在我们的环境中管理;他们应该适应与现代世界的互动。就我们的目的而言,我们认为家庭环境,即公寓等,将成为一个有趣的落脚点。在这些地方,我们的代理可以与人们一起导航一个私密的空间,并(潜在地)在日常生活中帮助他们。

此外,最*还发布了一系列非常棒的 3D 家庭环境,我们渴望对它们进行测试!

如果意识是足够复杂的系统的一个突现属性,那么我们希望我们的代理人的意识在寻找杯子时出现。我们希望我们的小家伙思考他来回寻找杯子的过程,思考它的用处,思考它的真正价值——思考他的真正价值。

当然,这可能看起来很牵强,没有证据,说实话,有点残酷——但我们承诺随着时间的推移,调整代理任务的多样性、复杂性和难度。只是为了让这种感觉不会像现实世界中经常发生的那样,被极度的无聊所消灭。

捡杯子的原因、内容和方式

从小做起,从简单做起。让我们训练化身代理在现实的 3D 房屋环境中导航,同时拿起杯子,让我们随着时间的推移提高速度(显著地)。当你阅读这篇文章时,有大批博士试图编写像手一样的抓取器来抓取任意物体,还有大批工业研究人员和工程师编写机器人来完成越来越复杂的任务;我们也从这里开始

我们打算快速迭代,完成要求代理理解自然语言指令、要求我们的代理进行交流、要求我们的代理理解的任务配置。指令、环境和新生的常识共同引导他完成根据我们最深处的欲望而定义的任务,例如“拿起杯子”。

Note: Example of task “place cup into the sink” within the AI2Thor environment (see 3D environments later on)

根据我们的定义,自然语言指导的捡杯子涉及强化学习(RL)、计算机视觉(CNN 架构)和自然语言处理(NLP)的结合,以进入语言基础领域。

你所说的神话般的语言基础是什么?嗯,根植建立了超越物体物理存在的概念,即使用抽象符号或表示,然后将它们“根植”到现实世界中表示的某种意义。自然语言本身就是这样一种符号系统。

为了说明这一点,我们可以用“狗”的概念作为例子。当你在这篇文章中读到“狗”这个词的时候,你可能会清晰地看到一种有四条腿、皮毛和其他没有提到的特征的动物。也就是说,我们对什么是狗有一个“共同点”或理解,并且可以讨论这个概念,而不需要一直带着一个例子。

我们把“狗”的概念建立在语言的基础上,也就是说,我们把这个词作为动物的抽象等价物来使用。但是它可以是我们同意的任何其他任意符号,不仅仅是一个单词,也不一定是字母 d-o-g 的组合。语言常常是我们理解另一个人的思维过程的方式,它也会让我们与代理人交流。

任何真正的智能(可能)都需要语言能力,无论是共享的还是内在的,以及代理在现实世界中的体现。然后,所述代理可以根据情况调整他们的内部目标和优先级。

语言指导是我们训练强化学习系统或策略来完成多项任务的方法之一。我们选择它是因为它使人机交流更加方便,同时也支持多任务学习。

最*的工作,像 Devendra Chaplot 的 ,表明语言基础在 ViZDoom 环境中已经触手可及。例如,如果你把一个代理放在一个房间里,房间里有几个随机放置的物体。根据每集开始时作为输入给出的语言指令,代理学习导航到特定对象,同时避开其他对象,例如“去绿色小火炬”。DeepMind 还通过在他们的实验室环境 中向该任务 添加关系指令,例如“旁边的物体”或“在绿色房间中”。

Note: Two successful cases of task-oriented language grounding in 3D environments. Left: DeepMind’s grounding modules in Lab. Right: Gated-Attention in ViZDoom. More complicated tasks have been thought of and performed since the work in these papers e.g. “Place the cup into the microwave and turn it on”

这涉及到多模态输入视觉和语言(参见我们关于 ' 多模态方法' )因为当代理人在环境中观察杯子时,他必须使用自然语言符号系统来建立单词“杯子”的含义。这个“拾起”实际上定义了现实世界中的一个特定目标。

从这里,“杯子”的符号可以被映射——映射到一个主体的特定欲望,或“意义”——在他的视觉系统中寻找杯子的强烈欲望。这样的欲望只是开始。如果我们的代理人有四肢,那么他可能希望操纵杯子并使用他的触觉反馈系统。

我们的代理人将学习杯子的光滑圆形,并将“杯子”的符号与他特别喜欢的光滑圆形联系起来。他会开始明白什么是“杯状”。他会在不知不觉中让自己根植于“杯子”的意义,并开始他从杯子到意识的旅程。

机器人革命万岁,是吗?

All griefs with a cup of tea are less, by instagram handle mizumitodepapu

对于一台机器来说,要实现这个梦想,它需要一个可以玩耍的世界,也就是一个环境。迄今为止,机器人一直被困在严格控制的环境中,大多被囚禁在工厂里。

随着学习机的加速发展,即将到来的机器人革命不可避免。能够处理模糊性的机器,以及我们家所代表的需求不断变化的复杂和动态的环境。大多数人会欢迎一个机器人来把我们从像吸尘、清洁和摆桌子这样的琐碎工作中解脱出来。这样的例子不胜枚举。

那么,这一切的良好起点是什么呢?我们能最终摆脱简单的 2D 雅达利游戏作为我们最强 RL 算法的测试*台吗?简短的回答是肯定的…

在现实世界中对我们的代理人进行培训和试验将是繁琐、缓慢和困难的。然而,通过对典型房间进行足够精确和真实的模拟,我们可以同时训练数千名代理人完成与现实世界相关的任务。也有可能为我们不可能处理或重现的罕见边缘情况进行培训。所有这些都可以比实时操作快得多。

因此,我们的目标是从模拟但真实的 3D 家居环境开始,例如厨房和客厅。有了这些,我们可以创建任务来更好地代表日常问题,包括一个人最常见的请求(“给我泡茶”、“打扫厨房”、“找到我最喜欢的杯子”)。为了在我们的家中部署这些系统,我们需要将知识和技能从模拟世界转移到现实世界。

“模拟注定会成功”——罗德尼·布鲁克斯

“预测:任何你可以模拟和采样无数训练样本的人工智能问题,都可以用今天的算法来解决,如深度和强化学习。”—理查德·索赫尔

3D 环境:不仅仅是简单的游戏

各大公司和研究机构已经做出了巨大的努力来发布新的环境,以应对复杂的 3D 世界中的学习挑战。与 ImageNet 如何推动计算机视觉的进步类似,这一次我们开辟了一条通往不同的、更广泛的、潜在的多模式革命的道路。一个将带来全新的 RL 和 AI 算法,以及将多项进步结合在一起的方法,例如 *期作品 中的 变分推理 世界 模型 RL

****Note: Clockwise from top left: Gibson, AI2Thor, Habitat, UnrealROX, CHALET and House3D (bottom left). Shows examples of typical segmentation and depth masks, interaction, 2D maps, humanoids and other agent types.

*年来,3D 环境的发布数量激增,最终达到了与真实世界相似的规模和真实性。这些环境包括ai2,** HoME MINOSViZDoomhouse 3d 栖息地 这些环境中的许多都是建立在matter port 3DSUNCG(45K 个不同场景)等的 3D 数据集之上的。这些环境有多种不同的方式,即可定制性、规模、操作、物理和照片真实感。**

查看下面的表格!

****

****Source: Above: AI2Thor webpage. Bottom: CHALET paper

可以看出,对于 RL 算法来说,这是一个非常激动人心的时刻。我们已经到了可以在越来越多的困难环境和其中的任务上进行测试的地步。对“智能的、越来越自主的系统”的需求增加,产生了培训它们的环境供应,这在推动环境的研究人员和推动研究人员的环境之间形成了一个反馈回路。

也就是说,在 3D 环境的许多变体中,许多具有可测量指标的明确定义的任务将迫使研究人员最终开发出能够学习一些高级感知、预测、推理、自我运动、操纵、基础、启示、抽象、规划、意识的智能体,最终达到我们所谓的“真正智能”。

令人兴奋的是,但是我们从哪里开始呢?

这些环境各有利弊,所以我们从 倒推我们希望代理做的 。例如,拿起杯子,更多的物理和现实是可取的,可定制性对我们来说是非常重要的。由于我们特别关注与环境中物体的互动,我们选定互动之家** (AI2THOR)作为我们研究的基础。**

如果‘ai2 thor’不是你的茶(呵呵),我们创建了一个最热门的 RL 框架和环境的综合列表,你可以探索一下。可以在我们在 GitHub** 上创建的RL-code-resources**资源库中找到。如果您对选择或列表中的环境有任何问题,请随时联系我们,我们将非常乐意讨论您的想法。****

****Source: Taken from https://aihabitat.org/

AI2Thor

我们从 AI2Thor 开始,因为它的 API 非常简单。在你的终端上写下“pip install ai2thor ”,这几乎是设置的范围,而且环境本身的界面是用户友好的,有很多定制的可能性。

我们很快发现 AI2Thor 不仅有杯子,还允许物体交互,例如打开和关闭微波炉/冰箱,打开水龙头,以及将杯子和其他物体放入/放在容器上。当我们看到这个环境包含杯子并允许与所述杯子进行简单的交互时,我们就抓住了这一点,因为这是完成我们通过人机共生达到综合感知的令人难以置信的崇高目标所需要的本质。或者至少,我们预见到智能体至少能够识别杯子并向它们导航的能力是我们许多算法的良好起点。

在 C2C #cuplife 的下期

在下一篇博客中,我们将更深入地探讨我们正在开发的界面,以使 ai2 成为一个开放的 ai 健身房环境。这样的界面将允许任务定制,我们的 repo 也包括几个最先进的算法的代码,可以在这些任务上进行训练。OpenAI 不仅将 gym 作为一套环境,而且作为一种在代码结构中定义它们的通用方法来推广;我们扩展了任务的概念以及它们与环境本身的关系(虽然是独立的概念)。

请随意喜欢我们的材料,跟随我们或和我们一起笑,因为我们开始了谦虚、雄心勃勃、积极、挑衅和轻松的尝试,讲述从杯子到意识的旅程。如果你等不及下一期,你可以关注我们回购的最新消息。

一定要给我们的回购打个星,恰如其分地命名为cups-rl(可定制的统一物理模拟(CUPS)用于强化学习算法)。否则在这里找到我们,或者在我们的 网站 找到我们。

一如既往地感谢您的阅读!

从杯子到意识(下):从模拟到真实世界

原文:https://towardsdatascience.com/from-cups-to-consciousness-part-2-from-simulation-to-the-real-world-a9ea1249e233?source=collection_archive---------21-----------------------

【AI2Thor 的任务接口,物理模拟和一个名为 Vector 的真实机器人

The moments of suspense as two teams of Vector robots (black vs multi-coloured) face each other before the “battle of the cup” commences. Created using the PyBullet physics simulator.

Round 1: Fight! 10 vs 10 Vectors. Cups fall mid-battle to cause carnage, hence “Cup Carnage”; a violent sport indeed. Scroll down for round 2 with 20 on each team!

在银行,我们朝着两个目标努力:

(1)在人工智能内部建模和提炼知识。

(2)朝着创造真正智能的机器前进。

作为这些努力的一部分,MTank 团队发布了关于我们工作的片段,供人们免费欣赏和学习。如果你喜欢我们的作品,那么请通过与其他也会喜欢它的人分享来表达你的支持。提前感谢!

  • 第一部分:杯子和智力有什么关系?
  • 第 2 部分:从模拟到现实世界
  • 第 3 部分:用 SLAM 绘制你的家的地图

“如果大脑创造了一种感知无线电程序,并用它来指挥有机体的行为,那么什么是倾听呢?而不是像一些泛灵论者认为的宇宙本身,或者像二元论者声称的物理宇宙之外的某个实体,我想说的是,意识体验是我们注意力内容的一个模型:它是虚拟的,是有机体模拟自我模型的一个组成部分,并由注意力导体产生”

巴赫的认知架构中的现象体验和知觉束缚状态

介绍

在我们的上一篇博客中,我们简要介绍了一些常见的关于意识的思想实验和争论。再一次,我们想提醒你,我们不打算为这些关于意识本质的深层问题提供答案——我们只是专注于很好地拿起杯子。世界级的世界杯选拔赛,以及它对人类的潜在意义。

也就是说,从唯物主义者的角度来看,世界仅仅是由物体及其相互作用组成的 T21。因此,让我们把“对象”放回客观状态,并让我们的代理进入各种环境,开始尝试有趣的任务。在主观世界的任何蛛丝马迹开始潜入它们的“自我模型”之前,我们萌芽中的意识——代理人——必须从某个地方开始。

在这一集里,我们深入探究了我们的特工可能生活的几个世界——我们的小家伙将迈出第一步的地方。他的奖励功能将引导他完成伟大的旅程——从他的模拟进入我们的模拟。我们将谈到我们对令人惊叹的开源 3D 照片逼真环境 AI2Thor 的功能进行扩展的工作,以及将我们的工作引入更具物理真实感的模拟(PyBullet 和 Gazebo)所采取的步骤,我们还将介绍一个名为 Vector 的简单而真实的机器人,它可以解决现实世界的导航问题。

欢呼吧,让采杯开始吧!

快速回顾一下

第一部分 中,我们谈到了项目目标、语言基础,并调查了一些 3D 环境。最后,我们详细讨论了名为 AI2Thor 的 真实感 Unity 环境。如果你对这些概念不熟悉,或者你想了解我们的思考,你可以在这里找到第一部分。

ai2 存储环境包装

一些人认为,你完全可以通过完成越来越困难和多样的人类任务来到达 AGI。按照这种思路,能够在模拟和现实世界中有效地指定任务,并且能够客观地衡量每个任务的性能,这一点很重要。因为我们想做很多任务,所以我们需要一个通用接口来定义一组不同的任务,并使其可定制以满足我们所有的需求

此外,我们希望帮助研究社区的其他人在 3D 环境中训练强化学习(RL)算法,并使他们能够为他们的特定目标修改这些环境。

输入 AI2Thor 和我们的贡献:

  • 我们创建了一个通用结构,用于定义 AI2Thor 环境中的环境设置和可重复实验。
  • 一种在我们的环境中运行通用 RL 算法的简单方法,同时遵循 OpenAI Gym 环境接口(step()和 reset())。
  • 任务界面旨在允许更快地创建不同的奖励功能和任务定义,即任务的核心和灵魂,例如“拿起杯子”。
  • 基于策略和价值的算法基准示例(A3C 和 Rainbow ),带有大量注释说明,有助于用户理解算法背后的细节和数学,以及如何在我们的环境中运行它们的完整过程。请关注下一篇博客,我们将在那里对此进行更深入的探讨。

最终,我们希望能够对来自整个开源世界的不同最先进(SOTA)算法进行基准测试。我们试图尽可能多地保留原始源代码,但也对它们进行了调整和微调,以适合我们设计的任务。但是让我们利用 gif 的力量从抽象的想法走向现实。

Note: Example task of “put the cup in the microwave” which can be made within our task interface.

上面我们可以看到一个简单任务的执行,在一个模拟的厨房里, 把杯子放进微波炉 。我们看到,在 AI2Thor 中,家庭环境是复杂和现实的,加上与环境的互动是相当丰富的。在下面的图片中,我们看到一个浴室场景,一个特工在训练捡起我们用 Unity 游戏引擎放在地上的杯子。

Note: An example of an RL agent training on our “NaturalLanguagePickUpMultipleObjectTask” in one of our customised scenes (edited with Unity).

简化任务定义的包装器

我们的包装器(【https://github.com/TheMTank/cups-rl】)试图通过实现相应的 gym env 子类,使 AI2Thor 可用作 OpenAI gym 环境。我们还包括一些任务、代理培训和脚本的示例,以简化学习过程。我们正在不断改进它,以提供更好的用户体验,但这是迭代的,所以请耐心等待。

健身房环境提供了恰到好处的抽象,因此可以通过在每集开始时调用 reset 函数和 step 函数在每一步向环境提供您的操作,以通常的 RL 方式运行您的实验,如下所示:

如果你想“按原样”使用环境,这是非常强大的但是我们发现当试图在保持这个简单界面的同时使它可定制到许多任务时,这是有问题的。遵循 gym 的建议,我们应该定义一个尽可能通用的环境类,然后从这些基类中的一个或几个继承,为特定的任务定制环境。

我们认为这个过程对于我们的用例来说可能过于复杂,因此我们决定采用一种不同的方法来使它对我们来说更加直观。我们希望对我们有意义的东西,对最终用户来说也更容易理解。我们相信,当目标是数百个任务和数不清的“任务变化”时,这是更具可伸缩性的,但仍然希望保持环境的重要、公共部分,在所有任务之间共享。

相同界面,更多控制

基本环境和该环境中的特定任务之间的自然划分将我们分为两大类:'ai2 torenv和' BaseTask '。这里的目标是将我们对 AI2Thor 的包装与奖励函数的细节以及为特定任务重置环境的细节分离开来。

前者包括场景的细节,将要考虑的对象,像分辨率或灰度格式这样的图像细节。后者包括该特定任务所需的初始化/重置条件,以及在每一步观察到的奖励的计算。

我们为什么要这样做?

这样,用户可以独立于环境细节定制和创建任务。我们通过将基本任务划分为它们的目标的子类,并依靠底层环境代码来运行并在任务间保持不变来实现这一点。

同时,我们确保用户不必为了实验定义而将他的思想分成独立地考虑环境和任务。我们通过使用单个配置文件来指定环境和任务参数来实现这一点。

作为一个例子,如果我们想要改变任务存储库上给出的示例任务来拾取杯子,而不是像在健身房环境中通常做的那样,从环境中创建一个新的子类并修改 step 和 reset 函数(可能添加大量的样板文件和意大利面条代码,可能还有一些 bug ),我们将创建一个新的任务类,如下所示:

然后轻松修改配置文件,在几秒钟内改变环境和任务条件:

Change the task to pick up (and put down) apples as fast as possible instead

任务和配置组合允许“任务变化”,例如 PickUpTask 允许您指定“苹果”或“杯子”采摘或两者兼而有之;每一项都是相同的任务,但都有特定的变化。

如果所有这些关于包装器、任务和通用代码接口的讨论让你感到兴奋,那么不要犹豫去尝试一下。请随意添加一个问题,或者您自己的拉动请求,包括新的任务,这样您就可以将您的结果与其他人进行的同类实验进行比较。您可以随时给我们发电子邮件,询问任何问题或要求澄清。

我们希望 GitHub README 能提供足够的信息,但是请随时联系我们,因为我们会很快回复。从您那里获得反馈将有助于我们使它更加强大,并可能使更多的人在方便的时候使用它进行自己的实验和环境定制。所以不要害羞!

模拟物理是通往真实世界机器人的道路

我们的现象体验对我们自己来说是非常真实的,但我们的自我却不是真实的。换句话说,当托诺尼和科赫(摘自他们 2015 年关于综合信息理论(IIT)的论文)认为只有物理有机体才能有意识体验,而模拟不能时,他们完全搞反了:物理系统不能有意识,只有模拟可以。”

巴赫的 现象体验与感性束缚状态

AI2Thor 提供了一组不同的照片真实感场景和一个简单操作的物理引擎,通过它我们可以测试我们代理的泛化能力;然而我们总是渴望对环境的每一部分有更精细的控制和物理真实感。

例如,完全指定我们代理的身体的能力:传感器、致动器、关节、链接等。此外,我们希望这些部件能够与丑陋的物理现象相互作用,这可能会导致我们的机器人摔倒,或者在非常令人沮丧的情况下,上帝保佑,甚至打破一个杯子。

希望这样,我们至少可以避免打破真实的世界杯。

这种程度的真实性和对环境的控制使我们能够更接*于最终将这些算法部署在真实的机器人中,在真实的家庭中。让我们能够以外科手术般的精度控制附属物,并随着时间的推移改善对象操作,例如,机器人手指穿过杯柄或使用勺子微妙地倒糖。

但在此之前,让我们介绍两位最新的团队成员,他们非常适合测试我们早期的假设:Vectors 00301ed100a10115。

介绍我们的第一只机器人豚鼠 Vector

他可能很小,但对于我们想要测试的许多常规任务和算法来说,他是完美的。机器人公司 Anki 从 Cozmo 开始,最*随着他们著名的 kickstarter 活动转移到 Vector。

我们必须跟上潮流,因为它有强大的 python SDK 和从您的台式机/笔记本电脑设备运行任何 python 代码的全部功能,即从 vector 接收状态信息(图像、3D 姿势、电池等),并向机器人发送适当的命令(将左轮向前移动 50 毫米,充电)。

这让我们可以在真实世界和 Vector 的世界中自由测试许多最先进的算法,例如同步定位和映射(SLAM)、主动 cup 识别、路径规划导航到 cup 或 RL 纯端到端方法等。

Note: Full specification of Vector. It’s incredible the amount of things that can be fit on such a small and inexpensive robot; truly jam-packed.

此外,我们试验了一个 ROS 包,它将允许我们管理来自传感器、致动器的独立控制,并使用强大的库来处理导航和感知问题,例如路径规划和 SLAM。

能够模拟矢量也很重要。我们发现 Anki 慷慨地分享了他们的设计文件(OBJ 和 MTL 格式)。我们还创建了相应的 URDF/SDF 文件,我们可以与你分享,这样你就可以玩向量,即使不买他!这些允许我们在模拟中模拟机器人的物理交互。

在本博客的第一部分中,我们介绍了许多不同的 3D 环境,重点是照片真实感和其他特性,但是除了 ai2 之外,很少有其他的具有广泛的物理特性。即使是阿尔托的物理学对于我们的需求来说也是有限的。了解了这一点,我们知道我们必须找到一种方法来增加我们模拟的物理真实性,例如,通过指定力、扭矩、关节、摩擦和详细对象的惯性。

好奇什么样的模拟在物理精度、控制和定制方面是绝对最好的?嗯,研究了一段时间后,我们最终选择了 PyBullet (也像 ai2thor 一样易于安装,“pip install pybullet ”)和 Gazebo (它是为用 ROS 控制的机器人设计的)。使用这些工具我们可以获得多少功率和控制的示例可以在下面的多个不同环境中的模拟矢量中看到(使用 URDF/SDF 文件):

Physics simulations can literally bring us to the moon. Try to casually handle that edge case in the real world! Created with Gazebo and ROS.

GOOOOOOOOOOAAAAAAAAL! Created with Gazebo and ROS.

And now we’ll leave you with round 2! The final round of “Cup Carnage”. 20 vs 20 Vectors. At the end, we see that one Vector got to run away with his cup into the far distance, clearly making this a win for the multi-coloured team. Created using PyBullet.

解构通往具身 AGI 的道路

老实说,我们不知道我们会在哪里结束。我们不断地重新规划、完善和重新确定我们的目标,并愿意快速转向最有前途的技术,以增加机器人在世界上捡起杯子的数量;我们真正的关键绩效指标 (KPI)。

为了最大化这个 KPI,我们不断地讨论人们可以分割 AI 问题的许多方法(“分而治之”),以及在我们的代理设计中选择哪些抽象来帮助我们向通用机器迈出微小的一步(例如,无模型与基于模型,PyTorch 与 TensorFlow)。例如,一个有趣的划分是将一个机器人(甚至一个人)的硬件分成几组传感器致动器,两者都使软件分别执行感知控制。以下是对此观点的一些思考,以及我们计划如何使用这些抽象:

感知

就人类的感知而言,主要的感官是视觉、触觉、听觉、嗅觉和味觉。后两个对我们的机器人来说是一个不寻常的起点,而前三个似乎是最重要的。

更具体地说,视觉可能是最有用的起点。为了在我们的代理中实现“视觉”,我们将使用我们的 计算机视觉专业知识 来部署诸如对象检测、深度估计、SLAM 和对象姿势识别等技术,以使我们的代理能够了解他所生活的世界。触觉和听觉会及时出现。也许有一天,我们的代理人会感受到一杯新茶的温暖,或者听到水壶烧开的声音。

控制

在控制端,对于取杯任务,我们将其分为导航抓取。我们接下来的几篇博客将关注导航到特定位置和特定物体(如杯子)的艺术。在这之后,我们将抓住杯子,举起它,轻轻地把它放在新的位置。在每一种情况下,我们都有更传统的技术以及更现代的“学习”方法供我们使用。

下一期 C2C (#cuplife)

在我们的下一篇博客中,我们将讨论我们在 cups-rl 报告中的一些任务上运行的两个 SOTA RL 算法。这应该向读者展示我们打算如何使用它来对不同的算法进行基准测试,当然,还有发现、挑选和囤积许多许多杯子。无模型 RL 范式中政策和基于价值的方法之间的史诗般的战斗。

可供选择的两种算法是: A3CRainbowDQN 。你会把钱押在这些硬汉中的哪一个身上?跟随我们的媒体去寻找答案吧!

*P.S. we changed priorities and decided to get our feet very wet in mapping algorithms like SLAM in part 3 of this blog. We realised that understanding where you are located and having a map is a universally useful and a fundamental pillar for many tasks for our embodied agents and for them to understand their environment and clearly AGI embodied agents will need to be able to do this. However, check out the repo for the code for these A3C and RainbowDQN RL models. What can we say, the road to AGI is long, winding and treacherous. We must be willing to adapt fast. Check out part 3 [here](https://medium.com/@TheMTank/from-cups-to-consciousness-part-3-mapping-your-home-with-slam-8a9129c2ed58)!*

从杯子到意识(第三部分):用 SLAM 绘制你的家

原文:https://towardsdatascience.com/from-cups-to-consciousness-part-3-mapping-your-home-with-slam-8a9129c2ed58?source=collection_archive---------9-----------------------

SLAM 简介,深入了解 SLAM 前端和传感器套件

Our favourite animated robo-mascot treasure hunting for cups with his map. By instagram handle mizumitodepapu

在 MTank ,我们朝着两个目标努力:
(1)在 AI 内部建模和提炼知识。(2)朝着创造真正智能的机器前进。作为这些努力的一部分,MTank 团队发布了关于我们工作的片段,供人们欣赏和学习,完全免费。如果你喜欢我们的工作,那么请表明你的支持。提前感谢!

  • 第一部分:杯子和智力有什么关系?
  • 第二部分:从模拟到现实世界
  • 第 3 部分:用 SLAM 绘制你的家

介绍

“你所需要的只是一个计划、一张路线图和朝着目的地前进的勇气”——厄尔·南丁格尔

在本系列的前一部分中,我们谈到了通往 AGI 之路是如何被分为感知和控制的。在控制范围内,导航和抓取是构建用于家务的通用机器人路线图的关键部分。但是正如柴郡猫在《爱丽丝梦游仙境》中对爱丽丝说的那样,

如果你不知道你想去哪里,你走哪条路真的重要吗?

这是两部分中的第一部分,我们将讨论我们的看似被绑架的机器人如何找到他们的方位。我们是什么意思?从他们的角度来看,每栋房子都是他们被扔进或突然醒来的神秘地方。正如人们可以猜测的那样,这一发现过程几乎完全属于感知领域,从逻辑上讲,这也是我们应该开始的地方。一个人必须先感知 ,然后才能相应地行动,包括了解你的周围,绘制你的环境,即了解哪里是什么,哪里是“被占领的”,哪里可以畅通无阻。

考虑一下制造能完成一般任务的机器人的第一步。忘记让机器人做单一的任务,例如,用 roomba 打扫地板,用 alexa 告诉你时间,还有一个烤面包机器人。为了执行一般任务,我们需要我们的机器人知道它的环境,即识别什么是障碍,以及东西在哪里,并使用这些信息来导航和完成任务。

似乎很简单。

模拟中的映射

在第一部分中,我们介绍了我们挑选杯子的哲学动机和愿望,并介绍了一组模拟的 3D 房屋环境。在第 2 部分中,我们介绍了 ai2 house 环境的包装器、一些强化学习(RL)实验和两个名为 PyBullet 和 Gazebo 的特定物理模拟,使我们能够将机器人向量放到月球上。

知道了映射是我们的下一个里程碑,我们自然开始在 PyBullet 模拟中实现初始映射。由于 PyBullet 包含深度和彩色 RGB 图像,以及相机的姿态(位置和方向),我们可以使用来自虚拟相机的深度信息来将每个 2D 像素转换为其在空间中的 3D 坐标,创建所谓的点云。

使用该点云,我们可以创建一个网格数据结构,定义机器人可以移动到哪里以及机器人周围的障碍物在哪里,即占用网格。这种深度图像,到点云,到占用网格管道是计算机视觉和机器人学中非常常见的操作。

扩展一个官方的 PyBullet 代码示例,从深度信息创建一个点云,我们能够在模拟的厨房中获取地板上和屋顶下的所有点。由此,我们创建一个占用网格,每个网格单元显示10 cm2区域的可能可通过性。这样,网格中的每个区域都被分配了一个被占用的概率。事实上,这是机器人导航最常见的格式和方法。

Note: Our own simulated PyBullet kitchen and living room with dynamic objects (e.g. beer bottle, bowl, cup, etc) and occupancy grid mapping with exact pose information. Within this GIF, we also present a semantic object occupancy grid map, mapping aggregation and a simulated robot with 2 wheels and a caster wheel moving around the living room with depth and segmented views displayed from the viewpoint of the robot. The semantic map describes which grid cells are occupied by specific objects. The aggregation combines the information from 3 viewpoints (local maps) into one merged map.

那么我们学到了什么?

这教会了我们很多关于占用网格、传感器模型以及将多个视点聚合到一个大的占用网格中的知识。但是上面提到的一切都是使用 PyBullet 提供的相机的精确姿势(位置和方向)找到的。我们知道接下来有必要找到一种方法在世界中定位代理的姿势,特别是在真实世界中。

正如我们在上一篇博客中提到的,我们决定从模拟转向首先让算法在真实机器人上工作。一个简单的原因是:与虚拟场景相比,真实摄像机会出现更多问题。

在未来,为了扩大我们的机器人可以处理的任务、杯子、水壶和环境的数量,我们肯定需要模拟。但是现在,真实的世界杯选拔赛每次都胜过黑客帝国风格。如你所见,通往 AGI 的道路漫长、曲折且充满危险。这一切都始于首先找到自己。

同步定位和绘图(SLAM)

“直到我们迷失了,我们才开始发现自己” —亨利·大卫·梭罗

使用已知的定位(映射问题)创建地图相对来说容易,在已知的地图内定位也相对来说容易(定位问题)。两者都有许多解决方案和变体,但是如果我们既没有机器人的姿态,也没有地图,会怎么样呢?也就是说,当我们不知道自己身在何处时,如何创建环境地图?

这个,相对来说,就没那么容易了。

回到我们被绑架的机器人,他刚刚被放在一个未知的房间里。一睁开眼睛,它怎么知道自己在哪里?大多数人会自然地使用他们周围的参考地标,即床、电视的角落、开着的门,来粗略地定位他们自己在环境中的位置。映射和本地化是密不可分的,它们相互需要,就像烤面包需要黄油一样,本质上是一个鸡和蛋的问题。

为了以极快的速度拿起杯子,并在机器人从未见过的家中操作,它应该能够在环境中定位自己,同时绘制地图,即找到世界各地的三维位置。这就是为什么在我们的旅程中,我们不可避免地到达了同步定位和绘图(SLAM) 领域。

SLAM 研究可以通过用于解决问题的传感器套件进行分类(稍后将详细介绍)。例如,您可以使用一台相机(或一组相机)通过在环境中检测到的地标来找到机器人的姿势。但是当灯关闭时,你可能不相信这些相机的弱点,或者视觉场景可能会令人困惑,在这种情况下,你可以使用雷达来代替。或者,就像大多数制造自动驾驶汽车的公司一样,如果你需要一个更可靠的传感器,可以发现距离你数百米远的物体的高细节,你可以使用昂贵的激光雷达。

没有一种传感器可以解决我们所有的问题。我们将需要将许多传感器结合在一起(即传感器融合),以寻求建造能够以我们能够理解的方式理解世界的机器人,同时保持低成本。为此,我们决定将精力集中在视觉算法上。即基于摄像机的 SLAM,或如文献中所命名的视觉 SLAM (V-SLAM)。

两年多前,我们在我们的计算机视觉报告中提到了 SLAM,现在我们很高兴有机会真正深入这项迷人的技术。如果您正在寻找一篇好的评论,或关于最新技术的详细信息,我们推荐:

  • SLAM:基本算法 第一部分 第二部分
  • 视觉里程计和视觉 SLAM 概述:移动机器人学的应用
  • 同时定位和绘图的过去、现在和未来:走向健壮感知时代

典型 SLAM 系统的架构

一个典型的视觉 SLAM 算法有两个很容易并行的主要部分,这意味着即使两个部分互连,它们也可以独立运行。根据文献,我们将这些称为“前端”和“后端”。

前端

前端将传感器数据抽象成易于评估的模型。它负责预处理输入,以及检测和跟踪相关的标志,以估计我们观察它们的姿势序列。

在 VSLAM 的情况下,实现这一点的算法是视觉里程计(VO),它本质上是根据显著的视觉特征来计算两帧之间的相对姿态(变换)。

最常见的方法是从一帧中提取关键点(例如使用 SIFT、ORB ),然后在下一帧中匹配这些相同的关键点或者用光流跟踪它们。此外,在匹配/跟踪来自不同位置的那些观察到的关键点时,这些算法的性质可能导致错误数据关联的误差,因此通常在之后应用另一种算法来移除可能的离群值,这些离群值可能会将附加误差传播到我们的估计,例如随机样本一致性(RANSAC)。

另一个重要的考虑是,如果我们持续跟踪每张图像的每个显著点,我们将消耗大量的内存,包括大量的冗余信息。出于效率原因,通常仅观察到所有图像的子集,这些“关键帧”由选择算法选择,同时仅在关键帧之间匹配和跟踪观察到的特征。一个简单的关键帧选择算法是每第 5 或第 10 帧取一个,但其他方法只涉及如果图像与前一帧相比有足够大的变化就添加一个关键帧(例如,测量变化的视差或关键点移动的距离)。

Source: ORB-SLAM in the KITTI dataset (Sequence 00) YouTube link Note: The top view is from the KITTI dataset with ORB features overlayed from ORB-SLAM2. On the bottom we see top-down trajectory in green but only the blue frustums are keyframes. In red are the features which are tracked.

Note: By adapting a simple VO example in Python (from here) and by using every 10th frame as a keyframe we were able to get reasonably good results on a sequence in one of our houses. The top down trajectory is shown on the right on the black background as we go around a table 3 times with the camera attached to a chair. But this example was carefully cherry-picked; other sequences didn’t show as reliable results on the trajectory estimation. In general, the algorithm suffers from severe drift problems, e.g. by using only every 5th frame as a keyframe this caused caused the drift errors to accumulate much faster. This per keyframe error can be blamed on many factors e.g. calibration, initialisation or monocular scale issues.

此外,我们可以计算两个连续点云之间的转换(例如,使用迭代最*点(ICP)算法的点云配准)来定位代理的轨迹。

Note: Pointcloud registration is about finding the transformation from one pointcloud to the other so that they overlap and align together in a way that makes most sense. The GIF shows the resulting point cloud (yellow + blue) after the registration step is performed, i.e. one of the point clouds (yellow) is transformed to be aligned to the other one (blue: which is the reference to align to), optimising the transformation so that overlaying this transformed point cloud onto the reference represents a single scene as consistently as possible. This obviously implies some overlap and consistency between both pointclouds. This relative transformation between two frames/pointclouds can be the basis of RGB-D or LiDAR odometry. For reference, a famous algorithm for computing this registration is called Iterative Closest Point (ICP).

此外,我们可以使用在图像中发现的特征的较低维度的表示,而不是它们的完整描述,例如通过使用“视觉单词包”方法(DBoW ),其创建可能特征的字典,并将图像转换为由可能特征(或字典中的“单词”)的组合形成的向量,用于更压缩的表示。然后,这可以用于位置识别/重新定位和循环闭合。

Source: Bag of Visual Words in a Nutshell Note: First row are the images, the second row are the image patches from these images and the third row are the histograms “bag of visual words” in a simplified four word dictionary.

后端

后端通常是使用从前端提取的所有信息的组件,以便构建、扩展和进一步校正机器人的轨迹和地图。它包括几个算法,如束调整,其目标是通过在一对以上的帧上实施重投影一致性来纠正错误。它还扩展到使用估计的不同姿态生成和优化图形,以及比较由前端存储的视觉单词包,以完成重新定位和循环闭合。

闭环包括当机器人识别出先前看到的位置时对图形进行修正。利用这些信息,我们可以减轻在整个 SLAM 过程中可能遇到的累积“漂移”误差。

为了让您更清楚地了解这些不同部分如何相互作用,这里是我们最喜欢的 SLAM 系统之一的高级架构。

Source: RTAB-Map slides Note: Without the back-end, SLAM essentially reduces to odometry. RTAB-Map is an amazing SLAM algorithm that works out of the box and creates a dense pointcloud and an occupancy grid. It can be used with an IMU, stereo camera and an RGB-D camera (more on what these sensors do below)

传感器套件:单声道、立体声、RGB-D、IMU

不言而喻,不同的传感器配置可以使 SLAM 的任务更容易或更困难。通常,你的传感器提供的信息越多越好,但是对于额外的传感器,你还需要以一种巧妙而有原则的方式合并和融合它们的信息。从计算角度来说,这可能会变得非常昂贵。理想情况下,通过使用多个传感器,它们的优点和缺点相互抵消,系统变得异常稳定,但这种选择通常需要权衡。

单目 SLAM 涉及使用单个摄像机作为 SLAM 相应算法的输入。这受到比例问题的影响,即从单目 SLAM 系统的角度来看,如果相机相应地缩放,我们无法区分普通家庭和“玩偶之家”之间的大小差异。这个比例问题可以通过各种方式解决,例如良好的初始化程序或使用物体的已知长度或真实世界的距离。尽管处理这些缺陷在算法上可能更加繁琐。就机器人硬件和架构而言,拥有单个传感器是一个非常简单和优雅的解决方案。一些著名的例子是 MonoSLAM,ORB-SLAM 和 LSD-SLAM。

Note: Example of tracking points using a monocular camera.

从初始位置(从红色图像)的一组“n”个观察点(在这种情况下是房子上的 4 个),我们在场景中移动并捕捉第二个图像(以绿色突出显示)。使用匹配算法,我们可以在第二幅图像中找到第一幅图像上观察到的点,并使用该信息来计算相机的运动(里程计)和场景的结构(观察点的 3D 坐标)。来自运动的结构(SfM)是另一个著名的领域,与单目 SLAM 有许多相似之处。通过查看关键点在两帧之间移动了多少,我们可以计算第二帧中相机的外部变换。

我们发现我们的一台 RGB 摄像机的水*视场(FoV)非常小,为 69.4 度,如果移动太快,可能会导致跟踪失败。更大的 FoV 理论上允许即使在更长的位移之后也能跟踪相同的关键点。在未来,我们还将试验更宽 FoV 的相机,如鱼眼镜头相机,它在给定的时间内观察更大的区域,因此与较窄 FoV 的相机相比,在以更高的速度跟踪观察到的场景方面,可能会使我们的生活变得更容易。

Note: With a common laptop webcam we can barely capture the center of the living room (right), whereas the 200 degree wide angle camera (left) allows us to look at the entire living room, part of the kitchen on the left and also a small peek into the bedroom after the corridor to the right.

立体视觉涉及使用两个摄像头来寻找场景的结构。从不同的已知位置同时拍摄两幅图像具有显著的优点。例如,在单目 SLAM 中,匹配发生在不同时间的两幅图像之间,这意味着在这些时间之间,场景中的任何对象都可能移动,这将完全破坏视觉里程计计算,而在立体视觉中,匹配是在同时拍摄的图像之间进行的,即不需要移动。然而, stereo SLAM 实际上大多数 SLAM 仍然会有这个“动态对象问题”,因为它们仍然必须跟踪跨多个帧拍摄的相同特征。流行的立体声灌篮是 VINS 融合或软式灌篮。

此外,典型的匹配算法需要在计算上昂贵的匹配搜索,但是由于在这种情况下摄像机的相对位置是已知的,我们可以将两个图像投影到一个假想的*面,以便使搜索更容易并且防止匹配上的一些错误。这个过程称为立体纠正,如下图所示。

Note: The dotted rectangles represent the original unrectified images. The epipolar lines help on matching by constraining the search to the epipolar lines marked in solid red. The solid black rectangles represent the rectified images, in which the epipolar lines are all parallel to the horizon, allowing for a more efficient search of possible matches.

Note: Example of the left and right stereo infrared images (from the RealSense D435i camera we bought in the top and bottom left) with a calculated disparity image on the bottom right and colour image in top right. If you alternate closing your left eye and right eye, you should observe that objects closer to you appear to jump in position more compared to objects further away (see the pen in both infrared images being in different positions). This is essentially how stereo vision can calculate disparity/depth (bottom right). The pen is so close that it gives a blind spot to one camera from calculating disparity in certain parts of the disparity image. Calculating this disparity from two (preferably rectified) stereo images essentially computes the inverse depth map which can be visualised with a colour map going from white to yellow to red, in which white represents close distances and yellow is further away.

被动对主动。立体视觉不一定非要用被动式 RGB 相机计算视差图,也可以做主动式立体。主动立体将光束投射到世界上,通过使用变形模式,它可以帮助提高深度的准确性。更多关于整流和有源与无源立体声的信息在这里。

RGB-D SLAM 通常指 SLAM 系统的输入是彩色和深度图像时。深度可以通过使用商业深度相机来实现,商业深度相机通常包含立体相机,但是如何检索和优化的细节留给深度相机的内部。由于具有这些像素的深度信息,RGB-D SLAM 能够计算密集图,即包括所有可见像素的密集图。与上述稀疏特征(即少量关键点)相比,这代表了可以在密集地图中使用和显示的丰富信息。在下一篇博客中,我们将介绍 RTAB 地图(之前展示的架构),这是一个优秀的 RGB-D SLAM 系统,但其他著名的例子包括 KinectFusion 和kintinulous。

Note: We bought the RealSense D435i depth camera from Intel. Above is the RealSense viewer. In the color RGB image (bottom left) we can’t see as much in dark areas compared to the infrared images (top 2) which can see better in the dark. Also enabling and disabling the emitter will show or remove the white projected dots. The emitter improves depth accuracy (you can see as it turns off and on in the depth image in the bottom right) and is good for textured areas. One can disable the IR emitter and use the infrared cameras as a typical stereo pair but it is grayscale only.

Note: The depth accuracy is high and it works out of the box. Active stereo RGB-D cameras works better at low light as well as night time. The camera also contains an internal IMU and we can see the accelerometer and gyroscope display on the right. Half way through, we switch to the 3D point cloud viewer.

Note: An example of the RealSense rs-motion program which demonstrates how a Complementary Filter can be used to estimate orientation but not position on the D435i using the inbuilt IMU only.

惯性测量单元(IMU) 通常包含加速度计和陀螺仪(有时还包含磁力计)。在 D435i 包含的 IMU 中,第一个测量加速度,第二个测量角速度,两者都测量 3 个自由度(DoF ),从而在这个 6 DoF IMU 中形成 6 DoF。许多其他变体也是可能的,例如,内置的磁力计将使其为 9 DoF,更简单的 3 DoF IMUs 通常用于自动驾驶汽车。

然而,从这些中提取位置涉及双重积分(因为加速度的积分是速度,而速度的积分是位置),甚至现有技术的解决方案也涉及大量的定位偏差,这些偏差将随着时间的推移而显著累积。这就是所谓的漂移,也是为什么 IMU 定位系统通常需要结合视觉反馈来减少漂移。

IMU 的主要用途是根据原始数据以高频率计算机器人的方位。例如,在我们的 D435i 中,加速度计可以设置为 250Hz(每秒 250 次测量),陀螺仪可以设置为 200Hz,并且可以对原始数据使用滤波器(例如卡尔曼或互补滤波器)来计算 IMU 的方向。

当你在 VO 系统中增加一个 IMU,就叫做视觉惯性里程计(VIO) 。如果您选择并仔细调整正确的 VIO 系统,还有许多方法(松耦合和紧耦合)可以输出几乎“无漂移”的定位。我们推荐“ 用于飞行机器人 的单目视觉-惯性里程计算法的基准比较”论文,以了解使用 IMU 的顶级 VIO 或 SLAMs 的概况。在下一篇博客中,我们将谈论一些伟大的 VIO 系统,如 VINS-Mono 和 ROVIO。

所有 SLAM 狂热者可能都梦想最终的 SLAM 系统能够处理任何情况(弱光、低纹理、快速运动、循环闭合、遮挡、动态对象和场景),并且仍然非常健壮。我们称这种神秘的神话生物为“跑酷满贯”

虽然这可能是纯粹的废话,只是一个荒谬的梦想,但适用于快速无人机的算法,如这些 VIO 系统,接*速度和灵活性的要求。因此,也许其中一个可能是我们正在寻找的跑酷大满贯,或者也许在未来的某一天,我们梦想中的大满贯将会到来。这个博客系列的第 4 部分将是我们试图找到这个街头顽童 SLAM 算法,用技术问题无情地测试它,并奖励一个 SLAMdog 百万富翁 100 万美元。

Source: ROVIO YouTube Note: Incredibly fast movements, could this be our ultimate champion SLAM, the Parkour SLAM?

基于功能与直接

Source: wavelab waterloo slides. Very good slides that are worth checking out to go deeper into many direct methods and compare them on a high level with feature-based SLAMs.

从自 2012 年以来一直主导计算机视觉的深度学习(DL)革命的角度来看,很容易被大多数 SLAMs 使用“经典”关键点或特征检测器(例如 SIFT,ORB,FAST,Harris corners)的事实所迷惑。考虑到围绕 DL 的大肆宣传和良好业绩,这是令人惊讶的。那么为什么没有深球呢?

首先,重要的是要提到,在“经典”分类管道中,关键点描述符被用作特征工程步骤,然后典型的分类器被用于输出类,例如支持向量机(SVM)。这个范例被 DL 完全破坏了,但是主要的收获是关键点和关键点描述符是不同的:关键点描述符是描述以关键点为中心的图像块的统计属性的值的向量,关键点指的是点本身,即它们的位置。

关键点在这里是非常常见且直观有用的,因为 SLAM 找到这些检测和跟踪的 2D 关键点所代表的 3D 点的几何关系和位置。事实上,这就是 VSLAM 所做的事情。

SLAM 可能会随着 DL 的使用而得到很大的改进——关键点检测、语义或者可能是“端到端 SLAM”。然而,经典的特征检测器目前做得很好。有关 DL 和 SLAM 如何相互帮助的更多信息,请查看 Tomasz Malisiewicz 关于实时 SLAM 和深度学习 vs SLAM 的精彩博客。

Note: This image highlights the difference between keypoints (2D pixel positions) or image descriptors of an image. In general, it’s important for feature detectors to repeatedly find re-identifiable parts of an image which can be found in successive frames e.g. corners, edges, points. Whereas the descriptor of each keypoint is a vector describing an image patch around the keypoint.

Note: Example of keypoints extracted using ORB features in ORB-SLAM2 algorithm running on a sequence from one of our houses. When referring to the word “features” it can mean a combination of the keypoint and its descriptor or just the keypoint. At the end of the GIF we see an example of loop closure fixing the accumulated drift. Keep an eye out for part 4 of this blog which covers the back-end and loop closure for greater depth on this.

SLAM 中还有另一个新兴的范例,它避免了稀疏关键点检测器的使用。这些所谓的“直接方法使用像素强度——来自图像的未经处理的 RGB 值——来直接估计相机的运动。这最小化了光度损失,而基于特征的方法通常最小化了几何损失。光度学本质上意味着我们正在计算如何使用直接来自两幅图像的像素值将第一幅图像投影扭曲成第二幅图像。通过最小化强度差异,我们对来自原始图像和经变换的合成生成图像的变换实施一致性。

Source: link Note: This highlights the projective transformation (T) between the first image to the second. Finding the correct T is the goal here.

直接方法中有许多变化。例如,我们可以使用 中的稀疏点直接稀疏里程表 (DSO) 。中的 DSO 论文很好地比较了密集+直接、密集+间接、稀疏+直接、稀疏+间接这四种组合。我们鼓励你去看看,特别是如果你像我们一样感到困惑的话。

另一篇著名论文 半密集视觉里程计 (SVO) 是基于特征和直接方法的混合。这意味着它仅跟踪来自边缘和角落的高梯度像素(使用直接光度误差),但是依赖于基于特征的方法来联合优化结构和运动。这些组合就是为什么它被认为只是“半直接”的原因。

Direct 有可能能够跟踪图像中纹理较少的部分,而基于特征的 SLAM 可能会发现这更加困难。许多著名的满贯狂热者相信直接满贯最终会战胜间接满贯。但是基于特征的 SLAM 的结果说明了一切。只有时间能证明一切。

结论

总之,我们讨论了一切,从映射背后的动机,模拟中的映射,到本地化和映射如何迫切需要彼此(SLAM);以及许多相关领域(例如视觉里程计、SfM)和不同 SLAM 算法之间的变化轴(例如它们的前端与后端、传感器套件等)。).不仅如此,还包括使用的具体方法,例如直接与基于特征、稀疏与密集地图/点云,以及这些系统是否具有全局优化和闭环。为了说明不同的 SLAM 是如何变化的,你可以在下表中找到许多著名 SLAM 之间的比较。

Source: Visual SLAM algorithms: a survey from 2010 to 2016 Note: This compares many different SLAMs across their varying dimensions. For example, the visual SLAM algorithms used with the raw image data could be feature-based (ORB-SLAM, MonoSLAM) vs direct (DTAM, LSD-SLAM) vs semi-direct (SVO) vs RGB-D (KinectFusion, SLAM++).

我们希望这个博客能够在很大程度上介绍和总结 SLAM 的前端组件。在某种意义上,这个组件主要负责计算相机的里程表。在我们看到的一些案例中,它可以在不需要任何后端组件的情况下产生高度精确的定位。

然而,机器人的轨迹越长,漂移就会积累得越多,即使每 10 公里仅*移 1 毫米或旋转 1/100 度,这种漂移也会增加。因此,在我们看来,需要一个后端系统和识别以前位置的能力。幸运的是,我们将这个组件的细节留到了本博客系列的下一部分,其中将包括束调整、姿势图创建和优化,以及循环闭合。

但是最激动人心的部分还在后面!在下一期的 C2C (#cuplife)中,我们将展示我们对 SLAM 中大量先进系统的选择和评估,包括我们测试过的一些算法以及我们认为该领域未来可能的发展方向。敬请期待!

从数据科学到 AI?

原文:https://towardsdatascience.com/from-data-science-to-ai-fcaa0e464010?source=collection_archive---------19-----------------------

一个是人,另一个是机器…它指引着我们!

让我们玩个游戏,好吗?对于我给你的每个单词,你会告诉我在人工智能和数据科学之间首先想到的是什么?好吗?没有欺骗,没有宗教战争(如果你觉得有些奇怪,强迫自己朝着一个方向,问问自己为什么)。

准备好了吗?

走吧,一次一个,阅读并意识到你的联想——
数据科学还是 AI?

  • 自治
  • 统计数字
  • 机器人
  • 机器学习
  • 终结者
  • 光学字符识别
  • 2001:太空漫游
  • 形象化

完成了吗?好,我先来:

  • 自主— AI
  • 统计学— 数据科学
  • 机器人— 人工智能
  • 机器学习— 都有!
  • 终结者—
  • OCR(光学字符识别)——数据科学
  • 2001:太空漫游—
  • 可视化— 数据科学

这些和你的相配吗?如果他们这样做,原因可能是文化或时代精神。如果我们把时间拨回到 30 或 40 年前,一个自动识别你的糟糕书法的系统[抱歉,10%的人用摄像机拍下了不清晰的书法 T20,这仍然是人工智能。“会阅读的机器眼”!今天,OCR 可以在移动设备上完成,尽管它并不总是准确,但它太普遍了,以至于不再被视为人工智能。

为什么有些东西可以不被认为是人工智能?数据科学也会发生同样的情况吗?首先,人工智能是一个负载很重的术语,与科幻小说有很强的关联,也与人类思考和学习的能力有很强的关联。这些联系引发了我们的情感反应,或者与我们的年轻、我们的激情,或者甚至是我们对什么使我们成为人类的哲学思考有关。

现在…数据科学有没有让你思考是什么让你成为人类?如果不是,那是因为它是一个比人工智能更精确的术语,而且没有人工智能那么神秘。

但是还有更多。更具体的东西。

数据科学是人类——人工智能是机器

AI 是一台机器获取并应用知识和技能的能力,而数据科学是一个人对数据的系统学习和应用。人类可以利用数据科学来创建人工智能系统的组件。相反的情况只发生在科幻小说中,只有在遥远的星系中,人工智能系统才有能力进行数据科学。

在这之间呢?机器什么时候变得智能?

没有硬性门槛。人工智能需要 4 种基本能力:感知、知识保留、思考和适应。这些包括感知、过滤、解释、存储、抽象、推理、理解、学习和在环境中行动。这些功能越发达,系统就越智能。因此,即使是计算器也有一定程度的智能。类似于狗、海豚和任何人类的智力水*。如果一个人工智能系统胜过人类,那么它通常被称为拥有超级智能(除了非常具体的任务,截至 2019 年,我们离超级人工智能还非常远)。

那么,为什么 AI 也经常被描述为一个巨大的技术领域,包括机器学习、深度学习、统计学等等?一个关键的原因是人工智能的 4 种能力可以用这些方法来开发。如果是人类应用它们,那就是数据科学创造了人工智能;如果是机器,那就是 AI 创造 AI。例如,当机器学习系统被训练时,它是由机器完成的,因此它是一个解决某个任务的人工智能系统。数据科学是围绕培训的一切。这也意味着许多数据科学工具具有智能的某些能力,可以被定义为人工智能。如上所述,人们是否愿意称它们为人工智能,或者“超自动化”取决于文化因素。

Ouroboros

数据科学可以产生人工智能

然而,数据科学并不是产生人工智能的唯一途径。有人认为进化、、量子力学以及其他尚待发现的方法也能产生人工智能元素。尽管如此,今天数据科学和人工智能之间有着强大的协同作用:虽然数据科学实际上让事情发生,但人工智能为我们提供了强大的工具和抱负,为我们指明了道路。

从开发到生产——让 Flask 应用程序在 AWS 上运行所需要知道的一切

原文:https://towardsdatascience.com/from-dev-to-prod-all-you-need-to-know-to-get-your-flask-application-running-on-aws-ecedd4eec55?source=collection_archive---------24-----------------------

获得正确的配置,确保它是安全的,确保通过端点访问资源,并有一个漂亮的渲染,…所有这些都是因为 AWS 而变得容易!

作为一名机器学习工程师,我从未真正面临过把我的算法发布出去的问题。嗯,直到最*,当我决定开始我的多重创业之旅…不幸的是,当你开始时,你没有 DevOps 或软件工程团队。这些人对客户使用这些服务的世界很有经验,他们知道如何跨越最后一步,让你的产品从零到一。

现在,我不得不花几个小时阅读教程和文档来学习基础知识,最后,将我自己的算法作为全球可用的独立容器化服务。出于可复制性的明显原因,我对这些步骤进行了模板化,我非常乐意与您分享这些模板!😃【模板托管这里。]

准备战场!

他的初始化步骤至关重要,取决于你的实践。在这里,我揭露了我做这件事的方式,但是你可以自由地创新。到目前为止,我唯一的假设是,你有一个适当的 AWS 帐户,并且你知道如何在服务之间导航!

  • 安装并配置 AWS CLI: AWS 教程。
  • 安装并配置 AWS Elastic Beanstalk CLI: AWS 教程。
  • 下载模板:您目前有三种选择:您可以从文件夹模板中单独下载每个文件;您可以克隆 project Challenger 的整个存储库,这是我存放模板的地方;您可以使用 subversion 通过以下命令下载特定的文件夹:
sudo apt install subversion
svn checkout [https://github.com/Coricos/Challenger/trunk/templates/beanstalk](https://github.com/Coricos/Challenger/trunk/templates/beanstalk)
  • 定义您的开发环境:
virtualenv -p python3 beanstalk
cd beanstalk
source bin/activate
pip install -r requirements.txt
  • application.py中构建您的 flask 服务器!首先在您的本地机器上试一试,检查一下一切都运行正常,并确保将服务器启动封装在__main__中。另外,这是 AWS 的特定要求,但是您的应用程序的名称应该明确为application

有用!现在怎么办?

B 因为我发现 AWS Elastic Beanstalk 是运行我的应用程序的最佳服务,我天生就愿意展示它。为什么?主要是因为在 beanstalk 实例上运行的内容可以在任何其他类似的服务和云提供商上产生。这给了您无限的灵活性(我甚至没有说使用 Docker 来获得更好的可部署性)。

该服务由一个运行在 EC2 实例上的基本容器组成,该容器链接到一个 S3 存储桶。在我们的例子中,应用程序本身不需要大量的计算能力(到目前为止我们没有谈到深度学习),所以我们将选择 t2.micro 实例(单个虚拟内核和 4gb RAM)。从那以后,它将只与配置有关,因为 AWS 使我们的生活更容易:您不必考虑子网、安全组、VPC、IP 网关、NAT 这是在您生成实例时自动创建和定义的。尽管如此,对于那些需要控制它们的人(在 VPC 工作或使用 RDS),你可以通过.ebextensions文件夹中的security.config来配置一切。关键配置以.elasticbeanstalk文件夹中的config.yml文件结束:

environment-defaults:
  {flask-app}:
    branch: null
    repository: null
global:
  application_name: {my-app}
  default_ec2_keyname: {my-ec2-key}
  default_region: {region}
  profile: {my-profile}
  workspace_type: Application

对于配置部分,没有太多事情要做:给应用程序和服务起一个好听的名字(~ environment);如果需要,定义它的 EC2 键名,否则使用缺省值;选择要在其中生成实例的区域;选择了您的用户配置文件;使用Application负载*衡器(这是我的建议)。

从那里,您已经可以访问并可视化您的在线运行的应用程序,使用一个名称,例如 {flask-app}。{id}。{zone}.aws.com 。然而,这缺少了一些东西:信息传输过程中的加密。你可能不是我,但我真的不喜欢使用不使用 HTTPS 的网站或终端…

把公主带到城堡里!

不幸的是,没有 SSL 证书,您的实例无法使用 HTTPS。通常,人们会使用 OpenSSL,这非常简单,但是在我们的例子中,AWS 通过他们的证书管理器服务又一次让它变得简单。如果你想让它更有趣,可以通过 53 号路线服务购买一个域名。然后,您可以使用 AWS 为您的 beanstalk 创建自己的证书,或者与您新获得的域名相关(我向您保证,这样看起来更专业)。现在,必须配置两个对象来重定向请求:一个是Canonical Name,比如 {cname}。将您的 EB 实例作为值的域名;一个Alias,比如{ 别名 } 。您的 EB 实例的域名。有了这两张唱片,你就可以上路了!

请用 HTTPS!

您错过的是信使:HTTPS 请求到您的实例的特定重定向。这个信使被称为监听器,有一个简单的配置:将外部世界的 HTTPS 定向到实例上的 HTTP。(可在listener.config买到!)

option_settings:
  aws:elb:listener:443:
    InstancePort: 80
    ListenerEnabled: true
    InstanceProtocol: HTTP
    ListenerProtocol: HTTPS
    SSLCertificateId: {certificate}

但这还不是全部!为了确保您的实例接受 HTTPS,您必须配置服务器:这就是https.config为您做的!;)

部署部署部署。

一旦你弄清楚了你的 Flask 应用程序,如何填充所有缺失的配置设置,如何获得你的 SSL 证书,是时候部署了!(不需要初始化,我们已经为此构建了配置文件。)

eb create flask-app

想要更多吗?给你!

以下是我不想在之前的教程中介绍的一些内容,但对于接下来的步骤同样重要:

  • 使用环境变量!当你在生产环境中工作时,记得要多疑;)我的做法通常是用我的变量填充一个environment.json文件,并用deploy-env.sh prod将它们部署在弹性 Beanstalk 实例上。
  • 如果您使用标题(例如Flask-JWT),请确保将headers.config添加到您的.ebextensions文件夹中。
  • 如果你使用 websockets (例如Flask-sockets),你将不得不使用 Docker 镜像并使用websocket.config。我可能要为那部分做另一个模板(如果那是你要找的,就同时 ping 我),因为我花了不止几个小时才弄明白…

Examples using such Configurations: project-element & project-aster

有兴趣保持联系吗?😄Twitter|LinkedIn|Github|Medium

从计量经济学到机器学习

原文:https://towardsdatascience.com/from-econometrics-to-machine-learning-ee182f3a45d7?source=collection_archive---------5-----------------------

为什么计量经济学应该成为你技能的一部分

作为一名拥有计量经济学硕士学位的数据科学家,我花了一些时间来理解让机器学习成为与计量经济学不同的学科的微妙之处。我想和你们谈谈这些乍一看并不明显的微妙之处,它们让我在整个旅程中都感到好奇。

首先…什么是机器学习?…什么是计量经济学?

计量经济学 是将统计方法应用于经济数据,以便赋予经济关系以实证内容。更准确地说,它是“基于理论和观察的并行发展,通过适当的推理方法对实际经济现象进行的定量分析”

机器学习(ML)是计算机系统用来执行特定任务的算法和统计模型的科学研究,不使用明确的指令,而是依靠模式和推理。它被视为人工智能的一个子集。机器学习算法基于样本数据(称为训练数据)构建数学模型,以便在没有明确编程执行任务的情况下做出预测或决策

很好,所以他们看起来都需要数据,都使用统计模型,都做出推论,所以根据他们的定义,机器学习似乎可以处理更广泛的问题,而不仅仅是经济。那么,计量经济学为什么还存在?!这是我在开始计量经济学研究的同时发现机器学习时问自己的问题。

作为一名未来优秀的经济学家,我需要完美地处理数字,拥有扎实的[Statistics](https://en.wikipedia.org/wiki/Statistics)背景,成为[linear algreba](https://en.wikipedia.org/wiki/Linear_algebra)[Mathematical optimization](https://en.wikipedia.org/wiki/Mathematical_optimization)的专家,最后拥有处理数据的计算机技能。这些技能将用于理解、演示应用我的回归、分类、聚类算法或时间序列预测。在这一年里,我将深入学习一些算法,如[Linear Regression](https://en.wikipedia.org/wiki/Linear_regression)[Logistic Regression](https://en.wikipedia.org/wiki/Logistic_regression)[Kmeans](https://en.wikipedia.org/wiki/K-means_clustering)[ARIMA](https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average)[VAR](https://en.wikipedia.org/wiki/Vector_autoregression)……等等。等等?*这些算法也用于机器学习!*****

从理论效率到经验效率

机器学习和计量经济学的一个根本区别在于它们的理论基础。计量经济学有扎实的数理统计和概率论基础。算法在数学上是稳健的,具有可论证的和吸引人的性质,这些算法主要基于其基础的稳健性进行评估。

对于机器学习,数学当然不会缺席,但它的存在是为了解释算法的行为,而不是展示其可靠性和吸引人的属性。这些算法主要根据它们的经验有效性进行评估。一个非常有启发性的例子是 Xgboost 算法的成功,它的成功归功于它在几个机器学习竞赛中的统治地位,而不是它的数学证明。

从精确到*似

另一个区别是,计量经济学只有一个解决方案,给定一个指定的模型和数据集,参数回归的参数是使用代数公式计算的。系数的[best linear unbiased estimator](https://en.wikipedia.org/wiki/Gauss%E2%80%93Markov_theorem) ( 蓝色)由普通最小二乘 (OLS)估计器在某些假设得到尊重的情况下给出。这里的“最佳”是指与其他无偏的线性估计量相比,给出估计的最低方差。

而大多数机器学习算法过于复杂,无法用单一的数学公式来描述。他们的解决方案是通过称为训练阶段的迭代方法在算法上确定的,训练阶段的目标是找到最适合我们数据的解决方案,因此由机器学习算法确定的解决方案是*似的,并且只是最有可能是最优的。

从参数模型到非参数模型

计量经济学模型(即:大多数时候是参数模型)是基于经济理论的。然后使用传统的统计推断工具(如最大似然法)来估计参数模型 mθ中参数向量θ的值。渐*理论然后发挥了重要作用(泰勒的发展,大数定律和中心极限定理…等)。

另一方面,在机器学习中,通常构造非参数模型,几乎完全基于数据(没有进行底层分布假设)和所使用的元参数(树深度、惩罚参数等)。)通过交叉验证、网格搜索算法或任何超参数优化算法进行优化。

从理论到实证的验证

你会明白的,模式会和以前一样,计量经济学依靠稳健的数学测试来验证模型,我们通常说的是模型的[goodness of fit](https://en.wikipedia.org/wiki/Goodness_of_fit)。它通过假设检验、残差的正态性评估、样本分布的比较来评估。我们还将讨论[R²](https://en.wikipedia.org/wiki/Coefficient_of_determination) ,它是从自变量中可预测的因变量方差的比例,以及[AIC|BIC](https://en.wikipedia.org/wiki/Akaike_information_criterion),它通过[p-value](https://en.wikipedia.org/wiki/P-value)评估每个模型相对于其他每个模型或变量评估的质量。

机器学习模型的评估将取决于它的预测,其基本思想是,如果模型能够很好地预测,那么它已经成功地学习了数据中的隐藏模式。为了确保模型不会过度拟合,数据集将被分为训练集和测试集,然后使用[cross-validation](https://en.wikipedia.org/wiki/Cross-validation_(statistics))砖块来验证模型的泛化能力,并确保数据分离没有偏差。最后,我们将使用 KPI 来衡量与现实的差距,如[RMSE](https://en.wikipedia.org/wiki/Root-mean-square_deviation), [MAE](https://en.wikipedia.org/wiki/Mean_absolute_error)[Accuracy](https://en.wikipedia.org/wiki/Accuracy_and_precision)

从理论趋同到目的分歧

计量经济学和机器学习都试图定义一个函数,该函数定义一组将对预测变量建模预测变量:

****

  • ɛ是随机变量 i.i.d .,规律 N (0,σ2)的实现也称为残差,来自计量经济学,否则 y = f(x)属于机器学习。

理论上,这两者在现阶段似乎是一致的,但在方式和目标上,他们也会有分歧。机器学习的目的是 y 在大多数情况下,而计量经济学的目的是估计每个预测因子的β。

计量经济学的主要目的不是预测而是量化一种经济现象

从理论到实践!

如果我们在实践中观察这些差异,我们将从一个经典的计量经济学模型和一个最广泛使用的模型线性回归开始。为此,我们将通过主要服务于机器学习模型的[sklearn](https://scikit-learn.org/stable/index.html)库的实现和更加面向计量经济学的[statsmodels](https://www.statsmodels.org/stable/index.html)库的实现来观察我们建模的结果。

**#import library
import pandas as pd
import numpy as np
import seaborn as sns
import statsmodels.api as sm
from sklearn import linear_model#import data 
iris = sns.load_dataset("iris")**

让我们比较一下这两种实现

**dummies = pd.get_dummies(iris["species"], drop_first=False)
iris = pd.concat([iris, dummies], axis=1)
iris.head()**

由于物种是一个分类变量,我们需要将它转换成计算机可以处理的格式,所以我们转向一次性编码格式。让我们从机器学习开始。

我们可以通过模型对象提取模型系数和斜率参数β0。让我们用 statsmodels 试一试。

与 sklearn 相比,Statsmodels 给了我们很多信息,我们得到了非常好的 R,我们之前讨论过的 AIC、BIC、每个变量的系数和警告。让我们试着预测一下:

我们得到了相同的 R 和非常好的 mae 和 Rmse …但是我们认为两个模型的系数不相等。Statsmodels 警告我们,我们的模型有可能是[Multicollinear](https://en.wikipedia.org/wiki/Multicollinearity)!这是指一个多元回归模型中的两个或更多解释变量高度线性相关的情况,这意味着我们的数据集中有冗余信息。这些信息来自物种变量,我们必须放弃一个类别,因为很明显,如果鸢尾不是 setosa 或 verginica 它是杂色的。

这意味着,尽管我们的模型有很强的 R,因此有很强的预测能力,但这些系数是有偏差的,无法解释的。

sklearn 尚未将此信息传输给我们。让我们通过传递 drop_first = True 来更正它。

Statsmodel 删除了它的警告,我们现在有了无偏系数。此外,偏度接* 0,峰度也意味着我们的残差可能是正态的,Jarque-Bera 的概率证实了这是一个很好的模型。让我们重新运行我们的 sklearn 模型:

最后,我们得到了相同的,让我们做一些阅读。可以看出,在所有其他因素都相同的情况下,花瓣长度增加 1%会使花瓣宽度增加 0.24 厘米。在分类变量的情况下,我们总是指缺失类别。我们可以看到,在所有因素都相同的情况下,verginica 物种的花瓣比缺失物种 setosa 宽 1.04 厘米。所有的 p 值在 5%的阈值下是显著的,因此我们的系数被认为是稳健的和无偏的。我们已经看到了线性回归模型的分析,它也可以转置到分类。逻辑回归在模型分析中提供了一个非常有趣的读数,我会在以后的文章中讨论比值比的读数。

阅读模型分析,我会在以后的文章中讨论优势比的阅读。

最后

计量经济学的概率基础无疑是它的强项,它不仅具有模型的可解释性,还具有不确定性的量化。然而,机器学习模型的预测性能是有趣的,因为它们允许我们突出计量经济学模型的不良规范,并且其中一些算法更适合于非结构化数据。计量经济学旨在严谨,但成为一种非常相关的经济因素分析工具,如果你的经理要求你量化一种影响,它除了给你统计和数学上的合法性外,还可能是相关的。

从错误到自主

原文:https://towardsdatascience.com/from-error-to-autonomy-207e285e62f5?source=collection_archive---------24-----------------------

数字误差的艺术潜力。

到目前为止,计算自治的想法是有问题的,科学界还没有达成共识。自从 19 世纪开始计算和数据分析以来,阿达·洛芙莱斯已经构建了一种思想,使机器创造多样化的作品合法化,然而,洛夫莱斯认为,机器不可能“创造”没有预先编程的东西。(洛夫莱斯,1842 年)。计算自治的可能性在 XX 世纪被正式考虑,即由著名科学家艾伦·图灵,他反对洛夫莱斯的陈述。

艾伦·图灵认为,现在可重新编程的计算机可以模拟人类的智力,如果为此目的对它进行足够的编程的话。在这个意义上,数学家鼓励在计算机编程中包含伪随机算法(图灵,1950)。这些目前被定义为随机过程:允许做出看似随机的决定,但可以通过数学概率计算的算法集。一方面,这是整合计算艺术的基础之一,因为该设备开始被探索作为其随机结果的创造力的助手,这些随机结果似乎模拟了人类的创造力。另一方面,艺术家们的实验方法论暗示了计算艺术的一个重大问题:艺术家不再认识自己的输出。

Vilém Flusser 和 Edmond Couchot 都用黑盒类比的方式处理了艺术家与技术的关系:不知道产生图像的机制的功能。Couchot 认为任何由技术中介产生的图像都是模型过程的模拟,因为编码和解码过程模拟并介入了媒介的特性。与图像的代表性内容相关,在后来的研究中,Hito Steyerl 将的劣质图像概念化:在数字毁灭的美学中趋向于抽象的图像。这些图像往往会遭受意想不到的失败,并收集编码伪像、,即由内容的编码和解码过程引起的众所周知的失真。在 Steyerl 看来,它们就像图像中的瘀伤,来自数据的压缩和传输,这证明了它们的动态和运动。(斯特耶尔,2009 年)

在用于读取和解码图像的介质的过程中,有时会发生改变数字内容的数据故障。正是从这个事实出发,Steyerl 反映了人类希望变得像数字图像一样的愿望。她认为,这些图像作为事物独立存在,因为它们表现出自主性并参与我们现实的构建,这些事物积聚力量,但也退化(STEYERL,2010)。与此同时,丹尼尔·洛克在他的“数字自主性”文章中重新思考了计算误差,认为这是一种不太可能的数字重新定义,它是由推动进步的自身法则决定的。用作者的话来说,“作为事物的图像通过它所隐藏的小故障保持其自主性”,小故障是由错误导致的编码工件。(鲁尔克,2011 年)。

数字的转换会导致意外的和不可避免的错误,这些错误通常是由于对内容的操作及其持续的时空更新而发生的。在实践中,错误过程的起源在于数字信息的不断重新适应,这从其“明显”的故障中揭示了媒体的证据。通过以上,调查图像的编码文物使我探索它们在艺术领域的潜力。像罗莎·门克曼这样的艺术家试图保存和再现这个错误的时刻。从她的角度来看,失败可以鼓励对系统功能的新理解。它可以导致一个反身的时刻,反过来,可能会显示自己是进步的外骨骼,一个宣泄的时刻(MENKMAN,2011)。内容的条件容易受到不同解释的影响,这些解释可能不完全是负面的,因为它可以引导用户到临界维度或揭示计算系统的一些重要因素。

“错误是对规范的违反,事实上,这代表了新的创造性解决方案的巨大潜力。”

有趣的是,这是 2018 年 9 月举行的电子艺术节(Ars Electronica festival)的主题,当时就当前对错误的需求进行了辩论,以促进数字自主性的改善。例如,在神经网络的功能和预测分析的结构中。这些过程通过计算和测量误差以及随机变异程度来优化,以自我管理它们的行为并模拟更自治的系统。

在这一点上,我承认:反乌托邦式的技术完全能够超越人类能力的想法可能永远不会实现。然而,为模拟机器行为而输入的数据的日益增加的复杂性反映了其未来的能力。计算系统对故障的敏感性与其行为的形式特征有关,计算机被认为是一个封闭系统,只在确定性过程下起作用。从这个意义上说,由于法典编纂的有限性,对任何技术过程的操作的限制似乎是显而易见的,但在实践中,这些限制确实在不断扩大其可能性。因此,数字自主的可能性取决于计算的未来发展和插入数据的复杂性。

人工智能对计算创造的期望仍然很高,并且正在迅速发展。更多的智能物智能体正在被关注,并且显然可以在无人监管的环境中(半)自主操作。可以预见的是,可能会产生一种机制,这种机制结合并适应他们的发现,以调整他们的自主行动,其目的不是取代人类,而是通过模拟我们的行为来帮助生产。假设这些艺术领域的自主能力,我想知道计算设备是否能够模拟艺术家的创造力?正如图灵会说的:如果他们“被教得足够多”;我想象那将成为一种与我们完全不同的创造力。然而,我承认,基于算法计算来定义某种创造能力是有风险的,因为这与人类的内在复杂性直接相关,而这是目前无法模拟的。

从 FaceApp 到 Deepfakes

原文:https://towardsdatascience.com/from-faceapp-to-deepfakes-3d1048713da0?source=collection_archive---------10-----------------------

关于挪用与人工智能的思考

考虑到我在摄影和性别研究方面的背景,我对森村泰正和 T2 辛迪·雪曼的作品感兴趣也就不足为奇了。两位艺术家都使用自画像来探索身份的表现,经常参考其他媒体。谢尔曼因她在《T4》系列电影《无题剧照》中扮演二流电影女演员而出名。森村以再现著名的历史艺术品而闻名,将自己作为主题插入其中。两人都投入了大量的工作来改造自己,模糊了神话和现实之间的界限。

My take on “American Gothic” with help from FaceApp.

现在,由于人工智能(AI)的发展,任何拥有智能手机的人都可以变形或将自己(或其他人)插入另一个场景。

当 FaceApp 在 2017 年火起来的时候,我花了一段时间才最终试图明白这到底是怎么回事。交换面孔,看看我几十年后可能的样子,对我来说没多大作用。但后来我顺便参观了格兰特·伍德的标志性画作美国哥特式。我无法告诉你看到那个农民冲我咧嘴笑时我有多开心。

My friend Travis and a stranger in the background, brought to life with Mug Life.

Mug Life 是另一款利用神经网络和深度学习的应用。它通过将静态图像转化为 3D 动画来提升游戏质量。这张照片让我开心多了,尽管我从未在自己的照片上用过它。

Me after Meitu. I look nothing like this in real life.

不过,在和某人讨论了我们作为动漫角色的样子后,我还是把自己的一些照片放到了美图应用程序中。这个应用程序以一种别人没有的方式让我反胃。该公司将自己宣传为“移动美容体验的先驱”,使用“获得专利的面部识别和机器学习算法来绘制每个用户独特的面部特征。”应用程序中的设置清楚地表明了美丽对美图的意义:更苗条的脸,更大的眼睛,没有雀斑或胎记的更亮的皮肤,以及化妆。

美图提出了几个问题。就个人而言,我担心认识我的人看到上面的照片后会一本正经地说:“你在那张照片里看起来真的很好!”但是也有关于数据隐私的问题。这是整个美白的问题。FaceApp 的“热”过滤器也做到了这一点,尽管这显然是一个缺陷,而不是一个功能。这位首席执行官为道歉,称“这是由训练集偏差引起的底层神经网络的不幸副作用,而不是有意的行为。”在像 FaceApp 这样的东西中复制偏见可能不会对整个世界产生太大影响。但这些同样的“不幸的副作用”也在人工智能的其他应用中发挥作用,包括贷款决策和预测性警务。

让我们在这里控制它。到目前为止,这些应用主要用于娱乐,人们为社交媒体制作迷因和自拍。这些图像与赞助广告、品牌大使和影响者一起填充提要。像机器人 Lil Miquela 这样的有影响力的人已经出演了广告活动,登上了杂志封面,在 Spotify 上发布了单曲,最*被聘为《Dazed》杂志的艺术编辑。

CGI influencer Lil Miquela with actress Tracee Ellis Ross.

像密凯拉这样的虚拟影响者的崛起带来了一些令人兴奋而另一些人害怕的可能性。公司可以雇佣容易驾驭的模特来推产品。Quantum Capture 首席执行官摩根杨预测名人可能会开始使用 CGI 替身:“围绕这一点建立了一个非常有趣的收入模式,其中你可能无法接触到人才本身,但你可能会接触到他们的数字化身,而实际的人将从使用他们的化身中赚钱。”

这些虚拟形象引发了许多其他问题,包括关于拨款和谁受益(经济上和其他方面)的问题。不管怎样,我们面对的未来是,人类和人工智能之间的界限只会越来越模糊。

用于驱动 Mug Life 等应用程序和创建头像的技术已经帮助创建了如此令人信服的复制品,以至于人们无法区分什么是真实的,什么是虚假的。显然,就连凯丽·费雪也认为她在《T2》和《星球大战外传:侠盗一号》中的出现是因为旧镜头,而不是 CGI 制作。

“We’re entering an era in which our enemies can make anyone say anything at any point in time.”

虽然对娱乐业来说很棒,但乔丹·皮尔在他的视频中强调了“深度假货”的潜在危险,美国前总统奥巴马似乎称唐纳德·川普为“完全彻底的笨蛋”这个视频可能会像病毒一样传播开来,因为许多人觉得它很有趣,但人们的担忧是真实的。

Deepfakes 已经被用来试图通过虚假的色情视频骚扰和羞辱女性。这个术语实际上来自于一个名为 Reddit 的用户的用户名,他通过使用 TensorFlow 建立生殖对抗网络(GANs)来创建这些视频。现在,情报官员正在谈论弗拉基米尔·普京利用假视频影响 2020 年总统选举的可能性。关于 deepfakes 作为对民主和国家安全的威胁以及如何检测它们的更多研究正在进行。

从个人层面来说,我觉得很纠结。我欣赏这些技术为表演和娱乐带来的可能性。我对算法和它们能产生什么一样感兴趣。但我也担心它们如何被使用,被谁使用,以及会产生什么(不)预期的后果。

感谢阅读!想法、问题和反馈总是很受欢迎。

从脸书到创业公司:数据科学正在成为一个工程问题

原文:https://towardsdatascience.com/from-facebook-to-startups-data-science-is-becoming-an-engineering-problem-4625d45ef2e0?source=collection_archive---------21-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

塞尔坎·皮安蒂诺在 TDS 播客

编者按:这是迈向数据科学播客“攀登数据科学阶梯”系列的第七集,由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:

如果你关注了我们的播客,你会知道一个清晰的主题在一个接一个的采访中浮现。每当我们向我们的客人询问数据科学的发展方向时,我们都会得到两个答案之一:要么 1)数据科学正在成为产品/业务角色,数据科学家需要像精通数据的产品经理一样思考;或者 2)数据科学正在成为一个工程问题,数据科学家需要更像工程师一样思考。

在今天的播客中,我们采访了一位专注于考虑第二种可能性的人:数据科学正在成为工程师的游戏。Serkan Piantino 曾担任脸书人工智能研究所的工程总监,现在运营机器学习基础设施初创公司 Spell。他们的目标是为数据科学家开发开发工具,让在云上训练模型像在本地训练模型一样容易。这段经历,再加上他在脸书的经历,让他对数据科学家应该使用的工程最佳实践以及整个领域的未来有了独特的看法。

以下是我从聊天中得到的最大收获:

  • 大多数人在工具上投资不足。任何时候你发现你在一遍又一遍地重复使用相同的代码,你应该认真考虑把它变成一个库。相关:你还需要留意新的工具,这些工具可以自动化或增强你的过程。正如 Serkan 指出的,最好的软件工程师花 80%的时间以这种方式优化流程——对于数据科学家来说,他认为这个数字应该更高。
  • 构建使您更高效的工具具有您可能没有想到的优势。具体来说,提高效率的一个效果是,测试和深入理解您的模型需要更少的工作,这反过来使您更有可能发现模型中的错误、过度拟合或偏差。
  • 机器学习逐渐成为软件工程工具带中的另一个工具。正如 devtools 在软件工程中至关重要一样,类似的工具在数据科学中将变得越来越重要。
  • 尽管数据科学和工程似乎正在融合,Serkan 认为我们将永远需要数据科学家。他强调,仅仅因为不同的数据科学任务随着时间的推移被抽象出来(想想:GridSearchCVBayesSearchCV用于超参数调优,或者更一般的 AutoML ),并不意味着理解模型背后的数学或数据库管理背后的工作原理没有价值。
  • 为您的模型运行健全性检查不是可选的。作为标准流程的一部分,除了使用所有标准模型评估策略(如 AUC 曲线、混淆矩阵等),您还应该始终使用精心选择的边缘案例测试您的模型。
  • 如果你没有上过像斯坦福这样的华而不实的学校,但你想进入像脸书这样的顶级科技公司,你的最佳策略是打造一些能吸引公司内部人们注意力的酷东西。项目是王道,但最好的项目不是 Kaggle 竞赛:它们是有明确用例的应用程序,是你的面试官可以想象自己使用的东西。
  • 要远离的一件事是:网上有很多肤浅的教学资源(例如,“在 5 分钟内学会如何构建 GAN!”).这些都是危险的,因为它们制造了理解的幻觉——当你不得不建立一些真实的东西时,这种幻觉很快就会瓦解。当你不明白某件事的时候,学会注意是一项至关重要的技能,可以帮助你避免这个陷阱。

TDS 播客—剪辑:

如果你在推特上,随时欢迎和我联系 @jeremiecharris !

从分形到吸引子

原文:https://towardsdatascience.com/from-fractals-to-attractors-b0e4ce9dcc71?source=collection_archive---------9-----------------------

我一直喜欢分形艺术,但在写一篇关于分形的文章时,我偶然发现了一种叫做吸引子的东西。由吸引子创造的艺术非常迷人。我可以花几天时间去探索。在这里,我将尝试一下巨大的可能性。

什么是吸引子?更正式的定义如下。在动力系统的数学领域中,吸引子是一组数值,系统趋向于朝着这些数值进化。

吸引子是状态的集合(相空间中的点),相邻状态在动态演化过程中向其靠*。吸引子被定义为不能自身分解成两个或更多吸引子的最小单位。这个限制是必要的,因为一个动力系统可能有多个吸引子。

事实上,我今天在这里的目的不是教你关于吸引子的知识,而是向你展示当它们变成艺术时是多么令人惊叹。独特的形状和独特的配色方案将画布变成美丽的东西。而且,这都是用数学完成的。对于那些觉得我的数学令人沮丧或“难看”的人来说,我理解这是可能的,但这是一个需要更深入探索的美丽主题。所以,继续美丽吧!

我将在这里包含创建以下艺术的代码。您可以使用这些代码并尝试创建您自己的艺术。

定义

Here a, b, c, and d are variables. There can be more but we’ll focus on four and show the results of those.

数字可以输入数据帧并立即使用,而不必逐个输入。这将一个接一个地呈现多个图形。有如此多的吸引子和如此多的美丽艺术可以简单地从数学方程、数字和代码中呈现出来。可能性是无限的。

The equation here is different than the Clifford attractor’s

下面是我用额外的 python 代码创建的另外两个吸引器。

Code for Clifford Attractors

Code Continued for Clifford Attractors

Here there are fifty five strange attractors but there are so many more that can be created. Below you will find the code for one specific Lazaro Alonso example. See if it intrigues you. Play with the code and try to create your own artwork.

From all this code, what do you get? It’s amazing!!

You can use this code to change the color, the background, the gradients, etc. See what you can do as you change the code to make your own creation.

虽然我很想在这里嵌入一个交互式吸引子生成器,但完成它比我预期的更具挑战性。外面有更多的世界。我无法阻止自己回到对计算机和数字组合能产生什么的敬畏中来!这是数学和数据科学中令人惊奇的一部分,应该进一步探索。

在利益相关者的支持下,从脆弱到敏捷

原文:https://towardsdatascience.com/from-fragile-to-agile-with-the-stakeholders-buy-in-6f973425c835?source=collection_archive---------21-----------------------

项目成功的最重要因素是在过程中获得利益相关者的支持

Photo by Michael Payne on Unsplash.

很难把一个敏捷型的钉子放进一个商业型的洞里!

TMI 警告:在 2015 年 8 月一个阳光明媚的早晨,在我的预产期,我在我的分娩球上蹦蹦跳跳,不耐烦地等待我的宝宝出现,但没有任何杂音!我必须让自己有事可做,所以我决定参加基于计算机的 ScrumMaster 认证考试——我参加迈克·科恩的培训已经有几个月了,但是我忽略了考试,现在看起来是个好时机,因为我的手在接下来的 12 个月里会很忙!

获得资格是容易的部分;我一点也不知道,即使我学会了所有的理论,实践是一个完全不同的野兽…四年下来,我成功地交付了几个具有挑战性的项目,我逐渐意识到,项目成功的最重要因素是获得利益相关者的认可,所以这就是我在本文中要讨论的。

这里的主要困境是,通过采用 SCRUM,你依赖于外部团体(即不仅仅是开发团队),如果他们没有履行他们的角色和职责,整个项目可能会崩溃。

所以,让我们看看什么会出错…

“我没有足够的时间在每次迭代中与团队合作”

产品负责人的参与是敏捷团队成败的关键。敏捷方法的协作性质,即产品所有者是团队的一部分,在时间管理方面会给他们增加很多压力。传统上,他们的输入是在项目的开始结束(签署软件符合规范)时被请求的,但是在敏捷项目中,他们被要求参加所有的仪式,保持待办事项列表整洁,区分优先级,并且每天与 Scrum 团队互动。

你需要向他们说明,他们有权做出与产品相关的决策,并利用他们的领域知识专注于功能,而不是管理本身。最重要的是,他们需要快速回答重要的问题,及时提供有价值的信息,并确保开发团队不受阻碍。你应该与产品负责人合作,支持他们需要的任何东西,并指导他们如何最好地为团队增加价值。

Courtesy: boost.co.nz

“我不需要每次冲刺复习都签到;给我发个报告就行了!”

利益相关者是忙碌的人。他们的日常工作要求很高,需要参加很多会议,做决策,管理多个项目。他们偶尔会对开发出来的软件不感兴趣,只要它能做到广告上说的那样。与产品负责人类似,他们习惯于参与项目的开始和结束,并不奇怪他们试图保护自己的时间,并取消任何他们似乎不必要的会议。

涉众不一定理解的是,Sprint 评审是为了团队的利益;不是让他们去发现团队在做什么,而是让团队去发现涉众真正想要什么。你需要让他们明白,在缺乏详细规格的情况下,这是检验产品并做出相应调整的机会。这是他们可以要求任何改变和增加的时候,所以如果他们不出现,他们就没有发言权

这些评论经常会陷入一些陷阱:

它们太长:在两个小时的评审中,有 20 分钟的时间是有价值的,所以他们的时间被浪费了,
它们太技术性了:低级别的实现细节正在被讨论,
没有什么可看的:涉众只想评审完整的工作流,而不是每个 sprint 开发的增量部分。

调整 Sprint 评审的结构以关注产品是吸引利益相关者参与的关键。这使得每个人都更容易调整他们对项目的目标和愿景,并继续交付一个有凝聚力的产品。

“但是我已经知道我想要什么了!”

通常情况下,人们认为他们已经知道他们想要什么,他们对软件应该做什么有一个清晰的想法,所以他们认为如果他们能写下来,让你继续做,会更有效率。你不能真的对利益相关者或产品负责人说:“我不相信在我给你看之前你知道你想要什么”——你需要在这个问题上更加外交化,并强调在项目过程中持续的投入是无价的。边缘案例在项目开始时并不明显,需要在发生时处理。此外,利益相关者想要的和他们需要的可能是不同的,并且很可能会带来实质上不同的成本

我喜欢用的一个比喻是“软件开发是蝴蝶效应的体现”:微小的变化可能会导致巨大的下游影响,所以除非利益相关者可以讨论和验证他们的需求,否则开发人员将不可避免地做出假设,这些假设在您获得的过程中变得越来越难以解开。

这部老掉牙但很好的轮胎摇摆卡通很好地总结了这一点:

Courtesy: businessballs.com

“我不能等待一个新特性的整个迭代”

敏捷宣言的第二个原则表明,即使在开发的后期,变化也是受欢迎的。利益相关者如何解释这一点:改变是要适应的 现在

固定迭代的想法是经过深思熟虑的,它试图控制需求的不断波动,并保护团队不要开始很多事情却没有完成。需要与产品所有者和其他利益相关者就最佳迭代长度达成一致:即,他们愿意等待新需求开始的可接受长度是多少,而开发团队需要足够长的周期来完成功能并满足他们的预期速度。

“这是一个监管项目,你能在截止日期前完成吗?”

是啊!!与流行的观点相反,敏捷方法确实可以在日期驱动的项目中发挥巨大作用。基于“铁三角”,有了固定的时间表,你必须变通其他两个目标中的一个,即要么增加更多的人员到项目中,要么缩小范围以实现这一目标。

Courtesy: Wikimedia

然而,你需要记住,如果更多的资源在项目的整个过程中保持不变,那么它们将是有益的——将更多的开发人员分配到一个已经运行较晚的项目中,将会使它运行得更晚(这在 Fred Brooks 的神话人月中有很好的记录)。关于范围,你确实依赖于产品所有者——他们必须优先考虑实现最小可行产品所需的特性。“从电影中学习”也是我推荐的一种方法:尽可能晚地对最终发布日期做出承诺。

要记住的一件重要事情是,在固定时间表的项目中,质量需要很高,这样错误和相关延迟的风险才能最小化。自动化测试和持续集成来拯救你,你应该把它们的附加值卖给管理层。此外,像 Atlassian Portfolio 或 ALM Works Structure 这样的工具可以可视化计划的组成部分(范围、人员和时间)来帮助你实时计划。

短迭代和使用工作软件作为主要的进度度量保证了当最后期限到来时,你保证交付一个具有正确特性的功能产品。即使你受困于不切实际的预算、进度和范围预期,你仍然应该以敏捷的方式运行项目,因为它提供了明确的证据,表明你将比在传统管理的项目中更早地失败,因此你有更多的选择…

计划就是一切,计划什么都不是——d·艾森豪威尔

准备好——准备好——Scrum!

以我的经验来看,从任何利益相关者那里获得认同的最好方法是让他们和你一起参加仪式,并参与日常的 Scrum 执行。有组织的演示和培训对于创造一种向敏捷过渡的最佳方式的感觉也是必不可少的。

另一方面,培养敏捷氛围并证明它不脆弱的需要,并没有给你全权去忽略那些不一定看到价值的涉众的反馈。相反,套用奈杰尔·尼科尔森在《哈佛商业评论》中的话:当有人反抗时,一个有效的领导者不会把他们视为需要解决的问题,而是需要理解的人!

感谢阅读!

我定期撰写关于领导力、技术和数据的文章——如果你想阅读我未来的帖子,请 在 Medium 上关注我

数据货币化的经验教训

原文:https://towardsdatascience.com/from-jumptap-to-verizon-lessons-on-data-monetization-7e061204dc72?source=collection_archive---------6-----------------------

谈论你的组织的隐藏价值的框架

Graph is illustrative of the journey not actual scale

2011 年 4 月。“Jumptap 是定向移动广告的领导者” Adam Towvim 指着他的 iPhone 4 告诉我。当他递给我的时候,那块闪亮的砖看起来像是被冰覆盖着。“用你的手指在屏幕上摩擦,”他示意道。霜神奇地消失了,露出了邓肯甜甜圈冰咖啡促销。

亚当给我看的广告很吸引人,但它不是由数据支持的。我们会面几周后,我加入了 Jumptap,领导团队最终将数据整合到公司的所有技术中。7 年后的今天,我回头看我们构建的客户喜爱的数据产品。这些产品让从广告商那里赚了数十亿美元,并推动了数十亿美元的收购。我思考着我们一路走来学到的教训。

当我们能够传达数据资产的价值和目的时,我们就取得了最大的成功。为了做到这一点,我们投入时间开发了一种通用的数据语言和工具来进行交流,我们与客户进行了深入的交流,并了解我们的数据如何解决他们的问题,当我们谈论数据时,我们要求数据和我们自己都保持完整性。在本文中,我描述了使成功成为可能的框架,以及可以使您的数据对话更有价值的工具。

学习语言

在一个充斥着数据点的世界里,令人痛苦的是缺乏关于数据的清晰交流。管理数据产品 20 年的经验告诉我,光是数据这个词就很危险。你需要上下文和定义来描述任何有价值的东西。无论是构建数据产品还是设定数据驱动的目标,管理者都必须花时间去学习、教授和使用一个比数据更好的词。

例如,如果你的公司存在于广告技术生态系统中,并希望将消费者行为数据货币化,你必须开始使用这些词的某些版本:

  • 标识符:与目标设备、用户、消费者或家庭相关联的字符串。
  • 信号:可以与标识符相关联的唯一观察值。一组信号通常被称为特征。
  • :所有共享共同信号或特征的 id 的集合。

为什么?这些词实际上对行业有一定的意义,并使团队能够围绕参与所需的技术和法律框架进行联合。Adtech,edtech,fintech,等。每个都有自己的基本数据字典。如果你不会说这种语言,你可能会有错误的对话。

在我的职业生涯中,我一直在接*尾声时加入注定要失败的数据货币化对话。一家数据提供商拥有一套令人满意的受众智能,但该团队尚未弄清楚如何将细分集成到应用程序中。几个月的业务发展审查质量和规模浪费了,因为没有办法连接这些点。差距可能是技术上的、法律上的、财务上的或者以上所有的。只需一次分歧就能扼杀一笔交易。

几乎有数百万博客提供如何更好地进行对话的建议,但我的经验证明,围绕复杂数据建立联系的唯一方式是建立一个简单的呼叫流程图,上面标有定义的数据元素(见下文)。你不需要成为一名工程师来组装这些。目标是开始一个实用的对话,而不是记录架构。

Call Flow for Weather Specific Ad Creative

当我们被要求设计一个根据当前天气动态更新的广告时,我们的团队需要集成一个天气数据服务。IP 地址是解析我们传递给气象服务的邮政编码所需的信号。他们回复了一个,一个两位数的天气代码。创意团队将这些代码存储在天气广告中,并使用它们来动态更新广告创意,以反映当前的天气。这很简单,也很有效。

随着数据点之间跳跃次数的增加,这些图表的价值也会增加。大多数数据应用程序,如将移动运营商细分市场带给广告商,需要一个用户标识符,并且不像这个天气示例那样简单。如果这些点只是在罕见的情况下连接起来,那么一笔 10 亿美元的交易是不会有回报的。尽早将产品和工程引入对话至关重要。这里成功的关键是使用普遍接受的数据语言。你的行业已经有了一个——学习它。

如果你认为你发明了一种新的数据类型或数据的独特用途,花时间与你的团队和合作伙伴一起明确定义它是什么,不是什么。创建一个命名约定,坚持它,并推广它。与普遍的看法相反,利用数据赚钱并不容易。只有当一个组织花时间定义其数据资产,并学会如何在内部以及最终与客户讨论它们时,价值提取才是可能的。

知道问题

数据对话往往以关于数据数量的争论开始和结束。不要让规模立即打消你追求数据驱动产品的念头。市场将永远重视规模,但客户将帮助确定规模和精度之间的正确*衡。重要的是找到一个值得解决的问题。我们在 Jumptap 经历了这一点,并在此过程中学到了关于数据货币化的重要经验;了解问题,了解你的客户,然后确定合适的规模。

2011 年,针对移动设备的广告商没有消费者购买数据。为了触及受众群体,广告商必须信任出版商的上下文元数据,并抱最大希望。Jumptap 领导团队认识到了这一市场需求,我们开始设计一种将消费者行为数据引入移动广告的方法。

我们的第一次迭代专注于快速扩展。我们从 DataLogix (现归甲骨文所有)获得了消费者购买数据的许可。他们向我们证明,对于某些产品类型,某些邮政编码显示出高于*均水*的购买行为。我们已经可以针对预定义的邮政编码组,因此我们根据 DataLogix 购买数据创建了专门的位置目标,并开始向广告商出售这些基于位置的受众。初步成功后,客户开始质疑产品的精确度。他们期望购买行为和设备之间有一对一的匹配。我们的解决方案没有提供这一点,但我们已经向一组客户证明,我们正在向市场仍未提供的解决方案冲刺。

我们的第二次迭代重视精度胜过规模。数据提供商可以向我们发送任何有电子邮件地址的用户的受众分群。我们联系了我们的出版商合作伙伴,请他们收集他们用户的电子邮件,并在地址上添加模糊哈希后发送给我们。我们向出版商支付了数百万封链接到有效移动设备 id 的散列电子邮件,并继续从我们的数据合作伙伴那里下载数据。更精确的产品是相当成功的,但是这一次我们遇到了无法克服的困难。我们无法从合作伙伴那里获得足够的电子邮件地址。

The Complex Map of Consumer Purchase Data

我们回到客户那里,找到了*衡规模和精度的折中方案。我们想出了如何准确地将移动设备与具体家庭联系起来。然后,有针对性的广告被发送到我们能接触到的所有与家庭相关的设备上。这个伸缩性很好。我们的客户认识到,当整个家庭都收到类似的信息时,影响购买行为是非常有效的。

我们立即投入了广告预算,这些预算受到当时移动广告缺乏针对性的限制。然后,我们采用相同的技术堆栈,用它来驱动市场上最早的一些跨设备瞄准和测量解决方案。我们能够大规模交付产品,同时保持市场认可的精确度水*,这是 Jumptap 最终以超过 2 亿美元的价格出售给 Millennial Media 的关键因素。我们知道我们要解决的问题,我们倾听客户的意见,我们在规模和精度之间进行权衡。

进行对话

每个组织都将创建数据视为自然的业务过程。在某种程度上,他们得出结论,数据可能有一定的货币价值。多年来,我开发了一个框架来帮助推动围绕数据货币化的对话,以帮助团队确定是否值得追求以及如何让团队支持决策。

第一步在本文的开头部分已经介绍过了。组织必须定义正在考虑的数据集,确认组织拥有使用数据的合法权利,并估计当前规模。以我的经验来看,10 家公司中有 9 家在执行盈利计划之前必须回头重写一些数据使用或隐私语言。这需要时间,而且可能会引起争议。先这样做,或者以后付出代价。

下一步是通过评估数据提炼和外部化的潜力来探索货币化机会。想一想您的数据或您对数据的处理是如何与众不同的。下面的矩阵是推动对话的好工具。

所有数据都从左下方开始—原始的、内部的,不创造任何价值。矩阵迫使团队思考数据集如何移动到不同的盒子中。提炼时向上,分享或出售时向右。

  • 我们对数据类型有唯一的访问权吗?
  • 数据类似于原材料还是成品?
  • 我们可以向其他公司提供我们的数据吗?
  • 我们想投资改进我们的数据吗?
  • 我们的数据已经有市场了吗?
  • 我们对数据的处理有什么不同吗?

回答这些最初的问题,并将数据资产放入当前和期望的盒子中,有助于团队支持更广泛的数据战略。为了更好地说明这些选项,我根据公司当前的货币化对话状态,将公司名称放入下面的主要方框中。一个公司可以有多个盒子里的产品。

亚马逊进行了对话,并得出结论,他们的战略是围绕他们的数据资产创建一个堡垒,同时通过数据优化和内部数据服务进行创新。他们在数据民主化服务上投入了大量资金,以增强员工的能力。他们利用客户情报来发展业务,并取得了巨大的成功。他们现在是数据驱动型企业的典范。

寻求成为下一个亚马逊并不是一个糟糕的决定。然而,如果领导层决定关注内部,他们需要定期沟通并捍卫这一决定。具有创新精神和创业精神的员工会发现值得考虑的商业机会。不要害怕进行对话。如今,提供数据即服务(DaaS) 是一个巨大的机遇。在获取、交付或提炼数据方面具有竞争优势的公司,如 Datalogix (被甲骨文收购),以及气象公司(被 IBM 收购),有可能达到十亿美元的估值。

沿着这条路走下去是一个需要大量投资的重大战略决策。如果这是货币化对话的结果,那么下一步就需要达成一致并制定详细的计划。试着呆在一个盒子里,非常强调差异化。矩阵中的另一家 DaaS 公司 PlaceIQ 是位置数据生态系统的早期远见者之一,但他们在建立规模和差异化方面面临挑战。多年来,他们已经开发了几乎每一个盒子中的产品,然后通过其当前的*台为客户提供高度精确的位置洞察,取得了成功。

最后一栏,数据卖家,由于脸书(不是卖家)和其他行为者在消费者数据实践和政策上不够透明,这些天正在应对负面新闻。尽管如此,出售数据是一项可以正当进行的合法业务。早在互联网出现之前,原始数据供应商就开始出售精细数据集,如家庭人口统计数据、购买历史记录或其他用于各种目的的高价值列表。这些数据的老爷爷们还在卖收缩包装的软件。这不是数据业务的发展方向,但对于一些数据集来说,这仍然是一个值得考虑的有效商业模式。

一批新的数据卖家已经发现,各种原始和精炼数据类型都有数字市场。在美国,除了金融和医疗垂直行业,数据交换通常不受监管。这在未来可能会发生变化,但今天像甲骨文公司、T2 公司、洛塔梅公司和 T4 公司这样的公司提供了通用的方法来将定义的数据资产货币化。小众买家,如位置情报提供商 Cuebiq 、un cast和 Safegraph 从多个移动应用发行商购买并汇总原始位置信号,这些发行商提供服务以换取出售精确位置信号的权利。正如 matrix 所建议的那样,将这样的原始数据出售给数据生态系统是价值链上的一个低端。然而,如果您的公司正在考虑转向 DaaS 业务或成为数据顾问,从这里开始是测试数据价值的完美有效的方法。

我看到绝大多数专家反对出售数据,但我认为公司需要采取务实的态度。进行货币化对话。如果您的公司对数据资产拥有完全的权利,有限的风险暴露,并且没有建立数据业务的短期意图,那么应该考虑加入数据生态系统。使用多样化的收入流以其他方式建立企业价值,或者随着时间的推移向数据价值链的上游移动。

货币化对话既不是一劳永逸的练习,也不是你想永远做下去的跑步机。每个公司都需要找到正确的节奏。如果你的公司走上亚马逊的道路,你应该定期重新评估这个决定,但不是每个月。如果有机会出现,测试市场。如今,数据的保存期限如此之短,以至于一个测试项目可以在有限的暴露情况下提供大量的知识。最重要的是,在团队评估货币化机会时,花时间记录机会、厌恶和结果。记录对话有助于避免重复讨论同一个问题。它还可以帮助创新型员工发现领导层尚未考虑到的机会。

要求诚信

大规模利用数据赚钱并不容易。对于每一个估值达到 10 亿美元的 Datalogix,就有 100 家像 T2 rocket fuel 这样的公司找到了数据的独特应用,但却犯了严重的错误。要想取得成功,你需要一个非常正直、有能力沟通复杂事物的团队。我选择这两个特征是因为以今天的技术,假设你可以用数据做任何事情。这一事实很容易夸大能力,低估复杂性。团队需要清楚地传达价值,然后交付。结果(用数据表示)最终会揭开真相。不要冒险假装。

挑战在于,激烈的竞争将不断推动团队利用他们的数据做越来越多的事情。投资于安全、隐私和政策培训系统非常重要。所有这些都不能弥补在数据使用方面表现出完整性的领导力。像欧洲 GDPR 这样的法规是技术自大和多年不透明数据收集的结果。如果我们让这减缓我们的进步,那将是一场悲剧。解决办法很简单。团队需要接受数据透明、同意和控制的新规范。这是一种公*的*衡。随着公司从使用数据中获利,他们也需要为消费者提供对数据更大的访问和控制。如果一个组织希望保持数据驱动优势,管理层必须让这种新模式成为公司文化的一部分。

创新数据使用的例子在我们身边比比皆是。从把你带到这个页面的谷歌搜索,到因为当地政府众包坑洞位置而在你的汽车中*稳行驶,数据被用来让我们的生活变得更好。机会是无穷的,但是很容易被与构建这些产品相关的风险和复杂性所淹没。当工作感觉巨大或数据资产不可获得时,很容易发现异议。我的经验向我证明,企业数据蕴含着巨大的价值。关键是使用简单的语言将大问题分解成微小的数据点,进行货币化对话以使团队保持一致,然后在团队交付时以残酷的诚实进行沟通。遵循这一框架并确定您的公司在哪里有数据机会可能是增长和停滞的区别。这是最后一课。

从数学到数据科学

原文:https://towardsdatascience.com/from-math-m-s-to-data-science-c3ab59dbceb3?source=collection_archive---------10-----------------------

我拥有纯数学硕士学位(想想定理证明,而不是数字运算),最*决定开始过渡到数据科学,特别是机器学习/人工智能。我的背景教会了我严谨而精确地思考,但还没有让我做好除了教书以外的任何事情的准备,无论是在学院、大学还是高中当助教。我的目标是研究,而不是教学,尽管我心目中的博士和终身教职肯定会涉及一些教学。事实证明,我可能真的擅长教学,有几年我认为我可以做得很好,但尽管没有博士学位意味着我暂时被数学研究拒之门外,但研究新问题和新想法的冲动从未离开过我。

我最喜欢的两门数学课程是图论和数理逻辑,当我还打算攻读博士学位时,我向数理逻辑教授征求关于专攻该领域的建议。她告诉我,现在这已经过时了,专攻数理逻辑无异于自杀,但数理逻辑的现代应用是人工智能。图论在数据结构和算法方面也很突出,事实上我最喜欢的所有主题都在机器学习中发挥了作用。

Photo by Franki Chamaki on Unsplash

当时我并不相信,但在决定继续当五到六年的学生对我现在的职业轨迹来说并不是一个正确的决定后,我最终接受了她的建议。在sharpen Minds的联合创始人爱德华·哈里斯(Edouard Harris)的指导下,我开始学习 Python(从何塞·波尔蒂利亚的完整的 Python Bootcamp 开始,然后用杰克·范德普拉斯的Python 旋风之旅填补了我基础中的一些空白)。我决不会声称此时已经掌握了 Python,但是我已经掌握了足够的基础知识来进行下一步。

然后,对我来说,听从哈里斯和许多其他人的建议,不要遵循我在研究生院根深蒂固的学习模式,这是一个巨大的信念飞跃:在将所有组件组合在一起之前,彻底学习每个组件。相反,我采用自上而下的方法:通过使用工具来学习,而不是在使用之前。对我来说,这是一个巨大的思维转变,我不知道我需要多长时间来适应它。

Photo by Fabian Grohs on Unsplash

因此,我没有通过高级 Python 课程在 Python 方面继续前进,而是刚刚在 Coursera 上完成了吴恩达的深度学习专业,并且正在开始 fast.ai 的程序员实用深度学习(两者都使用 Python)。fast.ai 由雷切尔·托马斯和杰瑞米·霍华德共同创立,体现了自上而下的学习方法,并表现出令人印象深刻的能力,通过以做为中心而不是理论化来教授学生高度适用的技能。我也一直在使用模式分析 SQL 教程学习 SQL,在何塞·波尔蒂利亚的Python for Data Science boot camp中玩更多的 Python 库,并在 Khan Academy 中复习我的统计数据。本着边做边学的理念,我希望在一年内为数据科学的入门级职位做好准备,可能会在求职期间申请成为最敏锐思维的学员。

来自学术界的我,仍然在内心挣扎,觉得自学是“值得的”,尤其是在申请工作的时候,尤其是因为寻求数据科学家的工作描述往往会让新人有些气馁。但也许数据科学中思想和技术的内在快速迭代需要该领域的每个人都擅长自学,而我强大的数学背景——毕竟我拥有“定量领域的研究生学位”——加上自学新概念和新技能的技能,将对潜在雇主具有吸引力。

(2022 年 11 月更新)

在成为数据科学家的路上发生了一件有趣的事情:我成了一名技术作家!但是我经常从这篇文章的读者那里得到一些信息,通常是这两个问题中的一个:

我(读者)应该成为数据科学家吗?

恐怕我真的无法为任何不是我的人回答这个问题,但我可以说:职业会改变,因为人类会改变。如果你对这篇文章感兴趣,你已经知道了!所以,请继续前进,精通 Python,并开始学习在技术领域非常普遍的技能,例如:

  • Git
    -如何在命令行中工作
    -如何使用像 Vim 或 Nano 这样的文本编辑器的绝对基础,即使你大多数时间更喜欢在 IDE 中工作
    -一些 SQL(数据库到处都是*)

当你学习这些通用技能时,找到属于几个不同技术领域的人的社交媒体账户,即使你只是阅读。你会开始对不同的行业如何运作有一点感觉,如果你跟随那些人,你会对前景有一个更大的了解。

我(读者)怎样才能成为一名数据科学家?

我很难回答这个问题,因为我最终没有选择数据科学,但在我突然改变方向之前,我一直在积极寻找工作,经历了几次多轮面试,并在此过程中获得了宝贵的建议。以下是我的建议:公司仅仅根据学位雇佣数学毕业生的日子已经一去不复返了。无论你拥有什么样的学位,公司都希望你拥有:

-至少有一个数据科学项目的投资组合(不是来自课程或教程)
-能够编写生产级 Python
-精通 Scikit-Learn、NumPy 和 Pandas 等 Python DS 库
-精通 SQL(不仅仅是语法,而是真实世界的使用)
-精通 Git(也不仅仅是语法,而是真实世界的使用)

我列出了一个我最喜欢的学习这些技能的资源的清单。我希望这有所帮助!感谢阅读。😊

可以找到我的地方:

  • Twitter
  • 乳齿象
    -Polywork
    -GitHub
    -Twitch
    -lauralangdon . io

从熊猫到有考拉的派斯帕克

原文:https://towardsdatascience.com/from-pandas-to-pyspark-with-koalas-e40f293be7c8?source=collection_archive---------7-----------------------

Photo by Ozgu Ozden on Unsplash

对于那些熟悉熊猫数据帧的人来说,切换到 PySpark 可能会相当混乱。API 是不一样的,当切换到分布式特性时,由于该特性所施加的限制,有些事情的处理方式会非常不同。

我最*在一个非常有趣的关于 Apache Spark 3.0、Delta Lake 和考拉的 Databricks 演示中偶然发现了考拉,我想探索一下会很不错。

考拉项目通过在 Apache Spark 上实现 pandas DataFrame API,使数据科学家在与大数据交互时更有效率。

pandas 是 Python 中事实上的标准(单节点)DataFrame 实现,而 Spark 是大数据处理的事实上的标准。使用此软件包,您可以:

-如果您已经熟悉熊猫,使用 Spark 可以立即提高工作效率,无需学习曲线。

-拥有一个既适用于 pandas(测试,较小的数据集)又适用于 Spark(分布式数据集)的单一代码库。

来源:https://koalas.readthedocs.io/en/latest/index.html

如何入门

考拉支持≥ Python 3.5 ,从我从文档中看到的来看, PySpark 2.4.x. 依赖项包括 pandas ≥ 0.23.0,pyarrow ≥ 0.10 用于使用柱状内存格式以获得更好的矢量操作性能,matplotlib ≥ 3.0.0 用于绘图。

装置

下面列出了安装考拉的不同方法:

[## 安装-考拉 0.20.0 文档

正式 Python 3.5 及以上。首先你需要安装 Conda。此后,我们应该创造一个新的环境

考拉. readthedocs.io](https://koalas.readthedocs.io/en/latest/getting_started/install.html)

但是让我们从简单的开始:

pip install koalaspip install pyspark

请记住上面提到的依赖性。

使用

给定以下数据:

**import** pandas **as** pd
**from** databricks **import** koalas **as** ks
**from** pyspark.sql **import** SparkSession

data = {**'a'**: [1, 2, 3, 4, 5, 6],
        **'b'**: [100, 200, 300, 400, 500, 600],
        **'c'**: [**"one"**, **"two"**, **"three"**, **"four"**, **"five"**, **"six"**]}

index = [10, 20, 30, 40, 50, 60]

你可以从熊猫的数据框架开始:

pdf = pd.DataFrame(data, index=index)*# from a pandas dataframe* kdf = ks.from_pandas(pdf)

来自考拉的数据框架:

*# start from raw data* kdf = ks.DataFrame(data, index=index)

或来自火花数据帧(单向):

# creating a spark dataframe from a pandas dataframe
sdf2 = spark_session.createDataFrame(pdf)# and then converting the spark dataframe to a koalas dataframe
kdf = sdf.to_koalas('index')

一个完整的简单输出示例:

A simple comparison of pandas, Koalas, pyspark Dataframe API

熊猫和考拉的 API 差不多。官方文档中的更多示例:

[## 10 分钟到考拉-考拉 0.20.0 文档

这是对考拉的简短介绍,主要面向新用户。本笔记本向您展示了一些关键的不同之处…

考拉. readthedocs.io](https://koalas.readthedocs.io/en/latest/getting_started/10min.html)

谨记在心

关于考拉项目的一些说明:

  • 如果你是从零开始,没有任何关于熊猫的知识,那么直接进入 PySpark 可能是一个更好的学习方法。
  • 一些功能可能丢失 —丢失的功能在这里记录
  • 一些行为可能不同(例如,Null 与 NaN,NaN 用于考拉,更适合熊猫,Null 用于 Spark)
  • 请记住,由于它是在幕后使用 Spark,s ome 操作是懒惰的,这意味着在有 Spark 动作之前,它们不会真正被评估和执行,比如打印出前 20 行。
  • 我确实对一些操作的效率有些担心,例如*.to_koalas()* 给出了一个*No Partition Defined for Window operation! Moving all data to a single partition, this can cause serious performance degradation.* 警告,这似乎是因为索引操作和可能会有相当大的问题,这取决于您拥有的数据量。请注意,当您在.to_koalas('index')中指定索引列名称时,警告并不存在,这是合理的,因为 spark/koalas 知道使用哪一列作为索引,并且不需要将所有数据放入一个分区来计算全局排名/索引。更多细节请看这里:https://towards data science . com/adding-sequential-ids-to-a-spark-data frame-fa 0 df 5566 ff 6

结论

免责声明:我真的没有怎么使用它,因为当我开始学习 spark 时,这还不可用,但我真的认为了解可用的工具是很好的,并且它可能对那些来自熊猫环境的人有所帮助——我仍然记得我从熊猫数据帧切换到 Spark 数据帧时的困惑。

我希望这是有帮助的,并且知道考拉将会节省你一些时间和麻烦。任何想法,问题,更正和建议都非常欢迎:)

如果您想了解更多关于 Spark 的工作原理,请访问:

[## 用非技术性的方式解释技术性的东西——Apache Spark

什么是 Spark 和 PySpark,我可以用它做什么?

towardsdatascience.com](/explaining-technical-stuff-in-a-non-techincal-way-apache-spark-274d6c9f70e9)

关于在 Spark 中添加索引:

[## 向 Spark 数据帧添加顺序 id

怎么做,这是个好主意吗?

towardsdatascience.com](/adding-sequential-ids-to-a-spark-dataframe-fa0df5566ff6)

一年从糕点师傅到数据分析师。

原文:https://towardsdatascience.com/from-pastry-chef-to-data-analyst-in-one-year-6545a8b65b5a?source=collection_archive---------38-----------------------

进入数据科学的秘诀是什么?

https://mycupcakeaddiction.com/en/recipes/laptop-computer-cupcakes

每天,像我这样有抱负的数据科学家都被关于数据科学如何酷以及它将如何在不久的将来改变一切的励志文章轰炸。这似乎是一个非常令人兴奋的学习和工作领域,如果你至少有一个 STEM 学位的话。

当你像我一样有不同的背景时,搜索那些转行从事数据工作的人并没有什么帮助。在很多情况下,你会发现那些从物理、天文或机械工程进入数据科学的人发生“大”变化的故事,这很酷,但厨师、银行出纳员和学校教师呢?这种感觉就像是一个陷阱,如果你以前从未接触过代码、统计或繁重的数学,就不可能真正处理数据。是的,从零开始学习任何东西都要困难得多,但是我在这里想告诉大家,尽管如此,这是可能的!

我学过烹饪学,它是烹饪艺术和酒店管理的混合体。大学毕业后,我做过糕点师和美食教师,后来,我还为一家银行工作。很多年来,我对 python、loops、z-scores 或者你可以用熊猫做的所有魔术一无所知。但是,我一直对 AI 和机器学习非常好奇,即使那时候那些概念对我来说更接*科幻。

在我休假一年后,当我意识到我想在生活中做一些新的事情时,一切都变了。然后,我开始研究什么是酷的,灵活的,有活力的,能让你在世界上任何地方工作。答案是技术,在所有的可能性中,数据科学是最酷的选择之一,所以我决定在 Dataquest 开设一门在线课程,看看我是否喜欢它,最初,我专注于学习 python 的基础知识。我也开始听播客,比如 Dataframed ,阅读大量文章,大部分是从到数据科学和 KD 掘金的文章,让自己熟悉那个世界的人物。

几个月后,我真的很喜欢我所学的东西,当时我搬到了爱尔兰的都柏林,在那里我找到了一个数据分析的高级文凭,这基本上是一个为期一年的密集课程,最终给你一个相当于学士学位的文凭。我当时全职工作,没有多少钱,但我决定给它一个机会,最终,一年的时间并不多。

记得我说过这是强化课程吗?这几乎占用了我一整年的所有空闲时间,有如此多的作业和考试,以至于我多次感到不知所措。但是,随着我在学习中的进步,我更高兴的是发现了这么多神奇的东西,如 Tableau、Kaggle 竞赛、学习如何清理数据(好吧,不是很酷,但真的很有必要)、t-test、ANOVA,还有很多。我非常确定我的方向是正确的,但是如何获得我的第一份工作机会呢?

我已经发出了 200 多份申请,已经修改了至少十几次简历,仍然一无所获。我照着菜谱做,创建了一个 github 文件夹和一个博客,同时我也试图在数据分析师需要的工具方面获得更多的实践知识。秘密是什么?很简单,耐心。

从零开始是很难的,坚韧不拔是我获得第一次面试的关键,也是我从第一次失败中吸取教训的关键。你需要了解人们期望你知道什么,以及你将如何展示这些。举个例子,我开始在我的面试中使用我的一个大学项目,一个交互式仪表盘(你可以点击这里)。谈论一些你深有体会的事情总是会在任何工作面试中给你加分,即使这个项目本身并不完美或不确定。

最后,我收到第一份工作邀请的面试来自当地的一次数据科学会议,我怎么强调都不为过的重要性是,尽可能参加所有可能的活动,与人交往,展示你的面孔,不要指望事情会轻易发生,做一个斗士!

总之,从我第一次在谷歌上输入“数据科学”到我签下第一份数据分析师的合同,整整花了我一年的时间,外加相当于一辆二手车的钱,但更重要的是,这需要我每天尽可能多地学习

。目前,我已经完成了我的课程,我现在有兴趣深入研究 NLP 和分类技术,可能明年开始攻读硕士学位。我刚刚开始烤我的数据科学蛋糕,但我可以告诉你,这将是一个美味的蛋糕!

从预训练的单词嵌入到预训练的语言模型——关注 BERT

原文:https://towardsdatascience.com/from-pre-trained-word-embeddings-to-pre-trained-language-models-focus-on-bert-343815627598?source=collection_archive---------1-----------------------

静态单词嵌入动态(语境化)单词嵌入

“在每个 NLP 实践者的工具箱中, 预训练语言模型 *所取代,这似乎只是时间问题”Sebastian Ruder*

adsieg.github.io

静态单词嵌入

  • Skip-Gram & CBOW(又名 Word2Vec
  • 手套
  • 快速文本
  • 外来 : Lda2Vec,Node2Vec,字符嵌入,CNN 嵌入,…
  • 庞加莱嵌入学习分层表示

上下文化(动态)单词嵌入(LM)

  • CoVe ( 语境化嵌词 s)
  • 无级变速器 ( 交叉训练)
  • ELMO ( 来自语言模型的嵌入)
  • ULMFiT ( 通用语言模型微调)
  • 伯特 ( 来自变压器的双向编码器表示)
  • GPT&GPT-2*(创成式预训)*
  • 变压器 XL (意为超长)
  • XLNet ( 广义自回归预训练)
  • 恩里耶 (通过知识整合增强表现)
  • (flai Embeddings(用于序列标记的上下文字符串嵌入))

还有很多其他的…

adsieg.github.io

什么是好的模式?

最佳模型将能够捕获 4 个组件:

  • 词汇方法(关于一种语言的单词或词汇)**
  • 句法方法(在一种语言中创造结构良好的句子的词语和短语的排列- >语法)**
  • 语义方法(关于语言中的意义——>引申意义,理解歧义)**
  • 语用方法(词语与文档的接*度)**

模特的主要家族有哪些?

https://nlp.stanford.edu//~johnhew//structural-probe.html?utm_source=quora&utm_medium=referral#the-structural-probe

语言建模是在单词序列上分配概率分布的任务,该概率分布与语言的分布相匹配。虽然听起来令人生畏,(即埃尔莫、伯特、GPT) 的语言建模本质上只是在一片空白中预测单词。更正式地说,给定一个上下文,语言模型预测一个单词在该上下文中出现的概率。**

这种方法为什么有效?因为这种方法迫使模型学习如何使用整句话中的信息来推断遗漏了什么单词。

0.静态与动态

  • 静态单词嵌入未能捕获多义词。它们为不同上下文中的同一个单词生成同一个嵌入。###语境化单词嵌入旨在捕获不同语境中的单词语义,以解决多义问题和单词依赖于语境的性质**
  • 静态单词嵌入只能利用来自下游任务的无监督模型的向量输出——而不是无监督模型本身。它们开始时大多是浅模型,并且在训练后经常被丢弃(例如 word2vec、Glove)# # #上下文化(动态)单词嵌入训练的输出是被训练的模型和向量——而不仅仅是向量。**
  • 传统的单词向量是浅层表示(单层权重,称为嵌入)。他们只是在模型的第一层融入了之前的知识。对于新的目标任务,网络的其余部分仍然需要从头开始训练。他们未能捕捉到可能更有用的高层信息。单词嵌入只在捕捉单词的语义时有用,但我们还需要理解更高层次的概念,如回指长期依赖、一致、否定等等。**

演变:

http://ruder.io/10-exciting-ideas-of-2018-in-nlp/

迁移学习——一种不是从头开始训练模型的技术,我们使用在大型数据集上预先训练的模型,然后针对特定的自然语言任务对它们进行微调。******

**一些特殊性:

  • ULMFiT →通过微调进行传送****
  • ELMo →通过特征提取转移****
  • 伯特 →转移注意力提取****

为什么使用迁移学习?

在 vision 中,它已经实践了一段时间,人们使用经过训练的模型从庞大的 ImageNet 数据集学习特征,然后针对不同的任务在较小的数据上进一步训练它。

  • 用于文本分类(或任何其他受监督的 NLP 任务)的大多数数据集都相当。这使得训练深度神经网络非常困难,因为它们会倾向于过度适应这些小的训练数据并且在实践中不能很好地概括

在计算机视觉领域,几年来,趋势是在巨大的 ImageNet 语料库上预先训练任何模型。这比随机初始化好得多,因为该模型学习一般的图像特征,并且该学习可以用于任何视觉任务(比如字幕或检测)。

在 NLP 中,我们在上训练一个通用语言建模(LM)任务,然后在文本分类(或其他任务)上微调。原则上,这将执行得很好,因为模型将能够使用从生成性预训练中获得的语言语义知识

  • 它能够捕捉语言中的长期依赖
  • 它有效地合并了层级关系
  • 它可以帮助模型学习情绪
  • 对于 LM 来说,大数据语料库很容易获得

伯特

https://mostafadehghani.com/2019/05/05/universal-transformers/

改进?

  1. GPTvs埃尔莫vs伯特- > 所有预训练模型架构的区别。伯特使用双向转换器GPT 使用从左到右转换器埃尔莫使用独立训练的从左到右和从右到左 LSTM 的串联来为下游任务生成特征。在所有层中,BERT 表示是由左右上下文共同决定的。换句话说,它是深度双向的,与 ELMo ( 浅层双向)和 OpenAI GPT ( 一个方向,从左到右)相反。****
  2. 变形金刚证明了递归卷积对于构建高性能的自然语言模型并不重要
  3. 他们使用一种自我注意操作来实现最先进的机器翻译结果
  4. 由于其并行性运行时的特性,注意力是一个高效操作
  5. 传统的语言模型采用前 n 个标记并预测下一个标记。相比之下,BERT 训练了一个语言模型,在预测时将上一个和下一个标记都考虑在内——实际上是双向的
  6. 如果你简单地要求一个深度神经网络通过阅读所有维基百科来学习典型的英语句子是什么样子,那么它对英语语言学习了什么? 当计算机已经将句子中的每个单词表示为实值向量,而没有解析树的显式表示时,BERT 对类似人类的解析树进行编码,并在这些向量空间中找到树结构 。BERT 能够从 Penn 树库中重建解析树。

https://nlp.stanford.edu//~johnhew//structural-probe.html?utm_source=quora&utm_medium=referral#the-structural-probe

  • 针对特定 NLP 任务 (如 POS、NER 等)对每层的重要性进行评分。)表示在网络中基本句法信息被更早的 (较低层)捕获,随后是较高层的语义信息。这反映在右图中。(这个观察结果也类似于在 ELMo 模型中看到的情况)**
  • 此外,与句法任务相关的信息似乎更多地局限于几个层,其中用于语义任务 ( SPR and Relations)的信息通常遍布整个网络
  • 检查输出单词向量显示,不仅单词的不同含义以不同的表示形式被捕获,它们还以细粒度的方式在空间上被分离。

https://arxiv.org/pdf/1906.02715.pdf

7.每个单词必须经过的距离:在一个简单的 RNN 中,单词“Echt”必须经过多个步骤。最后的红色层必须存储编码信息。在超过 50 个单词的大句子中,每个单词需要移动的距离线性增加。由于我们不断地改写那些编码信息,我们肯定会漏掉句子中出现较早的重要单词。在编码之后,它还必须经过传播才能到达解码的目的地。

有了注意力机制,我们不再试图将完整的源句子编码成固定长度的向量。相反,我们允许解码器在输出生成的每一步“关注”源句子的不同部分。

注意机制的显著成就是提高了对模型的空间理解。

工作?

1.→从单词到向量

  • 记号化就是把它劈成碎片的任务,叫做记号,或许同时扔掉某些字符,比如标点符号。**
  • 使用词块(如 playing - > play + ##ing)代替单词。这可以有效地减少词汇表的大小,并增加每个单词的可用数据量。
  • 数字化旨在将每个标记映射到语料库词汇中的唯一整数。
  • 令牌嵌入的任务是为序列中的每个单词获得嵌入(即一个实数向量)。该序列的每个单词被映射到模型将在训练期间学习的 emb_dim 维向量。你可以把它看作是对每个令牌的向量查找。这些向量的元素被视为模型参数,并像任何其他权重一样通过反向传播进行优化。
  • 填充用于使批次中的输入序列具有相同的长度。也就是说,我们通过添加' <填充符> ' 记号来增加一些序列的长度。**
  • 位置编码:

回想一下位置编码的设计是为了帮助模型学习序列的一些概念和记号的相对位置。这对于基于语言的任务至关重要,尤其是在这里,因为我们没有使用任何传统的循环单元,例如 RNNGRULSTM

直观地说,我们的目标是能够根据特定单词的位置来修改该单词所代表的意思。我们不想改变单词的完整表示,但是我们想通过使用预定的(非学习的)正弦函数向令牌嵌入中添加 [-1,1] 之间的数,对进行一点修改,以编码其位置。对于编码器的其余部分,单词将根据单词在中的位置略有不同地表示(即使是同一个单词)。

编码器必须能够利用这样一个事实,即一些字在给定位置,而在同一序列中,其他字在其他特定位置。也就是说,我们希望网络能够理解相对位置,而不仅仅是绝对位置。****

https://www.mihaileric.com/posts/transformers-attention-in-disguise/

作者选择的正弦函数允许位置被表示为彼此的线性组合,从而允许网络学习记号位置之间的相对关系

让我们考虑一个例子:

********

位置嵌入可以理解为序列中不同单词之间的距离。这里的直觉是将这些值添加到嵌入中提供了嵌入向量之间有意义的距离,一旦它们被投影到 Q/K/V 向量中,以及在点积注意力期间。****

https://mc.ai/seq2seq-pay-attention-to-self-attention-part-2/

2.→编码器模块

https://jalammar.github.io/illustrated-transformer/

总共 N 个编码器模块链接在一起,产生编码器的输出。

注: 伯特’s 实验中,块数 N(或者他们所说的 L)被选为 12 和 24。**

  • 编码块的输入输出的尺寸相同。因此,使用一个编码器模块的输出作为下一个编码器模块的输入是有意义的。
  • 一个特定的模块负责寻找输入表示之间的关系,并将它们编码到其输出中。**
  • 这些块彼此不共享权重。
  • 这种通过块的迭代过程将帮助神经网络捕获输入序列中单词之间更复杂的关系。
  • 转换器使用 多头注意力 ,这意味着它用不同权重矩阵计算注意力 h 不同时间,然后将结果串联在一起。****

注意机制

让我们深入研究一下注意力机制。请注意,编码器模块解码器模块之间的多头自我关注是不同的。

https://mc.ai/seq2seq-pay-attention-to-self-attention-part-2/

一个头自我关注

一个 RNN 保持一个隐藏状态,允许它将它已经处理过的先前单词/向量的表示与它正在处理的当前单词/向量的表示合并。自我关注是转换器用来将对其他相关单词的“理解”烘焙到我们当前正在处理的单词中的方法。

https://jalammar.github.io/illustrated-transformer/

这句话中的“ it 指的是什么?它指的是街道还是动物?

  • 从每个编码器的输入向量的创建三个向量
  • 对于的每个单词,我们创建一个查询向量一个关键向量,以及*一个值向量*******
  • 这些向量是通过将嵌入乘以三个矩阵创建的,这三个矩阵是我们在训练过程中训练的。****

注意这些新向量在尺寸上比嵌入向量小。它们的维度是 64* ,而嵌入和编码器输入/输出向量的维度是 512。*****

为什么维度是 64?正如我们必须拥有的:

****- >输出的维数是【输入序列长度】x【嵌入维数— 512】

->我们在多头自关注过程中使用 8 头。给定自我关注向量的输出大小为【输入序列长度】x【64】。因此所有多头自关注*过程产生的连接向量将是[输入序列长度]x([64]x[8])=[输入序列长度] x ([512])*******

How Self-Attention works?

查询 q:查询向量 q 对左侧正在关注的单词/位置进行编码,即正在“查询”其他单词的那个。在上例中,突出显示了“the”(所选单词)的查询向量。****

键 k: 键向量 k 对关注的右边的单词进行编码。如下所述,关键向量与查询向量一起确定各个单词之间的关注度得分。

q×k (逐元素):查询向量和一个关键向量的逐元素乘积。该乘积是在所选查询向量和每个关键向量之间计算的。这是点积(逐元素积的总和)的前身,包含它是为了可视化,因为它显示了查询中的单个元素和关键向量是如何贡献点积的。

q k :选择的查询向量和每个 keyvectors 的点积。这是未标准化的注意力得分。

Softmax :所有目标词的 q k / 8 的 Softmax。这将注意力分数归一化为正值,并且总和为 1。常数因子 8 是向量长度的*方根(64)。这个 softmax 分数决定了每个单词在这个位置的表达量。显然,在这个位置的单词将具有最高的 softmax 分数,但是有时关注与当前单词相关的另一个单词是有用的。

这三个向量怎么算?

我们为输入序列中的每个单词计算自我注意。

关注“分数”

【K 的 Q x 转置】是查询向量关键向量的乘积标量。关键向量查询向量越接*,由【Q x 转置】得到的分数越高。****

Softmax 将为我们提供一种概率分布,该概率分布保持增加与相应查询向量相似的关键向量的值,并因此保持减少远离查询向量的关键向量。

  • d _ v设置为d _ k=d _ v=emb _ dim/h .

记住 QK 是令牌到一个 d_k (即 64)维空间的不同投影。因此,我们可以把 这些投影的点积看作是表征投影之间相似性的度量 。对于通过 Q 投影的每个向量,通过K投影的点积测量这些向量之间的相似性。如果我们分别通过 QKv _ Iu_j 称为第 I 个令牌第 j 个令牌的投影,它们的点积可以看做:********

这是衡量的方向有多相似 u_iv _ j它们的长度有多大(方向越*,长度越大,点积越大)。******

考虑这个矩阵乘积的另一种方式是作为输入序列中每个记号之间的特定关系的编码(该关系由矩阵 KQ 定义)。

https://lesdieuxducode.com/blog/2019/4/bert--le-transformer-model-qui-sentraine-et-qui-represente

https://towardsdatascience.com/deconstructing-bert-part-2-visualizing-the-inner-workings-of-attention-60a16d86b5c1

我们看到""的查询向量和" store "(下一个单词)的关键向量乘积在大多数神经元中都是强正的。对于除下一个令牌之外的令牌,键查询产品包含一些正值和负值的组合。结果是“The”和“store”之间的关注度得分较高。******

举例:考虑一下这个短语——“行动得到结果** ”。为了计算第一个单词“Action”的自我关注度,我们将计算短语中所有单词相对于“Action”的得分。当我们对输入序列中的某个单词进行编码时,该分数决定了其他单词的重要性。****

https://www.analyticsvidhya.com/blog/2019/06/understanding-transformers-nlp-state-of-the-art-models/

https://www.analyticsvidhya.com/blog/2019/06/understanding-transformers-nlp-state-of-the-art-models/

让我们回到最初的例子:

********

总而言之,当谈到单头自我关注时

注意力背后的主要思想是查找表,一个有大量其他值的表你问它一个查询它返回一个最接*它的。在这里使用的方法中,我们给它提供了三个值,查询。有大量的键,基本上是 n 维空间中的 1 维向量,其中每个键都有一些对应的值。

https://medium.com/datadriveninvestor/lets-build-attention-is-all-you-need-1-2-de377cebe22

注意功能可以描述为一个字典对象

https://persagen.com/resources/biokdd-review-nlu.html

B —多头自我关注

这篇论文指出“附加注意”比上述自我注意表现得更好,尽管它要慢得多。加法注意力使用更复杂的兼容性函数,即前馈神经网络。

在 Transformer 的架构中,自我关注不是一次而是多次计算,并行且独立。因此称为多头关注。输出被连接并进行线性转换,如下图所示:

变压器使用八个注意力头,所以我们最终为每个编码器/解码器提供八套。每个集合用于将输入嵌入投影到不同的表示子空间。如果我们做同样的自我关注计算,我们会得到八个不同的 Z 矩阵。

然而,前馈层并不期望八个矩阵。我们需要将它们连接起来,并通过将它们与附加权重矩阵 w0 相乘,将这八个压缩成一个矩阵

在多头注意力中如何将 8 个矩阵 Z1…Z8 返回成单个矩阵 Z?

在一个矩阵 W0 上串联一个排序,维数为 512 x 512([(nom bre de têtes)x(dimension reqête or cléou valeur,即 64)]x[dimension des embedding]),快速研究在一个排序空间上的结果。

https://lesdieuxducode.com/blog/2019/4/bert--le-transformer-model-qui-sentraine-et-qui-represente

总而言之…

https://jalammar.github.io/illustrated-transformer/

结果如下:

https://jalammar.github.io/illustrated-transformer/

辍学、新增和正常

https://web . Stanford . edu/class/archive/cs/cs 224n/cs 224n . 1184/lectures/lectures 12 . pdf

在这一层之前,总有一层输入和输出具有相同的尺寸(多头关注前馈)。我们称该层为子层及其输入 x.****

在每个子层之后,以 10%的概率应用丢失。把这个结果叫做 Dropout(Sublayer(x)) 。这个结果被添加到子层的输入 x,,我们得到 x + Dropout(子层(x))。****

注意,在多头注意力层的上下文中,这意味着将令牌 x 的原始表示添加到基于与其他令牌的关系的表示中。这就像告诉令牌:**

“学习与其余令牌的关系,但不要忘记我们已经了解的关于你自己的内容!”

最后,用每一行的*均值和标准偏差计算标记方式/行方式的归一化。这提高了网络的稳定性。

https://jalammar.github.io/illustrated-transformer/

https://arxiv.org/pdf/1607.06450.pdf

我们计算用于归一化的*均值和方差,该*均值和方差来自单个训练案例中一层中神经元的所有总计输入。

位置式前馈网络

除了注意子层之外,我们的编码器和解码器中的每一层都包含一个完全连接的前馈网络,该网络分别且相同地应用于每个位置。这由两个线性转换组成,中间有一个 ReLU 激活。

https://mc.ai/seq2seq-pay-attention-to-self-attention-part-2/

虽然不同位置的线性变换是相同的,但是它们在层与层之间使用不同的参数。另一种描述方式是两个内核大小为 1 的卷积。输入和输出的维数是 dmodel=512,内层的维数是 dff=2048。

神经元的形式与一个激活的相关函数,形式类似于:

Ici W1 a pour dimensions[dimension des embedding]x[dimension d ' entre d '渡厄·FFN-奥乔瓦]和 W2[dimension d ' entre 渡厄·FFN-奥乔瓦]x[dimension des embedding]。来源ici

3.→解码器模块

每个解码层由子层组成:

  1. 屏蔽多头注意(带前瞻屏蔽填充屏蔽
  2. 多头注意(带垫口罩)。v(值)和 K(键)接收编码器输出作为输入。Q (query)接收来自屏蔽多头注意子层的输出。****
  3. 点式前馈网络

这些子图层中的每一个都有一个围绕它的残差连接,然后是图层规范化。每个子层的输出是LayerNorm(x + Sublayer(x))

变压器中有 N 个解码器层。

Q 接收来自解码器第一关注块的输出, K 接收编码器输出关注权重代表基于编码器输出给予解码器输入的重要性。换句话说,解码器通过查看编码器输出并关注自身输出来预测下一个字。

Decoder包括:

  1. 输出嵌入
  2. 位置编码
  3. 解码器层

目标经过嵌入,该嵌入与位置编码相加。该求和的输出是解码器层的输入。解码器的输出是最终线性层的输入。

What are the inputs of Transformer?

我们同时输入和输出句子。输出最初可以用任何东西填充,模型忽略你填充的任何东西。它使用整个输入句子和输出句子一次性预测下一个单词。一旦我们预测了单词,我们在输出序列中替换它,模型只考虑到该点的输出,而忽略它前面的内容。我们继续这样做,直到我们有一个完整的句子。

多头掩蔽自我注意

编码器中,自关注层过程输入查询来自上一层输出的编码器中的每个位置可以照顾到上一层编码器的所有位置**

解码器中,自关注层使每个位置能够关注解码器中所有以前的位置,包括当前位置。**

https://persagen.com/resources/biokdd-review-nlu.html

To prevent positions from attending to subsequent position (http://www.peterbloem.nl/blog/transformers)

换句话说,自关注层仅被允许关注输出序列中前面的位置。掩蔽多头注意力是通过在自我注意力计算中的 softmax 步骤之前掩蔽未来位置(将它们设置为-∞)来完成的。该步骤确保位置 i 的预测仅依赖于小于 i 位置的已知输出。因为我们希望这些元素在 softmax 之后为零,所以我们将它们设置为。

http://www.peterbloem.nl/blog/transformers

对于 RNNs——不存在这样的问题,因为它们无法预测输入序列:输出 I 仅取决于输入 0 至 i 。使用 transformer,输出依赖于整个输入序列,因此预测下一个单词/字符变得非常容易,只需从输入中检索即可。

要使用自我关注作为自回归模型,我们需要确保它不能预测到结果 e。在应用 softmax 之前,我们通过对点积矩阵应用遮罩来做到这一点。该掩码禁用矩阵对角线上方的所有元素

在我们像这样禁用了自我关注模块之后,模型在序列中不再向前看。

解码器关注层的工作方式类似于多头自我关注,除了它从其下面的层创建其查询矩阵,并且从编码器堆栈的输出中获取键和值矩阵。

********

解码器中的自关注层允许解码器中的每个位置关注解码器中的所有位置,直到并包括该位置。我们需要在解码器中防止向左的信息流,以保持的自回归特性。我们通过屏蔽(设置为∞)soft max 输入中与非法连接相对应的所有值,在比例点积注意中实现这一点。

4.→最终的线性和 Softmax 层

解码器堆栈输出一个浮点向量。我们如何把它变成一个单词?这是最后一个线性层的工作,接着是一个 Softmax 层。

线性层是一个简单的全连接神经网络,它将解码器堆栈产生的矢量投影到一个更大的矢量中,称为 logits 矢量。这个空间就是词汇量(所有单词)的大小。我们只是将权重矩阵(由解码器块提供)投影到“词汇空间”中。

从数学上讲,这意味着什么?

从代码的角度来看。关于矩阵 W1 的乘法。这是一个完整的连接,它是一个简单的在一个不可改变的尾巴空间里的一个故事。**

在我们的词汇词典中,这是一个单词。elle aura donc pour dimensions[dimension des embedding,即d model]x[nom bre de mots dans notere]。**

让我们假设我们的模型知道 10,000 个独特的英语单词(我们模型的“输出词汇”),这些单词是从它的训练数据集学习来的。这将使 logits 向量有 10,000 个单元格宽每个单元格对应一个唯一单词的分数。这就是我们如何解释线性层之后的模型输出。

然后 softmax 层将这些分数转化为概率(都是正数,加起来都是 1.0)。选择概率最高的单元格,并产生与之相关的单词作为该时间步长的输出。Softmax 为我们提供了最有可能预测到的单词(我们采用给我们最高概率的列中的单词)。

https://jalammar.github.io/illustrated-transformer/

该图从底部开始,矢量作为解码器堆栈的输出产生。然后它被转换成一个输出字。

5.→剩余连接

一个残差连接基本上就是取输入,加到子网络的输出,让训练深度网络在计算机视觉领域变得更容易。层归一化是深度学习中的一种归一化方法,类似于批量归一化。在图层标准化中,统计数据是跨每个特征计算的,并且独立于其他示例。输入之间的独立性意味着每个输入都有不同的规范化操作。

7.→模型训练—如何训练 BERT?

A —屏蔽语言建模(MLM)

屏蔽语言模型从输入中随机屏蔽一些标记,目标是仅基于其上下文预测屏蔽单词的原始词汇 id。与从左到右语言模型预训练不同,MLM 目标允许表示融合左右上下文,这允许我们预训练一个深度双向转换器

谷歌人工智能研究人员随机屏蔽了每个序列中 15%的单词。任务?来预测这些蒙面文字。这里有一个警告—被屏蔽的单词并不总是被屏蔽的标记[MASK]替换,因为[MASK]标记在微调过程中永远不会出现。

因此,研究人员使用了以下技术:

  • 80%的情况下,单词被替换为掩码标记[MASK]
  • 10%的时候,这些单词被随机的单词替换
  • 10%的时间单词保持不变

XLNet

B-下一句预测

通常,语言模型不能捕捉连续句子之间的关系。伯特也预先接受了这项任务的训练。

对于语言模型预训练,BERT 使用句子对作为其训练数据。每一对的选句都挺有意思的。我们试着借助一个例子来理解一下。

假设我们有一个包含 100,000 个句子的文本数据集,我们希望使用该数据集预先训练一个 BERT 语言模型。因此,将有 50,000 个训练示例或句子对作为训练数据。

  • 对于 50%的配对,第二句实际上是第一句的下一句
  • 对于剩余的 50%的对,第二个句子将是来自语料库的随机句子
  • 第一种情况的标签是‘是下一个’,第二种情况的标签是‘不是下一个’******

应用程序?

A- Real 应用程序:预培训与微调

A review of BERT based models (https://towardsdatascience.com/a-review-of-bert-based-models-4ffdc0f15d58)

在领域/应用特定语料库上预训练的模型是预训练模型。在特定领域语料库上的训练已经表明,当在下游自然语言处理任务(如 NER 等)上对它们进行微调时,会产生更好的性能。对于那些领域,对比微调 BERT (在图书语料库和维基百科上训练过)

  • 比奥伯特 (生物医学文本)
  • 塞伯特 (科学出版物)
  • (临床笔记)
  • G-BERT ( 医疗/诊断代码表示和建议)
  • M-BERT 来自 104 种语言,用于零触发跨语言模型转移(一种语言中的任务特定注释用于微调模型,以便在另一种语言中进行评估)**
  • 厄尼 (知识图)+ 厄尼 (2)将知识融入预训练但通过使用 KG 屏蔽实体和短语。
  • trans Bert——无监督,跟随两个监督步骤,用于故事结局预测任务
  • videoBERT ( 联合学习视频和语言表示学习的模型)通过将视频帧表示为特殊的描述符令牌,以及用于预训练的文本。这用于视频字幕。

微调型号。使用预训练模型针对特定任务进行微调的模型:

  • 文档分类(文档分类)
  • PatentBERT (专利分类)

b 案例研究

  • 使用 BERT 进行更好的情感分析:通过在预训练的模型上应用一个新层和 softmax 进行微调+使用 Docker 和 Tensorflow + API
  • 使用 BERT 和 TensorFlow 构建多标签文本分类器:在多标签分类中,不使用 softmax() ,而是使用 sigmoid() 来获取概率。Sigmoid 允许处理非独占标签(也称为多标签),而 softmax 处理独占类+计算一个 logit (也称为分数)
  • 逻辑回归& BERT :使用 BERT 嵌入运行逻辑回归
  • 使用 PyTorch 的 BERT 微调教程:
  • 驯服 BERT——基线:微调 BERT 模型,而不是使用预先训练的权重+使用 BERT 层的混合,而不是只使用最后一层的输出+调整 MLP 模型的一些超参数
  • BERT:Faire comprender le langage naturalàa machine,en pre-entrant des Transformers bi-directionals profonds:法国分类

奖金:

1.为什么要除以*方(dk)?

2.微调

**来自https://yashuseth . blog/2019/06/12/Bert-explained-FAQs-understand-Bert-working/

  • 序列分类任务的微调程序是什么?
  • 句子对分类任务的微调程序是怎样的?
  • 问答任务的微调程序是怎样的?
  • 单句标注任务的微调程序是怎样的?

3.伯特即服务

输入记号的最终隐藏状态(变换器输出)可以被连接和/或汇集在一起,以获得句子的编码表示。bert-as-a-service是一个开源项目,提供针对生产优化的 BERT 语句嵌入。 使用 Tensorflow 和 ZeroMQ 在生产中服务 Google BERT。

4.库尔贝克·莱布勒散度

https://en.wikipedia.org/wiki/Kullback–Leibler_divergence

从“R 与 Python”到“R 与 Python”

原文:https://towardsdatascience.com/from-r-vs-python-to-r-and-python-aa25db33ce17?source=collection_archive---------0-----------------------

在单个项目中充分利用 Python 和 R’的优点。

重点应该放在技能上,而不是工具上

如果你对数据科学感兴趣,可能会立即想到的两种编程语言是 RPython 。然而,我们不是将它们视为两种选择,而是经常将它们进行比较。r 和 Python 本身都是优秀的工具,但经常被视为竞争对手。如果你在谷歌搜索栏中输入R vs Python,你会立即得到大量关于一方优于另一方的话题的资源。

这种观点的原因之一是因为人们已经根据他们使用的编程语言的选择将数据科学领域分成了不同的阵营。有一个 R 阵营和一个 Python 阵营,历史是两个阵营无法和谐相处的见证。两个阵营的成员都坚信他们选择的语言优于对方。所以,在某种程度上,分歧不在于工具,而在于使用这些工具的人

为什么不两个都用?

数据科学社区中有人同时使用 Python 和 R,但他们的比例很小。另一方面,有许多人只致力于一种编程语言,但希望他们能够获得对手的一些能力。例如,R 用户有时渴望 Python 固有的面向对象能力,类似地,一些 Python 用户渴望 R 中可用的大范围统计分布。

上图为红和尚2018 年第三季度调查结果。这些结果基于语言在 Stack OverflowGithub 上的受欢迎程度,清楚地表明 R 和 Python 都被评为相当高。因此,我们没有内在的理由不能在同一个项目中与他们合作。我们的最终目标应该是做更好的分析,获得更好的洞察力,选择编程语言不应该成为实现这一目标的障碍。

R 和 Python 概述

让我们来看看这些语言的各个方面,以及它们的优点和缺点。

计算机编程语言

自 1991 年发布以来,Python 一直非常流行,并广泛应用于数据处理。它广受欢迎的一些原因是:

  • 面向对象语言
  • 通用
  • 有很多扩展和令人难以置信的社区支持
  • 简单易懂,易于学习
  • 像 pandas、numpy 和 scikit-learn 这样的包使 Python 成为机器学习活动的绝佳选择。

然而,Python 没有专门的统计计算包,不像 r。

稀有

r 的第一个版本发布于 1995 年,从那时起,它已经成为业内最常用的数据科学工具之一。

  • 包括几乎所有你能想到的统计应用的软件包。CRAN 目前托管超过 10k 个软件包。
  • 配备了出色的可视化库,如 ggplot2。
  • 能够独立分析

就性能而言,R 不是最快的语言,而且在处理大型数据集时,有时会占用大量内存。

利用两个世界的优点

我们能利用 R 的统计能力和 Python 的编程能力吗?那么,当我们可以轻松地将 SQL 代码嵌入到 R 或 Python 脚本中时,为什么不将 R 和 Python 融合在一起呢?

基本上有两种方法可以让我们在一个项目中同时使用 Python 和 R。

Python 中的 r

  • 派珀

PypeR 提供了一种通过管道从 Python 访问 R 的简单方法。PypeR 也包含在 Python 的包索引中,这提供了一种更方便的安装方式。当 Python 和 R 之间不需要频繁的交互数据传输时,PypeR 特别有用。通过管道运行 R,Python 程序在子进程控制、内存控制和跨流行操作系统*台(包括 Windows、GNU Linux 和 Mac OS)的可移植性方面获得了灵活性

Conventions for conversion of Python objects to R objects

  • pyRserve

pyRserve 使用 Rserve 作为 RPC 连接网关。通过这样的连接,可以在 Python 的 R 中设置变量,也可以远程调用 R 函数。R 对象作为 Python 实现的类的实例公开,在许多情况下,R 函数作为这些对象的绑定方法。

  • rpy2

rpy2 在 Python 进程中运行嵌入式 R。它创建了一个框架,可以将 Python 对象翻译成 R 对象,将它们传递给 R 函数,并将 R 输出转换回 Python 对象。rpy2 使用得更频繁,因为它是一种正在积极开发的产品。

在 Python 中使用 R 的一个好处是,我们可以在 Python 中轻松使用 R 的优秀包,如 ggplot2、tidyr、dplyr 等。作为一个例子,让我们看看如何在 Python 中轻松使用 ggplot2 进行映射。

  • 基本情节

https://rpy2.github.io/doc/latest/html/graphics.html#plot

  • 几何

https://rpy2.github.io/doc/latest/html/graphics.html#geometry

资源

为了更深入地了解 rpy2 ,您可能想看看以下资源:

  • rpy2 的官方文档
  • RPy2:为数据科学结合 R + Python 的力量
  • 使用 RPy2 从 Python 访问 R

R 内的 Python

我们可以使用下面的一种方法在 Python 中运行 R 脚本:

  • rJython

这个包通过 Jython 实现了 Python 的一个接口。它旨在让其他包能够嵌入 python 代码和 r。

  • rPython

rPython 又是一个允许 R 调用 Python 的包。它使得运行 Python 代码、进行函数调用、分配和检索变量等成为可能。从 r。

  • 耍蛇人

《耍蛇者》是 rPython 的现代改良版。它是“rPython”的一个分支,使用了“jsonlite ”,对 rPython 做了很多改进。

  • 皮托尼尔

PythonInR 通过提供从 R 内部与 Python 交互的函数,使得从 R 内部访问 Python 变得非常容易。

  • 网状

reticulate 包为 Python 和 r 之间的互操作性提供了一套全面的工具。在上述所有选择中,这一个是使用最广泛的,因为它是由 Rstudio 积极开发的。Reticulate 在 R 会话中嵌入了一个 Python 会话,实现了无缝、高性能的互操作性。这个包使你能够将 Python 代码编织成 R 语言,创建一个将两种语言编织在一起的新型项目。

网状包提供以下设施:

  • 以多种方式从 R 调用 Python,包括 R Markdown、获取 Python 脚本、导入 Python 模块以及在 R 会话中交互使用 Python。
  • R 和 Python 对象之间的转换(例如,R 和 Pandas 数据框之间,或者 R 矩阵和 NumPy 数组之间)。
  • 灵活绑定到不同版本的 Python,包括虚拟环境和 Conda 环境。

资源

关于使用 reticulate 包的一些重要资源有:

  • 文档非常健壮,有很多例子和用例来帮助你开始。
  • https://longhowlam . WordPress . com/2017/04/10/test-driving-python-integration-in-r-using-the-reticulate-package/
  • 包装中的蛇:结合 PYTHON 和 R 与 RETICULATE

结论

R 和 Python 都是非常健壮的语言,它们中的任何一种实际上都足以执行数据分析任务。然而,他们两个肯定都有高低之分,如果我们能利用两者的优势,我们最终会做得更好。无论哪种方式,拥有这两方面的知识将使我们更加灵活,从而增加我们能够在多种环境中工作的机会。

参考

本文改编自 Andrew Collier 于 2018 年在 Pydata Berlin 发表的这篇 精彩演讲

http://blog . yhat . com/tutorials/RP y2-coming-the-power-of-r-and-python . html

从原始图像到深度学习的实时预测

原文:https://towardsdatascience.com/from-raw-images-to-real-time-predictions-with-deep-learning-ddbbda1be0e4?source=collection_archive---------6-----------------------

使用 Keras、Flask 和 OpenCV 的人脸表情识别

Photo by Peter Lloyd on Unsplash

在我看来,人工智能最令人兴奋的领域之一是计算机视觉。我发现非常有趣的是,我们现在如何从复杂的原始数据结构(如图像)中自动提取知识。

本文的目标是探索一个计算机视觉应用的完整例子:构建一个具有深度学习的人脸表情识别系统。我们将了解如何:

  • 设计一个卷积神经网络
  • 通过输入一批图像来训练它
  • 将其导出,以便与实时图像数据一起重新使用

工具

Keras 是一种高级神经网络 API,用 Python 编写,能够在 TensorFlow、CNTK 或 Theano 之上运行。我们将用它来建立、训练和输出神经网络。

Flask 是一个用 Python 编写的微型 web 框架,它允许我们将模型直接提供给 web 界面。

OpenCV 是一个计算机视觉库,有 C++、Python 和 Java 接口。我们将使用这个库来自动检测图像中的人脸。

数据源

数据来源于往届 Kaggle 竞赛《表征学习中的挑战:面部表情识别挑战》:

https://www . ka ggle . com/c/challenges-in-re presentation-learning-face-expression-recognition-challenge

该数据由 48x48 像素的面部灰度图像组成。面部已经被自动注册,使得面部或多或少地居中,并且在每个图像中占据大约相同的空间。每张图片对应七种表情中的一种(0 =生气,1 =厌恶,2 =恐惧,3 =快乐,4 =悲伤,5 =惊讶,6 =中性)。数据集包含大约 36K 幅图像。

原始数据包含在数组中,每个像素有一个灰度值。我们将这些数据转换成原始图像,并将其拆分到多个文件夹中:

images/
    train/
        angry/
        disgust/
        fear/
        happy/
        neutral/
        sad/
        surprise/
    validation/
        angry/
        disgust/
        fear/
        happy/
        neutral/
        sad/
        surprise/

我们 80%的图像包含在 train 文件夹中,最后 20%在 validation 文件夹中。

快速数据可视化

首先让我们看看我们的图像是什么样子的:

Sample of the training images

你能猜出这些图像与哪些表情有关吗?

这项任务对人来说很容易,但对预测算法来说可能有点挑战,因为:

  • 这些图像的分辨率很低
  • 这些面不在同一位置
  • 一些图像上写有文字
  • 有些人用手遮住部分脸

然而,所有这些图像的多样性将有助于建立一个更通用的模型。

4103 fear images
436 disgust images
4982 neutral images
7164 happy images
3993 angry images
3205 surprise images
4938 sad images

除了“厌恶”类别,我们训练数据集中的面部表情相当*衡。

设置数据生成器

深度学习模型通过输入批量数据来训练。Keras 有一个非常有用的类可以自动从目录中获取数据:ImageDataGenerator。

Found 28821 images belonging to 7 classes.
Found 7066 images belonging to 7 classes.

它还可以在获取图像的同时执行数据扩充(随机旋转图像、缩放等。).当数据集很小时,这种方法通常被用作人工获取更多数据的方法。

函数 flow_from_directory()指定生成器应该如何导入图像(路径、图像大小、颜色等)。).

设置我们的卷积神经网络(CNN)

我们选择使用卷积神经网络来解决这个人脸识别问题。事实上,这种类型的神经网络(NN)对于提取图像的特征是很好的,并且被广泛用于图像分析主题,如图像分类。

快速提醒什么是 NN:

神经网络是由多层人工神经元(节点)组成的学习框架。每个节点获得加权的输入数据,将其传递给激活函数,并输出该函数的结果:

A node

神经网络由几层节点组成:

A classic NN architecture

  • 将获取数据的输入图层。输入图层的大小取决于输入数据的形状。
  • 一些隐藏层将允许神经网络学习数据中复杂的相互作用。具有许多隐藏层的神经网络被称为深度神经网络。
  • 给出最终结果的输出层,例如类别预测。这一层的大小取决于我们想要产生的输出类型(例如,我们想要预测多少个类?)

经典神经网络通常由几个完全连接的层组成。这意味着一层的每个节点都连接到下一层的所有节点。

卷积神经网络也具有卷积层,该卷积层将滑动函数应用于彼此相邻的像素组。因此,这些结构对我们可以在图像中观察到的模式有更好的理解。我们将在后面对此进行更详细的解释。

现在让我们来定义 CNN 的架构:

我们用以下全球架构定义我们的 CNN:

  • 4 个卷积层
  • 2 个完全连接的层

卷积层将从图像中提取相关特征,完全连接的层将专注于使用这些特征来很好地分类我们的图像。这个建筑的灵感来自于以下关于这个主题的工作:【https://github.com/jrishabh96/Facial-Expression-Recognition

现在让我们来关注这些卷积层是如何工作的。其中每个都包含以下操作:

  • 卷积运算符:使用滑动矩阵从输入图像中提取特征,以保持像素之间的空间关系。下图总结了它的工作原理:

A convolution operator

绿色矩阵对应于原始图像值。橙色滑动矩阵被称为“过滤器”或“内核”。此滤镜在图像上滑动,每步滑动一个像素。在每一步中,我们将滤波器与基础矩阵的相应元素相乘,并将结果相加。有不同类型的过滤器,每一种都能够检索不同的图像特征:

Different filter results

  • 我们应用 ReLU 函数在 CNN 中引入非线性。也可以使用其他函数,如 tanh 或 sigmoid,但 ReLU 在大多数情况下表现更好。
  • 池用于减少每个特征的维数,同时保留最重要的信息。像卷积步骤一样,我们对数据应用滑动函数。可以应用不同的函数:max、sum、mean…max 函数通常执行得更好。

Max pooling operation

我们还为每一层使用一些通用技术:

  • 批量标准化:通过提供零均值和单位方差的输入,提高 NNs 的性能和稳定性。
  • Dropout:通过随机不更新某些节点的权重来减少过度拟合。这有助于防止神经网络过分依赖层中的一个节点。

我们选择 softmax 作为最后的激活函数,因为它通常用于多标签分类。

现在我们的 CNN 已经定义好了,我们可以用更多的参数来编译它。我们选择 Adam 优化器,因为它是计算效率最高的优化器之一。我们选择分类交叉熵作为我们的损失函数,因为它与分类任务非常相关。我们的衡量标准将是准确性,这对于*衡数据集上的分类任务也非常有用。

在这里,我们从头开始定义和训练我们的 CNN,但您可能希望对需要更多计算资源的问题应用迁移学习方法。Keras 有几个预先训练好的模型可供使用:

[## 应用程序— Keras 文档

Keras 应用程序是深度学习模型,可与预训练的权重一起使用。这些型号可以是…

keras.io](https://keras.io/applications/)

训练模型

一切都准备好了,现在开始训练我们的模型吧!

Epoch 1/50
225/225 [==============================] - 36s 161ms/step - loss: 2.0174 - acc: 0.2333 - val_loss: 1.7391 - val_acc: 0.2966

Epoch 00001: val_acc improved from -inf to 0.29659, saving model to model_weights.h5Epoch 2/50
225/225 [==============================] - 31s 138ms/step - loss: 1.8401 - acc: 0.2873 - val_loss: 1.7091 - val_acc: 0.3311

Epoch 00002: val_acc improved from 0.29659 to 0.33108, saving model to model_weights.h5...Epoch 50/50
225/225 [==============================] - 30s 132ms/step - loss: 0.6723 - acc: 0.7499 - val_loss: 1.1159 - val_acc: 0.6384

Epoch 00050: val_acc did not improve from 0.65221

我们的最佳模型设法获得了大约 65%的验证准确率,这已经很不错了,因为我们的目标类有 7 个可能的值!

在每个时期,Keras 检查我们的模型是否比前一时期的模型表现得更好。如果是这种情况,新的最佳模型权重被保存到文件中。这将允许我们直接加载模型的权重,而不必在其他情况下使用它时重新训练它。

我们还必须保存我们的 CNN 的结构(层等)。)到一个文件中:

分析结果

我们在训练阶段的每一步都有产出。所有这些输出都保存在“历史”变量中。我们可以使用它在训练和验证数据集上绘制损失和准确性的演变:

Evolution of loss and accuracy with the number of training epochs

在 50 个周期结束时,验证准确度开始稳定在 60%和 65%之间。

训练损失略高于第一个时期的验证损失,这可能令人惊讶。事实上,我们习惯于看到机器学习中验证损失比训练损失更高。在这里,这仅仅是由于辍学的存在,它只适用于培训阶段,而不是在验证阶段。

我们可以看到,在第 20 次迭代之后,训练损失变得比验证损失小得多。这意味着我们的模型在太多的时期后开始过度适应我们的训练数据集。这就是为什么验证损失在之后没有减少很多的原因。一种解决方案是提前停止模型的训练。

我们也可以使用一些不同的丢弃值并执行数据扩充。这些方法在这个数据集上进行了测试,但是尽管它们减少了过拟合效应,但是它们并没有显著增加验证的准确性。使用它们稍微增加了模型的训练持续时间。

最后,我们可以绘制混淆矩阵,以了解我们的模型如何对图像进行分类:

我们的模型非常适合预测快乐和惊讶的面孔。然而,它预测的是非常糟糕的恐惧面孔,因为它把它们和悲伤的面孔混淆了。

随着更多的研究和更多的资源,这个模型肯定会得到改善,但这项研究的目标主要是集中在获得一个相当好的模型相比,在这个领域已经做了什么。

现在是时候在真实情况下尝试我们的模型了!我们将使用 flask 来服务于我们的模型,以便通过网络摄像头输入来执行实时预测。

实时预测

对于这一部分,我重用了来自以下存储库的一些代码:

  • https://github.com/log0/video_streaming_with_flask_example
  • https://github . com/piyush 2896/面部表情识别挑战

首先,让我们创建一个类,它将为我们提供之前训练的模型的预测:

接下来,我们实现一个 camera 类,它将执行以下操作:

  • 从我们的网络摄像头获取图像流
  • 使用 OpenCV 检测人脸并添加边界框
  • 将人脸转换成灰度,重新缩放,然后发送给我们预先训练好的神经网络
  • 从我们的神经网络中获取预测,并将标签添加到网络摄像头图像中
  • 返回最终的图像流

最后,我们的主脚本将创建一个 Flask 应用程序,将我们的图像预测渲染到一个网页中。

这是结果!

Our face expression recognition app

有用!我们的应用程序能够检测面部位置并预测正确的表情。

然而,该模型似乎在恶劣的条件下工作不佳(低光,人没有面对相机,人移动…),但仍然是一个好的开始!

感谢阅读这篇文章,我希望你喜欢它!

你可以在这里找到完整的代码:

[## jonathanoheix/实时人脸表情识别

带有 Keras、Flask 和 OpenCV-jonathanoheix/实时面部表情识别的面部表情识别应用程序

github.com](https://github.com/jonathanoheix/Real-Time-Face-Expression-Recognition)

在 LinkedIn 上找到我:

[## Jonathan Oheix -数据科学家- Influans | LinkedIn

查看 Jonathan Oheix 在全球最大的职业社区 LinkedIn 上的个人资料。乔纳森列出了 8 份工作…

www.linkedin.com](https://www.linkedin.com/in/jonathanoheix/)

从 sci kit-学会火花 ML

原文:https://towardsdatascience.com/from-scikit-learn-to-spark-ml-f2886fb46852?source=collection_archive---------8-----------------------

从 Python 到 Scala 的机器学习项目

在之前的一篇文章中,我展示了如何获取房屋销售的原始数据集,并在 Python 中对熊猫应用特征工程技术。这使我们能够使用 scikit-learn 机器学习模型来产生和改进对房屋销售价格的预测。

但是,当你想把这种项目投入生产,而不是 10,000 个数据点,也许有几十或几百千兆字节的数据来训练时,会发生什么呢?在这种情况下,脱离 Python 和 scikit 是值得的——学习可以处理大数据的框架。

输入 Scala 和 Spark

Scala 是一种基于 Java 虚拟机(JVM)的编程语言,使用函数式编程技术。Scala 中有无数非常复杂的特性可以学习,但是开始使用基本的 Scala 并不比用 Java 甚至 Python 编写代码难多少。

另一方面,Spark 是一个基于 Hadoop 技术的框架,它提供了比传统 Hadoop 更多的灵活性和可用性。它可能是管理和分析大型数据集(也称为大数据)的最佳工具。Spark ML 框架允许开发人员在构建机器学习模型时使用 Spark 进行大规模数据处理。

为什么不首先在 Spark ML 中完成所有的数据探索和模型训练呢?当然可以,但事实是,Python 更容易进行开放式探索,尤其是当您在 Jupyter 笔记本上工作时。但是话虽如此,Scala 和 Spark 并不需要比 Python 复杂太多,因为 pandas 和 Spark 都使用数据帧结构进行数据存储和操作。我们的目标是展示这种简单性,而不是纠结于困难。

这篇文章不会深入探讨 Scala 的复杂性,它假设你对之前的项目有所了解。我们将重现 Python 示例的结果,但我们不会重复我们这样做的所有原因,因为它们在前面已经解释过了。

首先,我们将从加载数据集开始,与之前完全相同的 CSV 文件。

val data_key = “housing_data_raw.csv”val df = spark.read
.format(“csv”)
.option(“header”, “true”)
.option(“inferSchema”, “true”)
.load(s”./$data_key”)

接下来,我们将删除我们在上一篇文章中发现的异常值。

import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.functions._def drop_outliers(data: DataFrame) = {
    val drop = List(1618, 3405,10652, 954, 11136, 5103, 916, 10967, 7383, 1465, 8967, 8300, 4997)

    data.filter(not($"_c0".isin(drop:_*)))
}val housing = drop_outliers(df)

现在,我们将lastsolddate字段从文本转换为数值,回归模型可以对其进行训练。

val housing_dateint = housing.withColumn("lastsolddateint", unix_timestamp($"lastsolddate","MM/dd/yy"))

我们还想删除一些列,反正现在我们不想在这些列上进行训练。

def drop_geog(data: DataFrame, keep: List[String] = List()) = {
    val removeList = List("info","address","z_address","longitude","latitude","neighborhood",
                          "lastsolddate","zipcode","zpid","usecode", "zestimate","zindexvalue")
    .filter(!keep.contains(_))

    data.drop(removeList: _*)
}val housing_dropgeo = drop_geog(housing_dateint)

我们通过一个函数来执行这个操作,以防我们以后想要再次运行相同的代码,我们将会这样做。还要注意,该函数有一个keep参数,以防我们想要实际保留我们要删除的这些值中的一个。我们稍后会讲到。

注意,除了两个主要的例外,这个语法的大部分非常接* Python。首先,Scala 是一种类型化语言。变量实际上不需要显式类型化,但是函数参数需要。第二,您将看到一行类似于:

data.drop(removeList: _*)

这意味着从数据 DataFrame 中删除removeList中的所有内容。_*是一个通配符类型定义,只是一些必要的语法,告诉 Scala 编译器如何完成工作。

在 Spark ML 中使用 VectorAssembler

现在,我们希望将数据分为训练集和测试集。

import org.apache.spark.ml.feature.VectorAssemblerdef train_test_split(data: DataFrame) = {

    val assembler = new VectorAssembler().
       setInputCols(data.drop("lastsoldprice").columns).
       setOutputCol("features")

    val Array(train, test) = data.randomSplit(Array(0.8, 0.2), seed = 30) (assembler.transform(train), assembler.transform(test))
}val (train, test) = train_test_split(housing_dropgeo)

这有点棘手,需要一些解释。

在 scitkit-learn 中,你可以获取整个熊猫数据帧,并将其发送给机器学习算法进行训练。Spark ML 也有一个数据帧结构,但模型训练总体上有点挑剔。您必须通过提取每行值并将它们打包到一个向量中,将您想要训练的每一列中的所有要素打包到一个列中。这意味着 Spark ML 只训练一列数据,而这恰好是一个实际包含多列数据的数据结构。一旦你有了代码(见上),设置起来并不复杂,但这是你必须意识到的一个额外的步骤。

使用 VectorAssembler 创建这些向量列之一。我们创建 VectorAssembler,表示我们想要使用所有的特征列(除了我们的标签/目标列,lastsoldprice),然后给新的向量列命名,通常是features。然后,我们使用这个新的组装器来转换两个数据帧,即测试和训练数据集,然后将每个转换后的数据帧作为一个元组返回。

现在,我们可以做一些机器学习。先说线性回归。

import org.apache.spark.ml.regression.LinearRegression
import org.apache.spark.ml.evaluation.RegressionEvaluatorval lr = new LinearRegression()
    .setLabelCol("lastsoldprice")
    .setFeaturesCol("features")val lrModel = lr.fit(train)
val predictions = lrModel.transform(test)val rmse = new RegressionEvaluator()
  .setLabelCol("lastsoldprice")
  .setPredictionCol("prediction")
  .setMetricName("rmse")val r2 = new RegressionEvaluator()
  .setLabelCol("lastsoldprice")
  .setPredictionCol("prediction")
  .setMetricName("r2")println("Root Mean Squared Error (RMSE) on test data = " + rmse.evaluate(predictions))
println("R^2 on test data = " + r2.evaluate(predictions))

我们的第一个预测

这应该是不言自明的。下面是上面代码的输出。

Root Mean Squared Error (RMSE) on test data = 857356.2890199891
R^2 on test data = 0.31933500943383086

这不太好,但这不是重点。这里真正的优势是我们现在有了一种格式的数据,我们可以使用 Spark ML,所以从这里开始尝试其他算法是很容易的一步。但是首先,我们将在一个函数中重新创建上述内容,我们可以使用不同的算法调用这个函数。在此过程中,我们将添加一个交叉验证选项,以便我们可以测试多个不同的超参数,并选择最佳结果模型。请注意,这一步并不是绝对必要的——前面的代码可以很容易地被重构以使用不同的算法——但这是一个更好的实践。

import org.apache.spark.ml.Predictor
import org.apache.spark.ml.PredictionModel
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.ml.tuning.{CrossValidator, ParamGridBuilder}
import org.apache.spark.ml.param.ParamMapdef train_eval[R <: Predictor[Vector, R, M],
               M <: PredictionModel[Vector, M]](
    predictor: Predictor[Vector, R, M],
    paramMap: Array[ParamMap],
    train: DataFrame, 
    test: DataFrame) = {val cv = new CrossValidator()
      .setEstimator( predictor    
                    .setLabelCol("lastsoldprice")
                    .setFeaturesCol("features"))
      .setEvaluator(new RegressionEvaluator()
          .setLabelCol("lastsoldprice")
          .setPredictionCol("prediction")
          .setMetricName("rmse"))
      .setEstimatorParamMaps(paramMap)
      .setNumFolds(5)
      .setParallelism(2) val cvModel = cv.fit(train)
    val predictions = cvModel.transform(test)

    println("Root Mean Squared Error (RMSE) on test data = " + rmse.evaluate(predictions))
    println("R^2 on test data = " + r2.evaluate(predictions)) val bestModel = cvModel.bestModel

    println(bestModel.extractParamMap)

    bestModel
}

大部分内容应该是不言自明的— 除了函数定义,它实际上是难以理解的。这是这一部分:

def train_eval[R <: Predictor[Vector, R, M],
               M <: PredictionModel[Vector, M]](
    predictor: Predictor[Vector, R, M],
    paramMap: Array[ParamMap],
    train: DataFrame, 
    test: DataFrame) = {

不幸的是,Spark ML 似乎没有一个通用的“模型”类型,例如,我们可以传入一个 RegressionModel 对象,然后我们的函数可以接受这个“模型”对象并调用.fit方法。这将使我们避免这种混乱。相反,我们必须提出这个复杂的定义,这样我们就可以创建一个接受通用“模型”类型的方法,因为该类型也依赖于输入格式和隐式赋值器类型。想出这种定义是相当棘手的——在环顾四周和反复试验之后,我发现直接从 Spark ML 源代码中提取它就可以了。

好消息是,一旦你写了这样的东西,呼叫者不需要真正了解或理解它(老实说,他们不太可能会了解)。相反,这种复杂类型定义允许调用者编写真正干净的代码,如下所示:

val lr = new LinearRegression()val lrParamMap = new ParamGridBuilder()
    .addGrid(lr.regParam, Array(10, 1, 0.1, 0.01, 0.001))
    .addGrid(lr.elasticNetParam, Array(0.0, 0.5, 1.0))
    .addGrid(lr.maxIter, Array(10000, 250000))
    .build()train_eval(lr, lrParamMap, train, test)

现在我们回到一些简单的东西:一个算法(线性回归)和一个交叉验证的参数网格。然后函数调用变得像我们在 Python 中看到的一样简单。这实际上是相同的代码。注意,我甚至为train_eval和其他变量保留了嵌入式下划线语法。在 Scala 和 Java 中,我们通常会使用 camel case,即trainEval,这也是我在编写产品代码时会做的事情,但是由于本教程最初是用 Python 编写的,所以为了比较,保持一些一致性是值得的。

我们现在来看看其他一些算法,看看它们是如何工作的。注意 Lasso 和 Ridge 没有显式类,因为elasticNetParam分别设置为 1 和 0 时指定这两种算法。

决策树:

import org.apache.spark.ml.regression.DecisionTreeRegressorval decisionTree = new DecisionTreeRegressor()
val dtParamMap = new ParamGridBuilder().build()
train_eval(decisionTree, dtParamMap, train, test)

结果:

Root Mean Squared Error (RMSE) on test data = 759685.8395738212
R^2 on test data = 0.46558480196241925

随机森林:

import org.apache.spark.ml.regression.RandomForestRegressorval randomForest = new RandomForestRegressor()val rfParamMap = new ParamGridBuilder()
    .addGrid(randomForest.maxBins, Array(4, 16, 32, 64))
    .addGrid(randomForest.numTrees, Array(1, 10, 100))
    .addGrid(randomForest.maxDepth, Array(2, 5, 10))
    .build()train_eval(randomForest, rfParamMap, train, test)

结果:

Root Mean Squared Error (RMSE) on test data = 647133.830611256
R^2 on test data = 0.6122079099308858

梯度增强:

import org.apache.spark.ml.regression.GBTRegressorval gradientBoost = new GBTRegressor()val gbParamMap = new ParamGridBuilder()
    .addGrid(randomForest.maxBins, Array(16, 32))
    .addGrid(randomForest.numTrees, Array(5, 10, 100))
    .addGrid(randomForest.maxDepth, Array(5, 10))
    .addGrid(randomForest.minInfoGain, Array(0.0, 0.1, 0.5))
    .build()train_eval(gradientBoost, gbParamMap, train, test)

结果:

Root Mean Squared Error (RMSE) on test data = 703037.6456894034
R^2 on test data = 0.5423137139558296

虽然确切的结果不同(特别是对于线性回归),但我们也看到了随机森林和梯度增强比更简单的算法工作得更好的类似趋势。同样,我们可以通过使用更好的数据来改进我们的结果。我们通过重新整合neighborhood数据来做到这一点,但采用算法可以使用的数字格式。我们通过使用 one-hot 编码将像MissionSouth Beach这样的类别更改为 1 和 0 的列来实现这一点。

一键编码

首先,我们用这些数据重建数据框架:

val housing_neighborhood = drop_geog(housing_dateint, List("neighborhood"))

然后,我们使用一个Pipeline通过一键编码来转换数据:

import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.OneHotEncoderEstimator
import org.apache.spark.ml.feature.StringIndexerval indexer = new StringIndexer().setInputCol("neighborhood").setOutputCol("neighborhoodIndex")val encoder = new OneHotEncoderEstimator()
  .setInputCols(Array(indexer.getOutputCol))
  .setOutputCols(Array("neighborhoodVector"))val pipeline = new Pipeline().setStages(Array(indexer, encoder))val housingEncoded = pipeline.fit(housing_neighborhood).transform(housing_neighborhood)
.drop("neighborhoodIndex")
.drop("neighborhood")

首先,我们必须使用一个StringIndexer,然后我们可以使用OneHotEncoderEstimator得到我们想要的结果。因为这是两个步骤,我们可以使用阶段的Pipeline将它们放在一起。管道可以用于许多多阶段的清理和修改操作,特别是当你需要一遍又一遍地做这些相同的阶段时,例如需要重新训练的不断发展的数据集。这在这里并不是真正必要的,但它值得展示,因为它非常有用。

更新数据后,我们可以像以前一样重新进行实验。我们只是传递我们的新数据(在创建训练和测试集之后):

val (train_neighborhood, test_neighborhood) = train_test_split(housingEncoded)

例如,对于线性回归,我们使用这些新变量调用完全相同的函数:

train_eval(lr, lrParamMap, train_neighborhood, test_neighborhood)

结果:

Root Mean Squared Error (RMSE) on test data = 754869.9632285038
R^2 on test data = 0.4723389619596349

这仍然不是很好,但比以前好多了。现在,让我们看看在传递转换后的数据帧后其他算法的结果。

决策树:

Root Mean Squared Error (RMSE) on test data = 722171.2606321493
R^2 on test data = 0.5170622654844328

随机森林:

Root Mean Squared Error (RMSE) on test data = 581188.983582857
R^2 on test data = 0.6872153115815951

梯度增强:

Root Mean Squared Error (RMSE) on test data = 636055.9695573623
R^2 on test data = 0.6253709908240936

在每种情况下,我们都看到了相当大的改进,现在我们有了一个模型和一个训练管道,可以用更大的数据集投入生产。

为 Connect4 从头开始实施 AlphaZero

原文:https://towardsdatascience.com/from-scratch-implementation-of-alphazero-for-connect4-f73d4554002a?source=collection_archive---------0-----------------------

一步一步的演示如何在游戏中使用 PyTorch 和标准 python 库实现 alpha zero

Demis Hassabis, the head of Google DeepMind. Credit: https://www.telegraph.co.uk/science/2017/12/06/entire-human-chess-knowledge-learned-surpassed-deepminds-alphazero

2016 年,谷歌 DeepMind 的计算机程序 AlphaGo 在一场有数百万人观看的比赛中以 4 比 1 击败了围棋世界冠军 Lee Sedol,这一壮举在此前一直由人类主导的超复杂围棋比赛中从未被任何计算机程序实现过。然而,在大约一年后的 2017 年由 DeepMind 出版的alpha go Zero,通过在没有任何人类数据输入的情况下实现类似的壮举,将边界向前推进了一大步。(AlphaGo 参考围棋特级大师游戏进行初始训练)同一组随后发布的一篇论文成功地将相同的强化学习+监督学习框架应用于国际象棋,仅经过 4 个小时的训练就超过了之前最好的国际象棋程序 Stockfish。

出于对这种强化学习模型的敬畏,我想了解它是如何获得一些见解的,没有什么比尝试从零开始构建自己的国际象棋人工智能程序更好的了,严格遵循上述论文中描述的方法。然而,事情很快变得过于昂贵,难以承受,因为即使程序已经启动并运行,训练它达到合理的技能水*很可能需要数百万的 GPU 和 TPU 成本。

由于无法与谷歌的雄厚财力相比,我决定尝试在 Connect4 上实现 AlphaZero,这是一种比国际象棋简单得多的游戏,对计算能力的要求也更低。这里的重点是证明 AlphaZero 算法最终可以很好地创建一个强大的 Connect4 AI 程序。这里描述的方法的实现脚本都可以在我的 Github repo 上找到。

连接 4 板

首先,我们需要用 Python 创建 Connect4 板供我们使用。我创建了一个名为“board”的类,有 4 个方法“init”、“drop_piece”、“check_winner”、“actions”。

Connect4 board in Python

  1. "init "构造函数将一个 6 行 7 列的空 Connect4 板初始化为 np.array,存储板的状态以及当前要玩的玩家

2)“drop _ piece”在每个玩家玩游戏时用“X”或“O”更新棋盘

3)“check _ winner”如果有人在当前棋盘状态中获胜,则返回 True

4)“动作”返回给定当前棋盘状态下可以下的所有可能的棋步,因此不会下非法的棋步

大局

AlphaZero 中有 3 个关键组件,稍后我将更详细地描述它们的实现。它们是:

1)深度卷积残差神经网络

输入:连接 4 板状态

输出:策略(可能移动的概率分布),值(O 胜:+1,X 胜:-1,*局:0)

2)蒙特卡罗树搜索(MCTS)

在迭代过程中,由来自神经网络的策略指导的自我游戏生成游戏数据集以训练神经网络

3)评估神经网络

玩家 vs 玩家,各自分别由当前网和先前网引导,保留赢得下一轮比赛的网

深度卷积残差神经网络

Neural network architecture of AlphaZero used here

我们使用具有类似于 AlphaZero 的上述架构的深度卷积残差神经网络(使用 PyTorch)来将输入 Connect4 板状态映射到其相关联的策略和值。策略本质上是玩家应该从当前棋盘状态(策略)移动的下一步棋的概率分布,值代表当前玩家从该棋盘状态中获胜的概率。这个神经网络是 MCTS 的一个组成部分,它通过其策略和值输出来帮助指导树搜索,我们将在后面看到。我们使用一个初始卷积块,接着是 19 个残差块,最后是一个输出块来构建这个神经网络(我称之为 ConnectNet ),如下所述。

卷积块

残留块

输出块

放在一起

在输入到神经网络之前,原始的 Connect4 板被编码成 6×7×3 的 1 和 0 的矩阵,其中 6×7 的板尺寸中的每一个的 3 个通道分别编码“X”、“O”(1 存在,0 为空)和要移动的玩家(0 为“O”,1 为“X”)。

Encoder to encode Connect4 board for neural net input

最后,为了正确地训练这个具有双头输出的神经网络,自定义损失函数(AlphaLoss)被定义为简单的均方误差值和交叉熵策略损失之和。

Neural Net loss function implemented via PyTorch

蒙特卡罗树搜索

一个游戏可以被描述为一棵树,树根是棋盘状态,树枝是所有可能的棋盘状态。在像围棋这样的游戏中,随着游戏的进行,分支的数量呈指数增长,简单地用蛮力评估所有分支实际上是不可能的。因此,蒙特卡罗树搜索(MCTS)算法被设计成以更智能和更有效的方式进行搜索。从本质上讲,人们希望优化探索-开发的权衡,人们希望进行足够彻底的搜索(探索)以发现可能的最佳回报(开发)。这在定义置信上限(UCB)的 MCTS 算法中的一个等式中被简洁地描述:

这里, Q 是*均行动值(*均报酬), cpuct 是确定探索水*的常数(设为 1),P(s =状态,a =行动)是神经网络的策略输出给出的选择行动 a 的先验概率, N(s,a) 是行动 a 所对应的分支被访问的次数。来自状态 s 的所有被探索分支(动作)的分子 sum 中的 N sum over b 本质上是 (s,a) 的父级被访问的次数。

MCTS 算法按以下步骤进行。

  1. 挑选

Select — AlphaGo Zero

Recursively selects the nodes based on highest UCB (best move) until leaf node or terminal node is reached. Adds node of best move if its not yet created.

s 开始,搜索选择具有最高 UCB 的下一个分支,直到到达叶节点(其分支都没有被探索的状态)或终端节点(结束游戏状态)。我们可以看到,如果奖励 Q 高,那么就更有可能选择那个分支。第二个探索项也起了很大的作用,其中我们看到如果动作 a 只被访问了几次,那么这个项将会很大,并且算法更有可能选择相关的分支。神经网络通过提供先验概率 P 来指导选择,当神经网络未被训练时,先验概率最初将是随机的。

2.展开并评估

Expand and Evaluate — AlphaGo Zero

Expand only nodes that result from legal moves, mask illegal moves and add Dirichlet noise to prior probabilities of root node.

这里,通过用神经网络评估与扩展节点相关联的状态来扩展叶节点,以获得并存储 P 。当然,非法移动不应该扩大,将被掩盖(通过设置先验概率为零)。如果该节点是根节点,我们还将在这里添加狄利克雷噪声,以向探索提供随机性,使得每个 MCTS 模拟都可能不同。

3.支持

Backup — AlphaGo Zero

Recursively update the visits counts and values of nodes once leaf node is evaluated.

现在,神经网络对叶节点进行评估,以确定其值 v 。这个值 v 然后被用于更新它上面的所有父节点的*均值 v 。更新应该是这样的,即 O 和 X 将发挥到最好(最小最大),例如,如果 O 赢了(对叶节点评估的 v = +1),则在该叶节点的直接父节点中,将轮到 O 出牌,并且我们将为该父节点更新 v = +1,然后为所有其他父节点更新 v = -1,其中 X 将出牌,以表示该动作对 X 不利。最后,在*局的情况下,更新 v = 0。

Code snippet for each simulation of Select, Expand and Evaluate, and Backup. num_reads here is the parameter controlling the number of simulations.

上述选择、扩展、评估和备份的过程代表了 MCTS 算法的每个根节点的一个搜索路径或模拟。在 AlphaGo Zero 中,进行了 1600 次这样的模拟。对于我们的 Connect4 实现,我们只运行 777,因为它是一个简单得多的游戏。在对该根节点运行 777 次模拟之后,我们将为根节点制定策略 p ,该策略被定义为与其直接子节点的访问次数成比例。这个策略 p 然后将被用于选择下一个移动到下一个棋盘状态,并且这个棋盘状态然后将被视为下一个 MCTS 模拟的根节点,以此类推,直到当有人赢或*局时游戏终止。对每个根节点运行 MCTS 模拟直到游戏结束的整个过程被称为 MCTS 自玩。

Function to execute MCTS self-play

在运行 MCTS 模拟的 MCTS 自玩游戏的每个步骤中,我们将有一个棋盘状态 s ,它的关联策略 p ,以及值 v ,因此当 MCTS 自玩游戏结束时,我们将有一组( s,p,v )值。然后,这组( s,p,v )值将用于训练神经网络,以改进其策略和值预测,然后,这个训练的神经网络将用于迭代地指导随后的 MCTS。通过这种方式,人们可以看到,最终在许多许多次迭代之后,神经网络和 MCTS 一起将非常善于生成最优移动。

评估神经网络

在一次迭代之后,其中使用 MCTS 自播放数据训练神经网络,然后再次使用由相应神经网络引导的 MCTS,将该训练的神经网络与其先前版本进行比较。表现更好的神经网络(例如赢得大多数游戏)将用于下一次迭代。这确保了网络总是在改进。

迭代流水线

总之,一个完整的迭代管道包括:

1.自我游戏使用 MCTS 生成游戏数据集( spv ),神经网络通过提供选择动作的先验概率来指导搜索

2.用 MCTS 自弹自唱产生的( spv )数据集训练神经网络

3.通过将经过训练的神经网络与来自前一次迭代的神经网络进行比较来评估经过训练的神经网络(在预定义的历元检查点),再次使用由相应神经网络引导的 MCTS,并且仅保留表现更好的神经网络。

4.冲洗并重复

结果

迭代 0:

alpha_net_0(用随机权重初始化)

151 游戏 MCTS 自玩生成

迭代 1:

alpha_net_1(从迭代 0 开始训练)

148 游戏 MCTS 自玩生成

迭代 2:

alpha_net_2(从迭代 1 开始训练)

310 游戏的 MCTS 自我发挥产生

评估 1:

阿尔法 _ 网络 _2 与阿尔法 _ 网络 _0 竞争

在 100 场比赛中,alpha_net_2 赢了 83 场,输了 17 场

迭代 3:

alpha_net_3(从迭代 2 开始训练)

584 游戏 MCTS 自玩生成

迭代 4:

alpha_net_4(从迭代 3 开始训练)

753 游戏 MCTS 自玩生成

迭代 5:

alpha_net_5(从迭代 4 开始训练)

1286 年 MCTS 自弹自唱游戏产生

迭代 6:

alpha_net_6(从迭代 5 开始训练)

1670 年 MCTS 自弹自唱游戏产生

评价 2:

阿尔法 _ 网络 _6 与阿尔法 _ 网络 _3 竞争

在 100 场比赛中,alpha_net_6 赢了 92 场,输了 8 场。

Typical Loss vs Epoch for neural net training at each iteration.

在 Google Colab 上几周的零星训练期间,总共生成了 4902 个 MCTS 自玩游戏的总共 6 次迭代。上面显示了每次迭代的神经网络训练的典型损失对时期,表明训练进行得相当好。从迭代中选定点处的评估 1 和 2 中,我们可以看到神经网络确实总是在改进,并且在生成获胜移动方面变得比其先前版本更强。

现在可能是展示一些真实游戏的时候了!下面的 gif 展示了 alpha_net_6(以 X 的身份玩)和 alpha_net_3(以 O 的身份玩)之间的一个示例游戏,其中 X 赢了。

此时此刻,我还在训练网/MCTS 自弹自唱。我希望能够达到一个阶段,使 MCTS +网络能够产生完美的移动(连接 4 是一个解决的游戏,这样首先移动的玩家总是可以迫使获胜),但谁知道这将需要多少次迭代…

反正都是乡亲们!希望你会觉得这篇文章有趣和有用。非常欢迎对实现和改进提出任何意见。要进一步阅读 AlphaZero 如何工作的更多细节,没有什么比阅读 DeepMind 的实际论文更好的了,我强烈推荐!

要了解最新的人工智能/数据科学趋势、论文和新闻,请查看我的@ follow AI _ bot(https://t.me/followai_bot),这是您的个性化人工智能/数据科学电报机器人。

从零开始:生活的游戏

原文:https://towardsdatascience.com/from-scratch-the-game-of-life-161430453ee3?source=collection_archive---------4-----------------------

Source: Domino Art Work

大家好,欢迎来到“从头开始”系列的第二篇文章。(上一篇:从无到有:贝叶斯推理,马尔可夫链蒙特卡罗和 Metropolis Hastings,在 python 中)

在这篇文章中,我们解释并提供了“生活的游戏”的实现。我说“我们”是因为这次我的朋友兼同事 Michel Haber 也加入了进来。我们的两个 GitHub 配置文件中都提供了代码: Joseph94m , Michel-Haber 。

第一部分将着重于给出游戏规则的解释以及如何玩/定义游戏的例子。第二部分将提供《生命的游戏》的 Python 和 Haskell 实现细节。在第三部分,我们比较了我们的实现的性能和优雅性。我们选择这两种语言是因为它们代表了两种最常用的编程范式,命令式(Python)和函数式(Haskell),并且因为它们在编写表达性和可理解的代码方面相对容易。

1-生活游戏简介

《生命的游戏》是约翰·h·康威在 20 世纪 70 年代设想的一种细胞自动机,可能是所有细胞自动机中最著名的。尽管规则非常简单,但生命的游戏是图灵完全确定的。

生活的游戏是数学意义上的游戏,而不是可玩的游戏。是“零玩家游戏”。

游戏发生在二维有限或无限网格上,网格的细胞可以采取两种截然不同的状态:“活着”或“死了”。

在每个阶段,单元的演化完全由其当前状态及其八个邻居的状态决定,如下所示:

1)恰好具有三个活邻居的死细胞变得活了。
2)具有两个或三个活邻居的活细胞仍然活着。
3)在所有其他情况下,细胞变得(或保持)死亡。

让我们假设一个简单的初始状态,其中只有 3 个细胞是活的:左细胞、中间细胞和右细胞

从图 1 中的简单配置开始,让模拟运行一次迭代,结果如图 2 所示。

那么这是怎么发生的呢?

Figure 2

左边和右边的细胞只有一个邻居,中间的细胞,因此它们死亡。中间的细胞有左右两个邻居,所以它还活着。顶部和底部细胞有 3 个邻居(中间,右边和左边),所以他们变得活跃。值得注意的是,细胞在迭代结束前不会死亡或存活。即算法决定哪些细胞将死亡或复活,然后一起给它们消息。这确保了单元格的求值顺序无关紧要。

再运行一次迭代就会得到图 1 所示的状态(初始状态)。

因此,从这个配置开始,游戏进入图 3 所示的无限循环。这种配置被称为闪光灯。

Figure 3: Blinker

Figure 4: An early state from figure 5 that shows some interesting structures.

现在用一个更有趣的场景来展示给康威印象最深的是什么。从图 5 左图中的简单配置开始,让代码运行,电路板演变成完全意想不到的东西。我们可以观察到稳定的结构:街区蜂巢。我们还可以观察到环形结构,例如图 3 中的眼罩以及由 3 或 4 个较小眼罩组成的较大眼罩。在这个模拟中观察到的另一个有趣的结构是滑翔机。一架 滑翔机 看起来像一架老式电子游戏飞船。它不受空间的限制,继续前进。

Figure 5. Left: Initial state. Right: Evolution

2-编码生活的游戏

我们用两种语言实现这个游戏,Python 和 Haskell。我们用这两种语言实现游戏的主要目的,是比较它们在速度和代码优雅性方面的表现。

2.1-在 Python 中

在图 6 中,我们定义了游戏类。它由一套规则、一个初始状态和一个最大尺寸(宽度和高度)组成。通过调用 run_game 函数并指定最大迭代次数来启动游戏。

Figure 6: Game Class

有两种可能的方式来表示状态:

一种密集表示,其中所有单元格都编码在一个宽*高矩阵中。死细胞用 0(或假)表示,活细胞用 1(或真)表示。网格上单元的位置由其在矩阵中的位置定义。

只有活细胞被编码的稀疏表示。每个活细胞由它在网格上的位置(int,int)表示。所有这些活细胞都聚集在一个字典结构中。

在我们的例子中,稀疏表示具有优势,因为它需要更少的内存(因为大多数细胞都是死的),并且允许我们只遍历活细胞集(因为死细胞对它们的邻居没有直接影响)。

无论如何,我们实现了这两种表示,以便提供一个性能基线。然而,为了避免冗余,我们在本文中只展示了稀疏表示的实现。

图 7 显示了稀疏表示的实现。它由一个属性组成,即网格,它记录了活细胞在集合中的位置。

Figure 7: State Class

图 8 显示了游戏的规则。在状态的网格上应用规则会返回带有更新的死单元和活单元的网格。

Figure 8: Sparse Rule class

图 9 示出了如何用图 5 的配置运行游戏的例子。

Figure 9: Example how to run the game

Figure 10: The fabulous blaster canon

2.2 英寸哈斯克尔

在图 11 中,我们展示了 Haskell 实现的类型定义。我们只实现了稀疏变体。我们利用 newtype 包装器来封装我们的主要类型。棋盘或网格只是活细胞坐标的列表。 TallyState 是一种状态 Monad 包含我们在其中计数细胞的活邻居的图。

最后, Rulesneighbors类型分别表示返回一个单元格的命运及其邻居列表的函数。

Figure 11: Type defiitions

在图 12 中,我们展示了游戏的一组函数。高级功能将规则应用于当前状态,并返回新状态。

Figure 12: The simulation functions

最后,在图 13 中,我们实现了我们的主函数和标准规则。

Figure 13: Main

3-比较

如前所述,我们想要比较不同表示的速度和优雅程度。

3.1-不同设置、电路板尺寸和初始配置的处理时间。

对于 80x80 的板尺寸,迭代 1500 次,初始配置为(39,40),(39,41),(40,39),(40,40),(41,40)。结果如图 14 所示。相应的计算时间为:

Python,密集:150 秒

Python,稀疏:1.03 秒

Haskell,稀疏:0.475 秒(使用-O3)

Figure 14.

在我们的第二次测试中,我们使用了 200x200 的电路板,并从以下初始配置开始运行 2000 次迭代模拟:

(50180)、(51180)、(50181)、(51181)、(60180)、(60179)、(60181)、(61178)、(62177)、(63177)、(61182)、(62183)、(63183)、(65182)、(66181)、(66180)、(66179)、(65

这导致了我们在图 15 中看到的结果,相应的计算时间是:

Python,密:1456 秒~ 24 分钟

Python,稀疏:1.54 秒

Haskell,稀疏:0.802 秒(使用-O3)

Figure 15.

从这两个测试来看,很明显 Python 中的密集表示比 Haskell 和 Python 中的稀疏表示要慢得多。这种行为是意料之中的,因为密集表示(a)单独处理单元,(b)试图评估死单元对附*单元的影响,即使已知死单元不会影响附*单元的未来状态,以及(c)使用更多的存储器,因为它存储所有单元的状态——这可能不会对这两个测试的速度产生直接影响,因为板的尺寸不是很大, 但是如果程序不能再在内存中容纳主板,那么它必须进行磁盘交换,这将进一步增加完成运行所需的时间。

在提供的两种稀疏表示中,Haskell 表示在计算时间上有显著的改进。

3.2-编程优雅

评估实现的优雅程度是一项相当主观的任务。相反,我们建议显示两种实现的一些指标:有效的代码行、函数的数量和显式条件语句的数量。

因此,代码优雅在很大程度上依赖于个人喜好,我们因此将决定权留给读者;)

有效代码行数:

密集 Python 表示:~75

稀疏 Python 表示:~70

稀疏 Haskell 表示:~40

功能数量:

密集 Python 表示:6

稀疏 Python 表示:6

稀疏哈斯克尔表示:7

显式条件语句的数量:

密集 Python 表示:13

稀疏 Python 表示:11

稀疏 Haskell 表示形式:0

4-结论

最后一个模拟,我们显然没有做:)。模拟人生游戏的人生游戏。

https://www.youtube.com/watch?v=xP5-iIeKXE8

A game of life, within a game of life.

有趣的是,看到如此复杂的系统可以从这样的基本规则和配置中出现——这让我们想起了现实世界,在现实世界中,基本单元聚集在一起,产生更加复杂的结构,如生命。

关于我们的两个普通(ish)实现,Haskell 实现在速度(和优雅性)上优于 Python 实现。).也就是说,人们可以想象其他一些 Python 和 Haskell 实现会带来更好的性能和代码优雅性。

最后,感谢您的阅读,不要忘记亲自尝试代码!

从零开始到搜索:设置 Elasticsearch 不到 4 分钟,用 Python 加载 CSV 并阅读更多相关内容

原文:https://towardsdatascience.com/from-scratch-to-search-setup-elasticsearch-under-4-minutes-load-a-csv-with-python-and-read-e31405d244f1?source=collection_archive---------6-----------------------

Photo by Kym Ellis on Unsplash

实用技术介绍(针对数据科学、日志记录和监控、全文搜索等。)

准备,稳定,开始…

这篇文章的主要目的是提供一个简短的指导,告诉你如何最初设置你的第一个 Elasticsearch“开发”环境,以便快速开始探索/利用该技术提供的东西。简介将围绕 Elasticsearch 提供的最重要的 API 展开,这些 API 是获取数据和执行数据查询的基础。第二个目的是提供文档和其他有趣资源的链接,以了解其他潜在的操作方面、附加的酷功能和各种工具(通常是我在使用 Elasticsearch 时发现有用的东西)。我已经错过了这种“进一步的指针介绍”,所以这是任何人都一样的尝试:)。这些环节将在每章专门的 接下来的 章节中进行总结。

目标受众可能是个人数据分析师或 web 开发人员,最终是有相关数据用例并听说过 Elasticsearch 的小型预算团队。不打算提供技术的全面技术概述(集群、节点、分片、副本、Lucene、倒排索引等)。)或者深入探讨某个特定主题,因为有许多关于这方面的好资源……其中一些将在文章中或在下一步是什么部分中链接。

Elasticsearch is… (source: Elastic https://www.youtube.com/watch?v=aLHH0eRciNE)

弹性搜索用例

如果你只是想知道 Elasticsearch 如何对你的目的有用,那么通常有三个主要领域(以及其他领域)可以被 Elastic Stack 有效支持

  • “大数据”分析&特定的数据科学任务,这些任务可能围绕大型半结构化数据(文本和 json 对象)展开,需要高度可用的存储和快速全文搜索功能。有趣的情况可以在 NLP 区域中找到,或者在处理大量基于地理的数据时需要执行地理位置查询和可视化。如果您需要一个现成的探索/仪表板工具来处理一些更复杂的业务分析查询,它也能带来价值。
  • 时序处理、存储和浏览与处理进入的时间戳数据流相关。这些可以包括 Elastic 的电源区域来自大量运行服务的日志处理,或者从健康和正常运行时间的角度对其进行监控,并且还可以处理可以被摄取到 Elasticsearch 中的任何传感器数据等。
  • 对任何大型文本数据(网站、企业资料、文档档案等)进行全文搜索。)使其内容可用于复杂的文本查询。这些可以(通过正确的设置)在几十毫秒内返回,从而高度支持用户体验和钻取相关信息的能力。也可以找到灵感,例如与其他技术如 OCR 结合使用。

我们将如何做

在我看来,开始试验 Elasticsearch(和许多其他软件技术)最简单的方法是通过 Docker,因此示例将利用这种方法。一般来说,集装箱化(已经有一段时间)也接管了实际生产部署/运营,因此这是二合一的好处。优步展示了这方面的大规模实例,展示了他们采用数百个弹性集群的完全集装箱化方法。所以让我们开始吧…

1.设置您的开发环境

我假设你已经熟悉 Docker 了(如果还不熟悉的话…安装 Docker for Desktop forMac、 Windows 或 Linux 发行版,阅读一些介绍的材料,你就可以开始了)。注意:例子是在 macOS Mojave 上测试的,记住在 Linux 发行版或 Win 上可能有一些 Docker 细节。

我们的第一个节点

当您准备好 docker 环境后,只需打开您的终端,使用以下命令启动 Elasticsearch 集群:

docker network create elastic-network

这将为我们未来的集装箱创造一个基本的通信“空间”。

现在,如果您只想进行单节点部署,只需运行:

docker run --rm --name esn01 -p 9200:9200 -v esdata01:/usr/share/elasticsearch/data --network elastic-network -e "node.name=esn01" -e "cluster.name=stanislavs-docker-cluster" -e "cluster.initial_master_nodes=esn01" -e "bootstrap.memory_lock=true" --ulimit memlock=-1:-1 -e ES_JAVA_OPTS="-Xms2g -Xmx2g" docker.elastic.co/elasticsearch/elasticsearch:7.3.0

等待几秒钟,在您的日志中,您应该会发现来自 Elasticsearch 集群的确认设置成功的消息:

{“type”: “server”, “timestamp”: “2019–08–18T13:40:18,575+0000”, “level”: “INFO”, “component”: “o.e.n.Node”, “cluster.name”: “stanislavs-docker-cluster”, “node.name”: “esn01”, “cluster.uuid”: “ilHqkY4UQuSRYnE5hFbhBg”, “node.id”: “KKnVMTDwQR6tinaGW_8kKg”, “message”: “started” }

万岁…我们已经启动了第一个运行在 Docker 容器(同名)中的 Elasticsearch 节点(esn01),监听端口 9201 (docker -p 参数)。由于cluster . initial _ master _ nodes,它在被称为集群引导的过程中形成了一个新的集群(其名称在 cluster.name 中给出),并立即选举自己为该集群的主集群(当你独自一人时还能做什么:)。最后值得一提的是 -v 参数,它创建了新的 Docker 卷 esdata01,并将其绑定到正在运行的 Elasticsearch 的数据目录中——这样在重启后我们的工作数据将被保留。其余参数更多地与“系统”相关(属于重要系统设置 ) —我们使用 bootstrap.memory_lock 禁用交换,使用 ulimit memlock 增加文件/进程限制,使用 ES_JAVA_OPTS 分配初始/最大堆大小(即专用内存,以便根据您的配置进行调整…但请记住,Elasticsearch 还利用堆外内存,因此不要设置超过可用内存的 50%许可说明:默认情况下使用基本许可运行,但是如果你想使用纯粹的开源风格,只需在镜像名称的末尾添加*-oss。

其他两个节点(可选)

现在,如果您想尝试分布式设置的味道,请向您的集群添加两个(或更多)其他节点。本教程的其余部分(在本地机器上运行:)甚至实际的基本操作都不需要它。然而,由于处理的分布实际上是 Elasticsearch 的核心增值功能之一(因为索引部分主要由 Apache Lucene 库负责),了解这一点至少是有好处的。因此,如果您想…这里是我们的另外两个节点(在单独的终端中运行):

docker run --rm --name esn02 -p 9202:9200 -v esdata02:/usr/share/elasticsearch/data --network elastic-network -e "node.name=esn02" -e "cluster.name=stanislavs-docker-cluster" -e "discovery.seed_hosts=esn01" -e "bootstrap.memory_lock=true" --ulimit memlock=-1:-1 -e ES_JAVA_OPTS="-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:7.3.0docker run --rm --name esn03 -p 9203:9200 -v esdata03:/usr/share/elasticsearch/data --network elastic-network -e "node.name=esn03" -e "cluster.name=stanislavs-docker-cluster" -e "discovery.seed_hosts=esn01,esn02" -e "bootstrap.memory_lock=true" --ulimit memlock=-1:-1 -e ES_JAVA_OPTS="-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:7.3.0

现在,随着节点加入我们的集群,事情开始变得更有趣了。您可以在日志中观察这个过程,日志中有关于添加的消息(下面来自我们集群的主节点,关于新添加的节点 esn02)。通常,节点加入集群时会联系在 discovery.seed_hosts 参数中列出的其他“已经存在”的节点(以获得关于集群设置的最新信息),该参数(与前面提到的cluster . initial _ master _ nodes一起)属于重要发现设置。集群中节点之间的所有通信都直接在传输层上执行(即没有 HTTP 开销),这就是为什么有端口 9300(而不是我们为与集群进行“外部”通信而公开的端口 920x)。

{“type”: “server”, “timestamp”: “2019–08–18T13:40:28,169+0000”, “level”: “INFO”, “component”: “o.e.c.s.ClusterApplierService”, “cluster.name”: “stanislavs-docker-cluster”, “node.name”: “esn01”, “cluster.uuid”: “ilHqkY4UQuSRYnE5hFbhBg”, “node.id”: “KKnVMTDwQR6tinaGW_8kKg”, “message”: “added {{esn02}{4xOwc-_fQDO_lwTlpPks2A}{FW-6YGVSSsmgEt3Mo_GY_Q}{172.18.0.3}{172.18.0.3:9300}{dim}{ml.machine_memory=8360488960, ml.max_open_jobs=20, xpack.installed=true},}, term: 1, version: 16, reason: Publication{term=1, version=16}” }

关于我们集群的信息

一切都已启动并运行,因此我们可以检查关于我们的 Elasticsearch 集群的一些事情(注意,我们可以联系我们集群中的任何节点,因为通常任何节点都可以成为协调节点,通过分散-收集方法)来处理传入的请求:

联系节点的基本信息:

curl localhost:9200

退货:

{
    "name" : "esn01",
    "cluster_name" : "stanislavs-docker-cluster",
    "cluster_uuid" : "ilHqkY4UQuSRYnE5hFbhBg",
    "version" : {
        "number" : "7.3.0",
        "build_flavor" : "default",
        "build_type" : "docker",
        "build_hash" : "de777fa",
        "build_date" : "2019–07–24T18:30:11.767338Z",
        "build_snapshot" : false,
        "lucene_version" : "8.1.0",
        "minimum_wire_compatibility_version" : "6.8.0",
        "minimum_index_compatibility_version" : "6.0.0-beta1"
    },
    "tagline" : "You Know, for Search"
}

关于集群状态的基本信息:

curl localhost:9202/_cluster/health?pretty

退货:

{
    "cluster_name" : "stanislavs-docker-cluster",
    "status" : "green",
    "timed_out" : false,
    "number_of_nodes" : 3,
    "number_of_data_nodes" : 3,
    "active_primary_shards" : 0,
    "active_shards" : 0,
    "relocating_shards" : 0,
    "initializing_shards" : 0,
    "unassigned_shards" : 0,
    "delayed_unassigned_shards" : 0,
    "number_of_pending_tasks" : 0,
    "number_of_in_flight_fetch" : 0,
    "task_max_waiting_in_queue_millis" : 0,
    "active_shards_percent_as_number" : 100.0
}

有关群集中节点的更多信息:

curl localhost:9203/_cat/nodes?v

退货:

ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.19.0.2 26 56 3 0.01 0.16 0.17 dim * esn01
172.19.0.4 13 56 1 0.01 0.16 0.17 dim — esn03
172.19.0.3 20 56 2 0.01 0.16 0.17 dim — esn02

最后一个回答可能是最有趣的(因为上面基本上说我们有一个空的集群:)。我们可以看到集群中的所有三个节点(ESN 01–03)。从 node.role 中我们可以看到,所有的节点都属于类型 mdi,这意味着它们是符合主节点条件的(如果当前主节点“发生故障”,它们可以被选为主节点)、数据(保存实际数据 ie 碎片,可以执行 CRUD/搜索操作)和摄取(可以设置特殊的摄取管道,以便在实际索引之前预处理 ie 转换/丰富传入数据)。我们也可以看到我们现在的主人(标有*)。

下一步怎么样

  • 部署:与您的开发人员一起考虑在您的集成/生产环境中运行的最佳选项,选项包括:在您的服务器上进行标准本地安装,托管服务解决方案弹性云或 AWS 弹性搜索等。或者是前面提到的“中间选择”,将 docker/OCI 映像部署到某个容器化*台( Kubernetes 、 OpenShift 、Swarm)中,再次在本地或云中运行
  • 配置:基本配置资源是 elasticsearch.yml 文件(位于 config 目录中),该文件存在于任何 elasticsearch 实例中——在重要设置中阅读关于该文件(以及其他关键参数)的更多信息
  • 保安:先……!你可以选择原生的 ES 安全选项或者更复杂的安全插件( SearchGuard , Open Distro Security )。至少要有 TLS 和基于角色的 auth!
  • 集群:分布式容错能力很强……不,如果你想更深入地了解集群概念,请阅读一些关于不同节点类型的内容,如符合主节点条件的节点/数据/摄取/ML ,并深入了解发现模块和进程(即了解为什么集群中应该有三个或更多符合主节点条件的节点)
  • 规模估算:阅读关于规模估算和容量规划的更多信息
  • DOCKER :关于 Docker 设置、卷、网络的更多信息,或者如果您正在处理特定的 Elasticsearch 版本,您可以获得匹配的图像
  • 弹性搜索的测井:改变特定层级的测井配置(基于 log4j)等。设置时很有用
  • 许可:检查某些特定的期望特性属于哪种特定的许可模式是很好的(在本文中,我尝试使用 Apache 2.0 下的纯操作系统或基本许可的东西进行测试)
  • API:elastic search 提供了一份关于他们所有REST API的很好的文档,所以来看看吧
  • API:如果你喜欢带有集群信息的 cat API(比如我),你会知道还有更多覆盖节点、分片、索引、健康、段等。等等。

TECHNOLOGY: Read also more on the key constituting technology components and concepts of Elasticsearch (source elastic.co)

2.将您的数据发送到 Elasticsearch (CSV 示例)

当您设置好初始环境后,就该将我们的数据转移到正在运行的节点上,为搜索做好准备了。Elasticsearch 的基本原则是,放入其中的任何数据“单元”都称为文档。这些文件要求的格式是 JSON。这些文档不是单独存储的,而是被分组到称为索引的特定集合中。一个索引中的文档共享相似的特征(即数据类型映射、设置等)。),因此索引还充当所包含文档的管理层和 API 层。

索引创建

因此,让我们用Create-indexes API创建一个索引,并用Index-Document API将 ie 索引一个文档放入其中…

curl -X PUT \
  [http://localhost:9200/test-csv](http://localhost:9200/test-csv) \
  -H 'Content-Type: application/json' \
  -d '{
    "settings" : {
        "index" : {
            "number_of_shards" : 3, 
            "number_of_replicas" : 2 
        }
    }
}'

退货:

{“acknowledged”:true,”shards_acknowledged”:true,”index”:”test-csv”}

索引创建…已检查!我们已经创建了第一个名为 test-csv 的索引,并定义了一个重要的设置碎片和副本的数量。主碎片和碎片副本(用正确的术语来说)是一种将我们的索引(即文档集合)分割成多个部分从而确保冗余的方法。实际值取决于(在基本意义上)我们有多少个节点。碎片的数量(即我们的索引将被分成多少个单元)在索引创建时是固定的。副本的数量决定了主碎片(即我们 3 个中的每一个)将被“复制”多少次。我们定义了 2,因为我们想达到这样一种状态:在每个节点上,我们有一个主碎片(我们数据的⅓),但也有我们数据的其他⅔的副本,即完整的数据集。这种设置确保了如果我们丢失一个节点,我们不会丢失任何数据。提示:如果您不想让 starter 弄乱这些设置,您不必这样做,因为如果您试图在没有现有索引的情况下索引一个文档,它会自动创建(默认为 1 个碎片和 1 个副本)。

curl -X PUT \
  [http://localhost:9203/test-csv/_doc/1?pretty](http://localhost:9203/test-csv/_doc/1?pretty) \
  -H 'Content-Type: application/json' \
  -d '{
    "value": "first document"
}'

退货:

{
    "_index" : "test-csv",
    "_type" : "_doc",
    "_id" : "1",
    "_version" : 1,
    "result" : "created",
    "_shards" : {
        "total" : 3,
        "successful" : 3,
        "failed" : 0
    },
    "_seq_no" : 0,
    "_primary_term" : 1
}

文档索引…已检查!我们已经将我们的第一个文档索引到我们的 test-csv 索引中,所有的碎片都响应正确。我们已经索引了一个非常简单的只有一个字段的 json 文档,但是你基本上可以索引任何文档(从大小、深度等角度来看),只要它是有效的 JSON——但是尽量把它保持在 100MB 以下。现在,您可以使用 Get API 通过 id 轻松检索单个文档。我将把那件事留给你。

使用 Python 从 CSV 加载数据

显然你不想用 curl 一个接一个地索引你的文档。当您的应用程序、数据库或存储驱动器中可能已经有这些数据时,就越是如此。出于这些目的,各种编程语言如 Java、JS、Go、Python 等都有官方的 Elasticsearch 客户端。您可以基于您的技术栈获取其中的任何一个,并使用其 API 以编程方式执行索引/删除/更新/…操作。

但是,如果您只有数据,并希望快速获取它们,您有两个选择…我使用了 Python 客户端并准备了非常简单的 CLI 脚本,允许您从给定文件中索引数据——支持 CSV 格式和 NDJSON 格式(换行符分隔的 JSON ,这通常用于日志记录、流处理等。).把它作为一种解决你的数据“问题”的可能方法,并根据你的需要写一些更好的东西:)。您可以在客户端文档中浏览许多其他与 Elasticsearch APIs 匹配的方法和助手。无论如何不要忘记在使用脚本之前pip install elastic search(安装模块)。

本报告中免费提供的代码/脚本:

[## stanislavprihoda/load _ CSV _ or _ JSON _ to _ elastic search

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/stanislavprihoda/load_csv_or_json_to_elasticsearch/blob/master/load_csv_or_json_to_elasticsearch.py)

我不会描述整个代码内容(因为它总是可以写得更好:),但代码中有两个相关的部分:

1。它利用 Python 生成器的概念,逐行遍历给定文件,并为索引执行生成一个预处理元素/行。选择这种“基于元素”的操作是为了确保内存效率,以便能够处理更大的文件。

def _csv_generator(self, es_dataset, **kwargs):
    with open(es_dataset.input_file) as csv_file:
        csv_dict_reader = csv.DictReader(csv_file)
        for cnt, row in enumerate(csv_dict_reader):
            yield self._prepare_document_for_bulk(es_dataset, row, cnt)

2。另一方面,由于实际的索引操作有些昂贵,它利用批量 API 在多个文档块中建立索引(默认 500 个条目),这与针对速度的调整的建议一致。对于这个操作,它使用了 python elasticsearch 客户端提供的一个帮助器(这些帮助器是在原始 api 之上的便利抽象)—elastic search . helpers . streaming _ bulk。

for cnt, response in enumerate(streaming_bulk(self.client, generator, chunk_size)):
    ok, result = response

在执行之后,有必要使用 refresh API 来使文档立即可搜索。

self.client.indices.refresh(index=es_dataset.es_index_name)

从数据的角度来看,现在有很多选择来获得一些有趣的数据集( Kaggle 数据集、 AWS 数据集或其他开放数据集的精选列表),但是因为我们也想展示一些文本搜索功能,所以让我们在 NLP 领域的一些东西上测试/展示我们的脚本—这里可以找到很好的集合。例如,我们可以使用危险问题数据集,因为它不是一个常见的演示数据集。注意:如果您使用这个集合,也要考虑删除标题中的空格,以获得更简洁的列/字段名称。

运转

现在,我们可以在终端中运行下面的命令,并观察 stdout 日志(出于测试目的,我保留了调试级别):

python3 load_csv_or_json_to_elasticsearch.py _data/JEOPARDY_CSV.csv test-csv

最后,我们应该会收到以下消息:

2019–08–18 17:03:19,013 — load_csv_or_json_to_elasticsearch.py — INFO — Script execution FINALIZED in 44.15356087684631 seconds. Dataset from file _data/JEOPARDY_CSV.csv loaded to Elasticsearch at localhost:9200\. Number of documents processed: 216929.

执行花费了 44 秒,这并不算快,但是因为我们在一台机器上运行所有的东西,这是(必须:)可以接受的。实际上,相当一部分是 3+2 分片的成本,所以对于测试来说,如果只使用 1+0(和单个节点),我们将低于 25 秒。它可能会通过对块大小的自我优化管理得到进一步改善,正如 tune for speed documentation 中所建议的那样(即从 100 开始,然后逐渐增加,直到速度*稳),因此您可以将它作为一个有趣的练习来做。另一方面,如果我们一个接一个地索引文档,我们会达到漂亮的 1411 秒😃,所以看起来批量 api 有一些意义。

现在我们可以重新检查/_ cat/index?确保我们所有的数据都在适当的位置。

下一步怎么样

  • 索引映射/设置:用获取映射 API 检查索引的数据结构,用获取设置 API 检查索引设置——有各种设置选项。
  • 索引模板:对于在持续的基础上(即在某些时间段)创建相似索引的用例,使用预定义的结构是很方便的——这就是索引模板的情况
  • 索引更改:您可以使用 Reindex API 在索引之间移动数据(当您需要在分片中进行更改时非常有用——这在创建之后是不可能的),这可以与索引别名结合使用,后者允许创建一个“昵称”,我们可以将查询指向该别名(这个抽象层允许更自由地更改别名背后的索引)
  • 分析:当我们对查询进行索引或全文搜索时,请阅读更多关于分析器及其核心构建模块字符过滤器、记号赋予器和记号过滤器的信息,或者创建您的自定义分析器。
  • 客户端:各种编程语言的官方 Elasticsearch 客户端,如 Java、JS、Go、Python 等。
  • 数据接收:通常是基于时间的数据(如日志、监控等。)您可能会考虑使用来自 Elastic Stack 的其他工具,例如 Beats (多用途轻量级数据传送器)或/和 Logstash 在索引到 Elasticsearch 之前进行更复杂的数据预处理
  • 内存/存储:如果您发现自己的索引数据越来越多,而磁盘空间却越来越少,您可能会考虑索引生命周期管理,它允许根据定义的规则来更改或删除索引。或者/并且如果你的内存不足,你可以考虑索引冻结,这将把各种开销数据结构从堆中移出。或者干脆多买些磁盘空间和内存:)
  • 性能:调整索引速度或高效磁盘使用

INDEX OPERATIONS & ANALYSIS: read also more on how Analysis process works — it is the core capability for fulltext searching and runs everytime we index or query our data (image source elastic.co).

3.搜索

现在我们已经索引了我们的数据,我们终于可以搜索和浏览我们的数据。Elasticsearch 使用特定的基于 JSON 的语言查询 DSL(领域特定语言)来执行跨索引数据的各种复杂查询。由于在 Elasticsearch 的 Query DSL 世界中有许多选项,我们将只介绍几个,让您尝试其余的选项。

URI 搜索

不过,在 Elasticsearch 中搜索的最简单方法是不使用查询 DSL,只提供搜索到的字符串作为查询参数在 URI 搜索中,这对快速卷曲测试很有用,正如 Elastic 自己所说:)。所以让我们从这里开始,搜索包含术语印象主义的文件。

curl localhost:9200/test-csv/_search?q=question:impressionism

退货:

{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 3,
        "successful": 3,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 4,
            "relation": "eq"
        },
        "max_score": 13.689855,
        "hits": [
(…)
        {
            "_index": "test-csv",
            "_type": "_doc",
            "_id": "68959",
            "_score": 12.518969,
            "_source": {
                "show-number": "4943",
                "air-date": "2006–02–22",
                "round": "Double Jeopardy!",
                "category": "ART & ARTISTS",
                "value": "$1200",
                "question": "Impressionism got its name thanks to his painting \"Impression: Sunrise\"",
                "answer": "(Claude) Monet"
            }
        }
(…)

我们可以看到,对我们的 216k 文档的查询花费了 10ms,已经成功地遍历了所有 3 个碎片,并且找到了具有给定术语的 4 个文档。实际结果在 hits 数组中的 hits 对象下。对于我们收到的每个文档 ie 命中,以及 _source 字段中的实际内容,还有 _score 字段,这是一个相关性计算

多匹配查询

现在让我们使用查询 DSL 跨多个字段进行搜索。为此,我们将使用多匹配查询来实现这一点。正如在链接的文档中可以看到的,有各种选项来处理条件、相关性计算和其他参数。让我们继续这个话题,寻找克洛德·莫内。我们将把短语指定为类型,因为我们希望两者都匹配,否则 Elasticsearch 也将返回只匹配其中一个术语的文档(Claude,但没有 Monet)。

curl -X GET \
  [http://localhost:9203/test-csv/_search](http://localhost:9203/test-csv/_search) \
  -H 'Content-Type: application/json' \
  -d '{
  "query": {
    "multi_match" : {
      "query":    "Claude Monet", 
      "fields": [ "category", "question", "answer" ],
      "type": "phrase" 
    }
  }
}'

退货:

{
"took": 16,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 36,
            "relation": "eq"
        },
        "max_score": 22.763008,
        "hits": [
        {
            "_index": "test-csv",
            "_type": "_doc",
            "_id": "171125",
            "_score": 22.763008,
            "_source": {
                "show-number": "2918",
                "air-date": "1997–04–16",
                "round": "Jeopardy!",
                "category": "CROSSWORD CLUES \"I\"",
                "value": "$400",
                "question": "Claude Monet or Rich Little (13)",
                "answer": "Impressionist"
            }
        },
(…)

我们现在有 36 个点击,前 10 名在点击字段下返回。顺便说一句。第一个结果…我想知道克劳德会对他的同伴的印象说些什么:)。

布尔查询

对于第三个查询,让我们变得更复杂,以一种我们再次寻找克洛德·莫内(这是必须的)的方式组合以上两个搜索,但我们也重视更多的结果匹配也是术语印象主义(这是应该的)…必须/应该的东西可能对你来说看起来很奇怪,但因为我们将使用布尔查询进行我们的搜索,我们将完全使用这些术语。布尔查询是所谓的复合查询的缺省值,它允许组合多个叶查询(匹配某个字段的实际查询)或其他复合查询。

curl -X GET \
  [http://localhost:9202/test-csv/_search](http://localhost:9202/test-csv/_search) \
  -H 'Content-Type: application/json' \
  -d '{
  "query": {
    "bool" : {
      "must" : {
        "multi_match" : {
            "query":    "Claude Monet", 
            "fields": [ "category", "question", "answer" ],
            "type": "phrase" 
        }
      },
      "should" : { 
          "match" : { "question" : "impressionism" } 
      }
    }
  }
}'

退货:

{
    "took": 6,
    "timed_out": false,
    "_shards": {
        "total": 3,
        "successful": 3,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 36,
            "relation": "eq"
        },
        "max_score": 28.663502,
        "hits": [
        {
            "_index": "test-csv",
            "_type": "_doc",
            "_id": "68959",
            "_score": 28.663502,
            "_source": {
                "show-number": "4943",
                "air-date": "2006–02–22",
                "round": "Double Jeopardy!",
                "category": "ART & ARTISTS",
                "value": "$1200",
                "question": "Impressionism got its name thanks to his painting \"Impression: Sunrise\"",
                "answer": "(Claude) Monet"
            }
        },
        {
            "_index": "test-csv",
            "_type": "_doc",
            "_id": "171125",
            "_score": 22.763008,
            "_source": {
                "show-number": "2918",
                "air-date": "1997–04–16",
                "round": "Jeopardy!",
                "category": "CROSSWORD CLUES \"I\"",
                "value": "$400",
                "question": "Claude Monet or Rich Little (13)",
                "answer": "Impressionist"
            }
        },
(…)

我们可以看到,我们已经收到了原始结果的最高分,因为它是唯一一个与我们的所有术语精确匹配的结果。

Search operation in one picture (image source elastic.co)

下一步怎么样

  • 查询 DSL :勾选全文查询的所有选项
  • 查询上下文&过滤上下文 : 文档是否匹配我们的查询以及匹配程度如何
  • 叶查询&复合查询:使用叶查询寻找特定字段中的特定值,例如匹配、术语或范围查询,另一方面使用复合查询可以将其他复合或叶查询包装在一起
  • 聚合:您可以将您的结果聚合为不同类型的聚合结果,如桶、度量、矩阵、管道等,并有多种选择,而不是在“文档级”的基础上处理数据
  • 公共选项:参见各种选项,可以应用于所有的 REST APIs 或者专门应用于搜索查询体
  • 性能:调至最大搜索速度
  • 分数调整:您可以使用函数分数查询或脚本分数查询(允许自定义分数计算脚本)来调整相关性分数,或者检查其他调整选项(如 rank_feature)以使结果与您的案例更相关
  • 高亮显示&提示器:还有很多其他很酷的特性,比如自动完成/随键入搜索功能的完成提示器或者高亮显示将结果包装在 html 标签中以强调匹配的位置

4.享受 Kibana 带来的便利

到目前为止,我们一直在与我们的 Elasticsearch 集群直接互动。在第一章中,通过 python 客户端,但后来主要是用简单的终端 cURL 命令。cURL 非常适合快速测试和整理东西,但是当你想用绘图、过滤等方式进行一些数据探索时。或者需要一些工具来对集群和索引进行管理检查和更新,您可能希望选择一些更方便的基于 UI 的应用程序。这就是 Kibana 的真正含义,或者像 Elastic 所说的那样,是 Elasticsearch 的窗口。事不宜迟,让我们将它添加到我们的设置中,看看我们要做什么:

docker run --rm --link esn01:elasticsearch --name kibana --network elastic-network -p 5601:5601 docker.elastic.co/kibana/kibana:7.3.0

Kibana docker 的参数非常简单。我们基本上需要做两件事——将 Kibana 添加到我们的 docker 网络(使用 —网络)并将其与我们的 Elasticsearch 集群链接(例如,使用 —链接指向我们的 esn01 节点),我们还保留默认端口 5601 并选择相同的版本 7.3。因为我们正在运行我们的弹性搜索,所以为了兼容性目的必须这么做。注意:这些也可以用绑定挂载的 自定义 kibana.yml 或者通过 环境变量 覆盖。加载完成后,您的 Kibana 实例就可以在: http://localhost:5601 上运行了,所以不要浪费时间去查看它:)它会带你到你的家,你可以开始浏览基巴纳街区。

管理和索引模式

我们的目标是快速开始处理数据,因此我们将直接进入管理->索引模式,并选择创建我们的第一个索引模式。从 Kibana 使用的角度来看,索引模式可能是最重要的概念。它们代表了 Elasticsearch 索引上的逻辑结构,并告诉 Kibana 使用什么索引(和相关字段)。索引模式可以匹配单个索引的名称,也可以包含通配符()来匹配多个索引。因此,让我们创建 test-索引模式(这将匹配我们的 test-csv 索引)。

在下一步中,我们将选择一个时间戳字段,稍后将用于基于时间的过滤。这可以通过选择我不想使用时间过滤器来省略,但如果您的数据中有任何时间戳字段,我建议不要这样做,以便我们可以进行时间序列可视化。选择创建,我们就完成了。它会将您带到索引模式概述页面,在该页面中您有所有字段的列表(如果您添加了更多字段,可以在右上角刷新)。您可以更改单个字段的格式,也可以添加新的脚本(但出于性能目的,弹性建议在使用脚本字段之前,请熟悉 脚本字段 和聚合 中的 脚本)。)。

我们可以在 Kibana 管理应用中做其他种类的弹性搜索管理/配置工作。例如,我们可以在索引上使用信息/操作检查索引管理部分(例如,冻结、删除、合并等。)或为索引生命周期管理设置自动作业和规则(这将为我们完成)。最后一点,所有的 Kibana 设置都存储在的 Elasticsearch 中。基巴纳系统索引,由于我们的 docker 卷,这些将在重启后与我们的其他数据一起保留。

发现

当您想要浏览、查询和过滤您的数据时,可以选择 Discover 应用程序(左侧菜单中的第一个)。当您打开它时,您将看到我们创建的默认索引模式和各个数据点。

在这里,您可以:

  • 过滤所需的时间范围(记住我们的数据是从 1984 年到 2012 年)
  • 筛选出所需的字段或值(提示:使用字段或值旁边的放大镜符号)
  • 使用基巴纳查询语言对数据进行搜索,即类别:愚蠢的答案
  • 请参见基本字段统计
  • 查看您的单个文档数据,并在其上下文中列出其他文档(即从时间角度)

可视化和仪表板

当您需要直观地展示您的数据发现或提供您正在处理的领域的交互式性能/状态/指标/KIPs 概述时,Kibana 也很有用。出于这些目的,您可以在 Kibana Visualize 应用程序中创建可视化效果,并在丰富的仪表板上对这些可视化效果进行分组,这些仪表板还可以提供解释性降价等。所有这些都建立在您的索引数据之上,并允许实时进行进一步过滤和定制视图,例如特定时间范围的视图。

由于我们的 showcase 数据集本质上并不是真正的数值型数据集,因此我们无法真正利用所有选项,但让我们至少创建几个文档计数可视化,并将它们放在一个仪表板上,以了解它的意义。因此,让我们转到 Visualize 应用程序(左侧第二个)并选择“创建新的可视化”。

让我们按年份对文件(我们资料中的问题)进行统计。选择一个竖线,并选择我们的 test-*索引模式,数据将通过该模式提取。然后,让我们添加到带有日期直方图聚合的时段和 X 轴时段,选择我们的日期字段并选择一个年度间隔。可选地,您可以放下部分存储桶,在右上角您应该会看到“播放箭头”按钮,该按钮会将定义的设置应用到我们的可视化中。然后…你完成了。

要将其放在仪表板上,请转到仪表板应用程序(如下 Visualize)并创建新仪表板。在顶部菜单中,您有一个添加选项,因此使用它来添加一个可视化面板。然后…你完成了。现在你可以尝试其中的几个,我相信你可以做得比我用我的简单仪表板更好。

下一步怎么样

  • 配置:在某个时候你会发现需要改变其他基巴纳配置这里链接的是选项的概述
  • 安全性:查看第一个下一个部分并检查链接的资源,因为这些资源显然必须也适用于基巴纳(通常基巴纳也有等效的插件或原生功能)
  • 可视化:在可视化应用程序中创建一个可视化,用交互式仪表盘将多个可视化放在一起,或者用画布共享更多可视化定制报告,如果你有 GeoJSON 数据,将它放在地图上
  • 空格:使用空格分隔出不同的数据区/域等。
  • 监控:Stack MONITORING app非常有用,尤其是在处理大量 Stack 工具实例时(部署了大量服务器,集群中有多个节点等)。)
  • 其他 KIBANA 应用:根据您的堆栈设置有很多,例如正常运行时间与心跳一起用于端点监控
  • 开发工具:当喜欢 Kibana UI 但仍然想执行一些基于请求的东西时,使用开发工具
  • CSV 文件加载:您可以通过仍然相当新的 Kibana 工具(仍然具有实验性状态)文件数据可视化器执行相同的 CSV/NDJSON 摄取(我们已经用 Python 脚本完成了),它允许索引数据高达 100 MB——非常适合快速数据检查。
  • 样本数据:如果你只是想玩 Kibana,使用提供的样本数据

5.奖励——对于集群爱好者

如果没有看到主选举,这将不是一个完整的(分布式)图片。您可以在 Docker 中轻松地使用这些内容,但记得在之后将所有内容备份:)。我们检查谁是当前的主节点(例如 /_cat/nodes 记住),要杀死它,我们可以运行:

docker stop esn01

这将立即在我们的集群中导致一个异常,并启动一个主选举。除了一个明显的例外(与主服务器的连接失败有关),您可以在日志中看到,两个节点都成为了主服务器的候选节点(正如我们已经知道的,两个节点都符合主服务器的条件),并且通过两个候选节点执行选举。所有事情都发生在 200 毫秒之内(对于真实生活场景,还会增加一些网络开销等。).

{“type”: “server”, “timestamp”: “2019–08–18T18:31:15,485+0000”, “level”: “INFO”, “component”: “o.e.c.s.ClusterApplierService”, “cluster.name”: “stanislavs-docker-cluster”, “node.name”: “esn02”, “cluster.uuid”: “w16btQPhSQ-iE96DSM6PnQ”, “node.id”: “yPAolS5gTxes0mcltF5WvA”, “message”: “master node changed {previous [{esn01}{EHEDowSVRMenU2BaVM442g}{thFwnNprQs-QwOx75KUbUg}{172.18.0.2}{172.18.0.2:9300}], current []}, term: 1, version: 5, reason: becoming candidate: onLeaderFailure” }(...){“type”: “server”, “timestamp”: “2019–08–18T18:31:15,626+0000”, “level”: “INFO”, “component”: “o.e.c.s.MasterService”, “cluster.name”: “stanislavs-docker-cluster”, “node.name”: “esn03”, “cluster.uuid”: “w16btQPhSQ-iE96DSM6PnQ”, “node.id”: “rLAI506ATr6lvqw-aiKgHg”, “message”: “elected-as-master ([2] nodes joined)[{esn03}{rLAI506ATr6lvqw-aiKgHg}{pf-3B_9GTGayL4KzmGkqIQ}{172.18.0.4}{172.18.0.4:9300} elect leader, {esn02}{yPAolS5gTxes0mcltF5WvA}{kadMA9eFTO2WR4v0t4aXzQ}{172.18.0.3}{172.18.0.3:9300} elect leader, _BECOME_MASTER_TASK_, _FINISH_ELECTION_], term: 2, version: 6, reason: master node changed {previous [], current [{esn03}{rLAI506ATr6lvqw-aiKgHg}{pf-3B_9GTGayL4KzmGkqIQ}{172.18.0.4}{172.18.0.4:9300}]}” }

事后你可以请求/_ 猫/节点?再次 v 看谁是新老板。完成后,您可以使用docker system prune-volumes清除未使用的容器、卷、网络等,重新开始。

结束

就这样…我们通过 Elasticsearch 完成了一个简单的“端到端”流程,从 Docker 设置开始,获取集群中的数据并执行基本的搜索查询。然后,我们还将 Kibana 添加到我们的堆栈中,以获得一些浏览和管理舒适性以及有用的可视化特性。从简介中概述的最初目标来看,可能并没有真正达到:)但是希望您对该技术能够提供什么有了一些了解,从而为决定如何最终将它部署到您的架构中提供了一个基础。请随意分享可以添加到下一步部分列表中的任何其他有趣的资源。

Photo by Jan Tinneberg on Unsplash

从软件工程到数据科学:战略进展和相互联系。

原文:https://towardsdatascience.com/from-software-engineering-to-data-science-strategic-progress-and-being-connected-b90ea105cb7c?source=collection_archive---------11-----------------------

许多有抱负的数据科学家想知道如何走上这条道路并获得数据科学家的工作。幸运的是,现在,你不必开始一个昂贵的训练营或大学学位来成为一名数据科学家,因为有许多资源可用,而且其中许多资源是免费的,每个人都可以访问。在这篇文章的 第一部分 中,我分享了帮助我获得数据科学家工作的资源。然而,没有战略,就更难实现。

我个人加入了一个社区,帮助我 知道我的目的塑造我的梦想职业明确我的目标和行动步骤 。是优雅的职业女孩。这是我时间管理工具和组织自己的主要资源。我还受到了其他一些推荐技巧的启发,如番茄工作法、最重要的任务、感恩日志等..

让我们回顾一下我制定的战略支柱!

Photo by JESHOOTS.COM on Unsplash

有计划

没有计划的目标只是一个愿望。安托万·德圣埃克苏佩里

我相信,没有一个计划,无论何时当你面对一些“沮丧”的时刻,你都不能坚持你的目标。因此,有一个计划是必不可少的,这样你就能一直关注它,并更新你对目标的承诺。我是这样做的:

  1. 我从一个年度计划开始,从中我创建了一个四分之一板,上面有三个主要目标,并回答“为什么?”每一个。
  2. 准备一份 90 天目标行动计划:填写一张表格,在上面我写下了我每个月的重点重点领域是什么以及要在 30、60 和 90 天内完成的任务
  3. 每月做一次回顾。

每日优先级排序

每天早上,我首先写下我一天中的 5 个优先事项,或者被称为最重要的任务(MITs ):

首先,我选择 1 个最重要的任务,然后是 2 个次要任务,最后是 3 个附加任务。第二,我通过所需番茄的数量(有多少个 30 分钟的时间段)给他们每个人估计时间。最后,在一天结束的时候,我用效率分数来评估我的表现。

下面是一个例子(注意日期下面的引用,每天我都会选择一个引用来激励自己):

A Daily planning example

积极心态

我做的另一件事是确保正确的心态,这在这样的过渡阶段非常重要:

每天早上在纸上写下:

  • 我感激的 3 件事(越具体越好)
  • 让今天变得伟大的三件事
  • 一个日常肯定

Unsplash

然后,在一天结束时,我写下:

  • 那天发生的 3 件令人惊奇的事情(当然,即使是最简单的好事也应该有!)
  • 我怎样才能让这一天变得更好?

免责声明:我不会假装每天都完成了所有这些任务,但我学会了在完成最重要的任务和一些次要任务时感到快乐。

时间/任务记录

为了跟踪时间,我使用了 Kanbanflow :我创建了一个名为周计划的面板,其中的列是:一周的所有日子 + 今天 + 完成。

在开始我写在纸上的任务之前(见每日优先顺序 ) 我把与一周中的某一天相对应的任务移到“今天”栏,并用番茄工作法记录每项任务的时间(我还用标签 1 番茄工作法、2 番茄工作法等给它们涂上颜色)..).然后,它甚至可以检查时间日志,看看我花了多少小时。这真的是一个很棒的工具,我至今仍在使用。这有助于集中注意力,并有一个具体的任务日志概述。这里有一个例子:

Screenshot of my KanbanFlow board

好吧,那么现在,这些足够得到这份工作了吗?

依我看,答案是否定的。即使你参加了课程、学习、组织自己,如果你不努力,你得到工作的机会也是微乎其微的。

如果你不努力,你得到这份工作的机会微乎其微。

因此,您肯定需要:

  • 分享你的学习成果:当你分享你的学习成果时,你是第一个从中受益的人,因为当你把新知识传授给别人时,你会更好地记住它。可以通过博客文章、youtube 视频或 LinkedIn 文章。我非常喜欢最*发现的一篇文章我在一年中每周写一篇数据科学文章的收获,它讲述了写一篇数据科学文章的好处。
  • 做一些小项目,并把它们放入 Github: 一方面,这种实践可以让你获得实用的知识,正如我在第 1 部分中已经提到的将你所学应用到项目中的重要性。招聘人员更感兴趣的是你做过的项目,而不是你完成的课程。另一方面,使用 Github 将是有益的,因为很可能在你的工作中,你也必须使用它。
  • 参加数据科学活动/聚会:通过参加数据科学/大数据活动,你可以了解该领域的现状,此外,它建立了一个网络,你可以利用这些活动的机会在一个项目中寻求帮助,或在一个项目中提供帮助,与其他想要整合该领域的人联系。在旅途中感受到支持和找到一个部落是非常重要的。有时甚至有免费的在线会议,我参加过一次由 Metis 组织的免费在线会议。Kaggle 还将在下个月组织一个名为 CareerCon 的活动。你也可以查看 meetup.com,在你所在的地区寻找关键词为数据科学、大数据、机器学习的聚会。
  • 与业内人士联系:向业内人士介绍自己,无论是在参加活动时还是在网上。如果在网上,不要发送标准的邀请信息/电子邮件,要私人化:陈述他们写的博客,或者问一个问题,或者和他们谈谈你的旅程,也许他们有建议。如果你尝试的话,你甚至可以在他们中间找到一个导师。数据科学社区中有很多人愿意提供帮助,所以不要感到羞愧。你只需要知道如何介绍自己和你的目的。

数据科学社区中有很多人愿意提供帮助,所以不要感到羞愧。你只需要知道如何介绍自己和你的目的。

Unsplash

无论是作为与会者还是作为发言人,参加一些会议对我帮助很大( Data Natives 2016 , Data Natives 2017 )。我也抓住了一个的短期自由职业机会,这主要是通过在一个真实的项目中工作来学习。

另外,在我联系过的数据科学人士中,我强烈建议在 LinkedIn 上关注他们:

  • 基里尔·叶列缅科 :数据科学管理顾问,superdata Science CEO,Udemy *台数据科学讲师。
  • Eric Weber:数据科学家总是分享他的知识。
  • 法维奥·巴斯克斯 : 首席数据科学家,数据科学导师。
  • Lillian Pierson:科技中小企业商业蔻驰,大数据战略家&企业培训师,Data-Mania 创始人。
  • Brandon Rohrer:脸书大学的数据科学家,机器学习讲师,非常擅长在视频中解释事情。
  • 克里斯托弗档案员 : 首席数据科学家。他在媒体上有很棒的系列。发现他关于成为机器学习工程师的系列时,我好开心。
  • 杰森·布朗利 : 机器学习大师的创始人
  • 马修·梅奥 : 机器学习研究员和 KDnuggets 的编辑,出版关于机器学习和数据科学的各种内容。

最后一点,面试也能教会你很多东西,所以不要害怕尝试,即使一开始你觉得你没有达到要求。大多数情况下,在招聘过程中,你会收到一个数据挑战。做这些挑战才是真金白银!认真对待他们,尽你所能,如果你没有得到这份工作,那么你已经得到了一些东西,不要认为你失去了!是的,有时候会令人失望,但是继续向前看,你会发现所有这些面试都有助于你获得一份比你想象中更好的工作。史蒂夫·乔布斯曾经说过什么?

“你的时间有限,所以不要浪费在过别人的生活上。不要被教条所困,那是活在别人思考的结果里。最重要的是,要有勇气跟随你的心和直觉。他们已经知道你真正想成为什么样的人。其他一切都是次要的。”—史蒂夫·乔布斯

摘要

总而言之,以下是第 1 部分和第 2 部分中提到的要点:

  • 制定一个计划并定义你的目标——每天追踪你的进展是非常重要的。
  • 做在线课程,使用在线资源
  • 开始小项目
  • 分享你的知识
  • 走出去,和这个领域的人联系
  • 做面试,不要害怕失败。挑战生活,赢得比赛!

我自己也遵循了这些步骤,尽管我花了大约一年时间才得到这份工作,但我相信这一年是必要的,因为最终我进入了我梦想的工作环境(尽管我以前的一位公司经理否认了它的存在)。此外,我发现自己在广告界和推荐系统项目中工作。事实上,我的职业吸引了我想得到的东西:

“不仅如此,在所有的主题中,尤其是两个主题引起了我的注意: 推荐系统营销分析(广告竞价,从广告中提取信息等)!他们是多么迷人啊!”(我在我的Up to my new tech challenges文章中写了这句话)。

看到了吗?记住我之前告诉你的话:你会得到你所关注的。😃

Unsplash

最后引用达芬奇的一段话:

有成就的人很少坐以待毙,让事情发生在他们身上。他们出去了,发生了一些事情。“莱昂纳多·达芬奇

那么,你还在等什么?现在就开始!如果你需要帮助,请通过 LinkedIn 联系我,我会很乐意支持你!

: 原创文章 发表在我的网站上。

从软件工程到数据科学:哪些资源帮助了我?

原文:https://towardsdatascience.com/from-software-engineering-to-data-science-what-resources-helped-me-23b3f42b64db?source=collection_archive---------9-----------------------

大约两年前,我决定辞去软件工程师的工作,开始在机器学习领域寻找工作。辞职后,我立即在我的博客 上写了一篇关于我的新技术挑战 的文章,旅程由此开始。

Photo by Ian Schneider on Unsplash

在这篇文章中,我很高兴与大家分享我是如何找到梦想中的工作的。是的,我拿到了!我在柏林的 Remerge 公司做了一年的数据科学家。

现在就开始吧!

选择正确的课程

Photo by Glenn Carstens-Peters on Unsplash

首先,理解机器学习/数据科学中的 核心概念 技术 很重要,所以我开始在网上学习一些主要课程:

机器学习专业化 ,华盛顿大学,Coursera:

您将学习不同的算法、如何预测、如何分类、如何评估结果、何时使用每种算法以及如何调整算法性能。

两位亚马逊教授教授的专业课是一个很好的起点,尤其是从基本理论知识的角度来看。它经历了主要的机器学习领域: 回归分类聚类信息检索

用于数据科学和机器学习的 Python,Udemy:

因为我也是从 python 开始的,所以我选择将 Coursera specialization 与这个训练营结合起来,以便获得实践和理论。我喜欢它的简单明了和非常有用!它教授以上主要的机器学习领域,但更侧重于 Python 和库的,这些库可以用于每个算法 的 ,它让您开始使用 Jupyter 笔记本探索数据等等。**

在遵循它的同时,还探索了数据科学中的不同业务领域。

练习有时应用于金融数据,有时应用于电子商务数据,在课程结束时,还将介绍神经网络深度学习 。**

不要停留在网络课程上,要利用更多的资源

我在网上使用了一些免费资源,它们对我帮助很大,我可以列举一些主要的:

  • 机器学习掌握网站:这个网站通过提供和解释步骤帮助我开始了我的第一个项目,除此之外还有很多其他解释得很好的教程!我建议从这篇文章开始:机器学习掌握方法。
  • 精英数据科学博客:该网站有一个工具&资源部分,提供项目创意、项目启动指南和一些免费数据集的链接。下面是它的一篇文章:初学者的机器学习项目。
  • Analytics Vidhya 博客:该博客富含应用机器学习,不同机器学习领域的顶级技术,例如本文:你应该知道的 7 种回归技术!也是面试准备的有益资源:数据科学面试问答。
  • 数据学校 : 这个网站有教程,视频,笔记本,帮助我学习如何使用 python 库(熊猫,Scikit-learn,..).

为了获得一份机器学习工程师或数据科学家的工作,在实践方面需要做大量的工作(开发项目)。

除了这些参考文献,还有一些社区在中,像走向数据科学和自由代码阵营。他们都有每周精选,可以通过电子邮件订阅。他们有一套很好的话题:****

  • **迈向数据科学时事通讯提供了各种精选的数据科学主题。
  • **自由代码营时事通讯提供了一些有趣的开发者话题。

通过这两个社区将特定范围和更广泛的范围结合起来是很好的。我还有一份电子邮件上收到的媒体每日文摘,它根据我在媒体中关注的内容分享新文章,我建议你也这样做。这有助于你保持更新和动力。****

即使当你在公共交通工具上或做家务时,你也可以学习!

Photo by Mohammad Metri on Unsplash

每当你想在做其他必要的事情的同时让你的时间富有成效的时候,听播客是一个绝妙的主意(我知道:我们的生活中有太多的事情)。

许多数据科学、人工智能、机器学习播客都存在,你可以在这里找到一个列表。我更坚持检查和遵循的一条是:

  • 超级数据科学播客 :在这些播客系列中,超级数据科学 CEOKirill采访了不同背景的人,分享着同样的激情: 挖掘数据 !我发现他的播客信息量很大:它们将你与数据科学领域的人联系起来,让你发现不同领域的数据科学,因为这些人拥有非常广泛的专业经验,它们激励你挑战极限,更加努力地实现目标,因为这是可能的!**

书籍也是用来强化知识的

Photo by Susan Yin on Unsplash

我没有从头到尾读过一本关于数据科学或机器学习的书,每当我在处理一些数据时遇到机器学习问题,或者当我从课程或在线资源中不能很好地理解某个概念时,我都会使用它们。一些有用的书有:

  • 从零开始的数据科学 ,Joel Grus: 这本书在算法没有被很好理解的时候很有帮助,因为它教你如何从零开始,一步一步地实现它。
  • 做数据科学 ,作者 Cathy O'Neil: 它介绍了数据科学中的不同主题和技术,以及它们在一些实际问题上的应用。它在我的小项目中帮助了我,比如垃圾邮件过滤器和建立推荐系统。
  • Think Stats:Python 中的探索性数据分析 ,作者 Allen Downey: 我用这本书作为参考,学习如何正确地做 EDA。它给出了必要的统计前提,并在此基础上构建了真实的数据集 EDA 示例。
  • 在线统计书籍: 当我发现这个在线资源时,我感到非常幸运,因为我正在与统计所需的背景作斗争,我不喜欢那些太多的理论书籍或课程。这个和我一起工作。
  • 特征提取&图像处理作者 Mark Nixon :在开始一个计算机视觉项目时很有帮助。
  • 推荐系统-教科书,作者 Aggarwal,Charu C: 当然,这都是关于推荐系统的,是最好的参考资料之一,我甚至买了纸质版的,因为我真的很想从事推荐系统的研究。

网上仍然有很多资源和课程,它们甚至是无限的,你只需要寻找和挑选更适合你的,但是为了真正从这个工具包中受益,有一件事是绝对必要的:那就是致力于,让知道你想要实现什么以及何时实现,并让保持一致,因为你会得到你所关注的!我打赌你现在在想:“说起来容易,做起来难”,我在这里回答:我写这篇博客是为了给出一个具体的、真实的例子。当然这并不容易,但是你可能想到的每一个成功人士都制定了成功/进步策略。****

让我获得数据科学家工作的策略是什么?

让我们把它留到本文的第二部分。(第二部现已面世:从软件工程到数据科学:进度策略与被连接。)

为了从这个工具包中真正受益,有一件事是绝对必要的:那就是坚持不懈,知道你想在什么时候实现什么,并且保持一致。

You get what you focus on!

…..

我想以这张我在 Remerge 的第一天办公室经理拍的照片来结束我的演讲:她让我画一张我自己的照片和一个简短的介绍。

: 原文 发表在我的网站上。

从 Tensorflow 1.0 到 PyTorch &回到 Tensorflow 2.0

原文:https://towardsdatascience.com/from-tensorflow-1-0-to-pytorch-back-to-tensorflow-2-0-f2f8a4c716b7?source=collection_archive---------20-----------------------

为了开发深度学习项目,我们必须在 Tensorflow 和 Pytorch 这样的库之间来回移动,这是一种常见的情况。

Photo by Simon Matzinger on Unsplash

我在 2015 年左右开始了我的机器学习之旅,当时我快十几岁了。由于对这个领域没有清晰的认识,我读了很多文章,看了大量 YouTube 视频。我不知道这个领域是什么,也不知道它是如何运作的。那是谷歌流行的机器学习库 Tensorflow 发布的时间。

步入张量流

Tensorflow 于 2015 年 11 月作为“机器智能开源软件库”发布。它一发布,人们就开始投身其中。GitHub 中的分叉数量呈指数增长。但是它有一个根本性的缺陷:'静态图'。

在幕后,Tensorflow 使用静态图实现来管理数据流和操作。这意味着从程序员的角度来看,您必须首先创建一个完整的模型架构,将其存储到一个图中,然后使用“会话”启动该图。虽然这对于创建生产模型来说是一个优势,但是它缺乏的 pythonic 性质

社区开始抱怨这个问题,Tensorflow 团队创建了“渴望执行”来解决这个问题。但是,它仍然没有被添加为默认模式。Tensorflow 也有很多(有点太多)API,以至于令人困惑。同样的函数定义也有很多冗余。

转移到 PyTorch

这段时间(2017 年左右),我要做一个项目,需要同时训练两个神经网络,两者之间有数据流。我用 Tensorflow 开始我的工作,因为它是一个烂摊子。多个图,图与图之间切换,手动选择参数进行更新……纯粹一塌糊涂。最后我放弃了 Tensorflow,开始用 PyTorch。

使用 PyTorch 要容易得多…具体的定义,稳定的设计,通用的设计结构。我非常喜欢它。尽管如此,我没有完全放弃 Tensorflow,我使用 Keras 和 Tensorflow 和 Tensorboard 参加了研讨会和讲座。后来,我完成了我的项目,在 PyTorch 上又做了一些,但是我觉得这个社区还不够强大。

返回张量流

在此期间,Tensorflow 变得越来越强大,与软件包紧密集成,通过 GPU 轻松训练,并作为 Tensorflow 服务为生产提供强大支持。感觉 TensorFlow 正在向一个新的方向发展。

2019 年 10 月 1 日,TF2.0 首个稳定版发布。新特性包括与 Keras 的紧密集成、默认的急切执行(最后😅)、功能和非会话、多 GPU 支持等等。另一个漂亮的特性是 tf.function decorator,它将代码块转换成优化的图形,从而提供更快的执行速度。

此外,像 tf.probability、tensorflow_model_optimization、tf.agents 这样的 API 将深度学习的能力推向了其他领域。作为一个建议,我希望看到不同的强化学习包,像 Tensorflow 代理,TFRL(松露),多巴胺合并成一个单一的 API。

谢谢大家!!

从理解到掌握。数据专业人员面临的问题类型以及如何应对

原文:https://towardsdatascience.com/from-understanding-to-scaling-mastery-68247236a1c1?source=collection_archive---------47-----------------------

当你开始一个新的数据科学或分析角色时,你做的第一件事是什么?你知道,除了安装你需要的所有必要的工具和软件包,以及访问数据?如果你还没有,明智的做法是做一个数据问题审计,找出你的组织中数据可以发挥作用的所有领域。

数据问题审计是简单地进行一系列的访谈,以暴露组织中存在的问题,这些问题可以用数据来回答。无论您是个人、团队领导,甚至是受托开发数据战略的人,提出所有这些问题都是有价值的。根据我做上述所有事情的经验,经常会出现四类问题。

它们是:

一级分析(了解)

告诉我的价值

二级分析(理解)

不要只报告趋势,告诉我为什么会这样

三级分析(掌握)

我喜欢这些趋势,但是我们能全面彻底地回答吗?

第 4 层分析(扩展精通)

我喜欢你迄今为止所做的一切,我们能不能把你从等式中去掉,建立一些永久有效的东西

第 1 级问题的一个例子是,如果您被问到实际值和目标值之间的差值是多少。分析师应该用不到一天的时间来回答这些问题。应对这些问题的主要技能是数据挖掘和开发可视化的能力。

第二层是,如果你被要求调查造成这种差异的因素。根据问题的复杂程度,回答这个问题可能需要几个小时,甚至几天。

第三层是要求你全面回答实际和目标之间的关系是什么,它是如何随着时间的推移而演变的,以及有哪些因素影响它。这样做的时间通常会超过一周。第 2 层和第 3 层需要结合数据挖掘、分析和数据科学专业知识。

第 4 层是当您被要求开发一个模型来预测一个值或结果时(在某些情况下,您最初被要求简单地报告的那个,在我们的例子中是“实际值”)。这需要 ML 模型的生产、测试和部署,可能需要几个月的时间。这是数据科学的领域,也是数据工程师的领域。

从简单地报告正在发生的事情,到预测性分析解决方案的部署和扩展,这个连续体将带您了解一切。从了解到掌握。那么现在你的审计已经告诉你那里有什么,你会怎么做呢?

自动化简单的事情

你的第一级问题是 BAU 问题,没有上下文。在这些问题中,您的利益相关者可能只需要知道一个数据点,而不需要深究它的实际含义。

这些任务通常落在分析团队身上,尽管他们中的一些人可能仍然留在商业领域(尽管这两者应该保持同步)。鉴于许多组织刚刚开始投资和建立他们的分析和数据科学团队,你可能会对你的审计中属于这一领域的问题的比例感到惊讶。如果您已经加入了一个新生的数据功能,或者正在一个初创的环境中工作,这一点尤其正确。您的组织已经承诺构建数据能力,他们可能有大量积压的项目需要分析团队来处理,其中许多项目都在这一流程中。

虽然这些之前积压的问题可能会得到很好的回答,而且它们相对容易解决,但它们本身会带来一些风险,你需要减轻这些风险。它们包括:

  1. 分析师流失的风险:没有多少分析师只是在游戏中挖掘数据点——他们希望产生影响,并使用他们的技能来弄清事情的真相。此外,由于这些查询的 BAU 性质,未能自动化您的第 1 级响应可能会导致任务重复
  2. 没有得到重要东西的风险:记住知道是走向掌握的连续体的开始。你需要把简单的事情处理掉,让你开始真正的增值任务
  3. 预期与现实不符的风险:数据资源并不便宜。如果你没有管理预期,并且一直在解决 BAU /低附加值问题,这可能会对组织从数据中获得(或认为获得)多少价值产生影响

幸运的是,你解决第一层问题的方法很简单。一旦你确定了这些问题,你就可以腾出时间自动给出他们的回答。

这通常通过开发自助仪表盘来实现。花几个月的时间开发一个自动化的自助服务解决方案,满足您的组织的所有第 1 层报告需求,并让您的团队有时间从事更高附加值的工作。更好的是,如果你做得好,这将在可预见的未来解决这些问题,只有当企业进入新的垂直市场或获得新的(重要的)数据源时,才需要扩展。它还将作为第 2 级和第 3 级问题的线索和来源,您将需要花大部分时间来解决这些问题。

第二层和第三层是你的面包涂黄油的地方

您在自动化第 1 级响应方面所做的所有出色工作都是为了腾出时间,以便您和您的团队能够在这个领域开展工作。这些都是很有价值的问题。此外,随着你的组织开始使用更多的数据,他们将有一个定期和有机的需求流,并要求你调查每当你回答第 1 级问题时出现的趋势。第 2 级和第 3 级非常相似,主要区别在于回答每个问题所需的时间,以及回答问题的结论性。

例如,第 2 层的问题可能是:“我们想调查为什么销售额逐年下降”,而第 3 层的问题可能是“我们想了解是什么因素推动了销售,以及我们如何能够销售更多的产品”。前者更局限于特定的场景,而后者更开放,更有结论性,需要你穷尽所有可能的调查途径。

另一个区别是,第 2 级问题可能用于告知战略行动,而第 3 级问题可能告知战略方向(或某些战略行动将级联的总体战略)。一个放入 powerpoint,另一个放入纸板。

重要的是要认识到这两个领域的重要性,并管理期望,以便您将 80%的时间花在这两个领域上(当然是自动回复第 1 级问题)。你还应该积极主动地确定你的组织可能想要全面回答的领域(第 3 级),并开始抽出时间来解决这些问题,因为它们可能需要几周或几个月的时间来全面回答。

这些是你将会花大部分时间去解决的问题,所以花点时间来构建你的团队工作流程和节奏,以公正地对待它们。

规模重要性

现在你已经自动回答了最简单的问题,并且开发了一个很好的节奏让你去做最重要的事情,那么剩下的是什么呢?最后一个阶段是确定您的组织希望在未来和永久得到回答的问题,即第 4 层。这一步要求您自动回答复杂的问题,您是否能够在处理重要的组织问题时,生成能够提供足够准确性的模型或工具?本质上,这需要预测模型的产生和部署,甚至可能是全面的数据工程。

这里的挑战是识别 a)存在的和 b)需要优先考虑的用例,假设你每年只执行几个用例( if that )。从优先顺序的角度来看,最好从最容易执行的开始,前提是价值能够实现。这将让你摘下容易摘到的果实,并对你的方法建立信心,一旦你展示了回报的能力,你就可以要求更多的资源和资金。这一点尤其重要,因为这一层中的大多数问题都需要商业案例、资金和其他治理措施才能成功执行。

当您运行问题审核时,全面确定可能属于这一层的问题(即,我们是否能够使用数据来预测…?)并开始对它们进行优先排序。与之前的任何层级相比,您可能需要教育您的利益相关者什么是可能的,以及您应该做什么,因为某些计划可能:

  1. 释放其他能力——基于客户终身价值模型的开发做出更明智的决策
  2. 提供可以扩展或重新分配的技术,只需一点点努力,就可以解决具有一些相似特性的不同问题
  3. 需要技术投资

也要认识到,这将主要是项目工作,所以他们将被交付的性质将发生变化,需要一个不同的管理风格相比,你的 BAU 工作。

最后,管理期望,让你的团队花大约 20%的时间在这些项目上,根据你的资源,你每年至少交付 2-3 个这样的项目()。也可以将这些项目留到最后,完全隐藏起来,直到您的所有第 1 层分析都得到解决,并且您已经取得了良好的进展,并为您的第 2 层和第 3 层开发了节奏。但是,您需要知道这些机会在哪里,一旦有机会,您需要找到时间(和正确的策略)来执行它们。

最后的想法

您可能会注意到,第 1 层和第 4 层都有一个自动化组件。在第 1 层中,您自动化简单性,而在第 4 层中,您自动化复杂性。其余的问题将是具体的,由上下文驱动的,因此很难自动化。有时,他们还需要对您的第 1 级和第 4 级回应产生的结果进行解释。

因此,他们也将成为你最可靠和最有价值的工作来源。在某些方面,您将把第 1 层的解释和决策部分委托给自助终端用户,将第 4 层委托给算法(这取决于技术,可能是黑盒本身)。然而,你将是第二层和第三层空间中任何事情的关键解释者和决策者,所以对这些问题承担责任和所有权,并确保它们占去了你投资管理工作的大部分时间。

祝好运和快乐(问题)审计!

本文原载于【https://datandi.com/】

从单词嵌入到预训练语言模型——自然语言处理的新时代——第一部分

原文:https://towardsdatascience.com/from-word-embeddings-to-pretrained-language-models-a-new-age-in-nlp-part-1-7ed0c7f3dfc5?source=collection_archive---------10-----------------------

对于机器学习模型要处理的单词,它们需要某种形式的数字表示,模型可以在计算中使用。这是 2 部分系列的第 1 部分,在这里我将介绍单词到矢量表示方法是如何随着时间的推移而发展的。第二部分可以在这里找到。

传统的上下文无关表示法

一袋单词或一个热门编码

在这种方法中,向量中的每个元素对应于语料库词汇表中的一个唯一的单词或 n 元语法(标记)。然后,如果文档中存在特定索引处的标记,则将该元素标记为 1,否则标记为 0。

BoW Representation

在上面的例子中,我们的语料库由三个文档中的每个唯一单词组成。第二个文档的 BoW 表示显示在图片中,我们可以看到向量的每个元素对应于特定单词在文档 2 中出现的次数。

这种方法的一个明显的局限性是,它没有将任何意义或单词相似性的概念编码到向量中。

TF-IDF 代表

TF-IDF 是术语频率-逆文档频率的缩写。它是一种统计方法,用于评估一个词在一组文档或语料库中对一个文档的重要性。这种重要性与一个单词在文档中出现的次数成正比,但被语料库中包含该单词的文档数量所抵消。我们来分解一下。

词频(TF):是该词在当前文档中出现频率的得分。因为每个文档的长度不同,所以一个术语在长文档中出现的次数可能比短文档多得多。因此,将词频除以文档长度进行归一化。

逆文档频率(IDF):是对该单词在文档中的稀有程度的评分。术语越少,IDF 分数越高。

因此,TF-IDF 得分= TF * IDF

在这种方法中,不是用原始计数填充文档向量(像在 BoW 方法中),而是用该文档的术语的 TF*IDF 分数填充它。

即使 TF-IDF BoW 表示为不同的单词提供权重,它们也不能捕捉单词的含义。

基于分布相似性的表示——单词嵌入

上述两种方法都有一个明显的局限性,并且不能捕获单词语义,那就是随着词汇量的增加,文档的向量表示也会增加。这会产生一个有很多零分数的向量,称为稀疏向量或稀疏表示,在建模时会产生更多的内存和计算资源。

神经单词嵌入解决了这两个缺点——通过使用密集表示实现降维,以及使用上下文相似性实现更具表达力的表示。

单词嵌入是文本的学习表示(实值向量),其中具有相同含义的单词具有相似的表示,例如,著名的“国王-男人+女人=女王”示例。这种方法的关键是对每个单词使用密集的分布式表示。每个单词用一个实值向量来表示,往往是几十维或者几百维。这与稀疏单词表示所需的数千或数百万维形成对比,例如一键编码。

两个最流行的单词嵌入是 Word2Vec 和 GloVe。

Word2Vec

Word2Vec 基本上有两个版本——连续单词包
(CBOW)和 Skip-Gram。CBOW 模型通过基于上下文(周围的单词)预测当前单词来学习嵌入。Skip-Gram 模型通过预测给定当前单词的周围单词(上下文)来学习。

Word2Vec CBOW vs Skip-gram

现在让我们来看看 skip-gram,因为它在大多数任务上实现了更好的性能。

Skip-gram 试图预测给定单词的*邻。我们取一个中心单词和一个上下文(相邻)单词的窗口,并尝试预测该中心单词周围某个窗口大小的上下文单词。因此,我们的模型将定义一个概率分布,即给定一个中心词,一个词在上下文中出现的概率,我们将选择我们的向量表示来最大化该概率。一旦我们可以相当准确地预测周围的单词,我们就移除输出层,并使用隐藏层来获得我们的单词向量。我们从单词向量的小的随机初始化开始。我们的预测模型通过最小化损失函数来学习向量。在 Word2vec 中,这通过带有语言建模任务(预测下一个单词)和优化技术(如随机梯度下降)的前馈神经网络来实现。

杰伊·阿拉玛的这个博客在解释 Word2Vec 方面做得非常出色。

手套

GloVe 是“Global Vectors”的缩写,其动机是基于上下文窗口的方法具有不能从全局语料库统计中学习的缺点。这可能导致无法学习重复和大规模的模式以及这些模型。手套模型背后的主要思想是关注文本语料库中单词的共现概率,以便将它们嵌入到有意义的向量中。换句话说,GloVe 查看一个单词 j 在我们所有文本语料库中的单词 i 的上下文中出现的频率。

Word2Vec 是一个“预测”模型,而 GloVe 是一个“基于计数”的模型。使用这两种方法生成的嵌入在下游 NLP 任务中的表现非常相似。

接下来,我们将在 第二部分 中讨论情境化的表征。

参考

[## Word2vec 自然语言处理白痴指南

Word2vec 可以说是神经网络自然语言处理革命最著名的面孔。Word2vec…

opendatascience.com](https://opendatascience.com/an-idiots-guide-to-word2vec-natural-language-processing/)

从单词嵌入到预训练语言模型——自然语言处理的新时代——第二部分

原文:https://towardsdatascience.com/from-word-embeddings-to-pretrained-language-models-a-new-age-in-nlp-part-2-e9af9a0bdcd9?source=collection_archive---------7-----------------------

对于机器学习模型要处理的单词,它们需要某种形式的数字表示,模型可以在计算中使用。这是由两部分组成的系列文章的第 2 部分,其中我将介绍单词到矢量表示方法是如何随着时间的推移而发展的。如果你没有读过这个系列的 部分 1 ,我建议你先看看!

超越传统的上下文无关的表示

虽然我们在 第一部分 中看到的预训练单词嵌入已经非常有影响力,但它们有一个主要的局限性——它们假设单词的意思在句子中相对稳定。事实并非如此。一词多义现象比比皆是,我们必须小心一个单词在意思上的巨大差异:例如 lit(描述某物燃烧的形容词)和 lit(文学的缩写);或者 get(获得的动词)和 get(动物的后代)

传统的单词向量是浅层表示(单层权重,称为嵌入)。他们只是在模型的第一层中加入了以前的知识。对于新的目标任务,网络的其余部分仍然需要从头开始训练。

使用单词嵌入就像用只对边缘进行编码的预训练表示来初始化计算机视觉模型一样——它们将对许多任务有帮助,但它们无法捕捉可能更有用的更高级信息。单词嵌入只在捕捉单词的语义时有用,但我们还需要理解更高层次的概念,如回指、长期依赖、一致、否定等等。

例如,考虑不完整的句子“服务很差,但食物很棒”。为了预测随后的单词是“yummy”或“delicious ”,模型不仅必须记住用来描述食物的属性,还必须能够识别连接词“but”引入了对比,使得新属性具有“poor”的对立情绪。

这些单词嵌入不是上下文特定的——它们是基于单词并发性而不是顺序上下文来学习的。因此,在两个句子中,“我正在吃苹果”和“我有一部苹果手机”,两个“苹果”单词指的是非常不同的事物,但它们仍然共享同一个单词嵌入向量。

由浅入深的前期培训

大多数文本分类(或任何其他受监督的 NLP 任务)的数据集都相当小。这使得训练深度神经网络非常困难,因为它们往往会过度适应这些小的训练数据集,并且在实践中不能很好地推广。

在计算机视觉领域,几年来,趋势是在巨大的 ImageNet 语料库上预先训练任何模型。这比随机初始化好得多,因为该模型学习一般的图像特征,并且该学习可以用于任何视觉任务(比如字幕或检测)。预训练的 ImageNet 模型已经被用于在诸如对象检测、语义分割、人体姿态估计和视频识别等任务中实现最先进的结果。与此同时,他们使得 CV 能够应用于训练样本数量少且注释昂贵的领域。

基于语言建模的预训练模型可以被认为是用于 NLP 的 ImageNet 的对应物。语言建模已经被证明能够捕获与下游任务相关的语言的许多方面,例如长期依赖性、层级关系和情感。语言建模的最大好处之一是,任何文本语料库都可以免费获得训练数据,并且潜在地可以获得无限量的训练数据。

进行 NLP 项目的标准方式一直是——通过诸如 word2vec 和 GloVe 等算法对大量未标记数据进行预训练的单词嵌入被用于初始化神经网络的第一层,其余部分则根据特定任务的数据进行训练。然而,目前许多用于监督 NLP 任务的先进模型都是在语言建模(这是一项无监督的任务)上预先训练的模型,然后使用特定于任务的标记数据进行微调(监督)。ULMFiT、ELMo、OpenAI transformer 和 BERT 的最新进展的核心是一个关键的范式转变——从仅仅初始化我们模型的第一层到用分层表示对整个模型进行预训练,以在自然语言处理的各种任务上实现最先进的水*,包括文本分类、问题回答、自然语言推理、共指消解、序列标记等。所有这些方法都允许我们在大型数据语料库(如所有维基百科文章)上预训练一个无监督的语言模型,然后在下游任务上微调这些预训练的模型。

来自语言模型的嵌入(ELMo)

ELMo 的动机是单词嵌入应该包含单词级别的特征以及上下文语义。解决方案非常简单——ELMo 表示是双 LSTM 所有内部层的函数,而不是仅将深层双 LSTM 语言模型的最后一层作为单词表示。ELMo 获得每一层的每个内部功能状态的向量,并以加权的方式组合它们以获得最终的嵌入。深度表示优于仅从 LSTM 顶层得到的表示。

直觉上,双 LSTM 的较高层次状态捕捉到了上下文,而较低层次捕捉到了语法。通过比较第一层和第二层嵌入的性能,也可以从经验上看出这一点。虽然第一层在词性标注上表现更好,但第二层在词义消歧任务上实现了更好的准确性。

ELMo 通过训练来预测单词序列中的下一个单词,从而获得了语言理解能力——这是一项名为语言建模的任务。ELMo 没有为每个单词使用固定的嵌入,而是在为每个单词分配嵌入之前查看整个句子,从而为每个出现的单词生成稍微不同的嵌入。

例如,考虑句子“百老汇戏剧昨天首演”,在上面的句子中,单词“ play ”使用标准单词嵌入来编码多个意思,例如动词 来播放 或者在示例句子的情况下,一部戏剧作品。在诸如 Glove、Fast Text 或 Word2Vec 的标准单词嵌入中,单词 play 的每个实例将具有相同的表示。

通用语言模型微调(ULMFiT)

ULMFiT 在六个文本分类任务上明显优于最先进的技术,在大多数数据集上减少了 18–24%的错误。此外,只有 100 个标记的例子,它匹配从零开始在 100 倍以上的数据上训练的性能。

ULMFiT 基于 AWD-LSTM (这是一个多层双 LSTM 网络,无需关注)。该模型在 WikiText-103 语料库上进行训练。

ULM-FiT 引入了一些方法来有效地利用模型在预训练期间学习到的很多东西——不仅仅是嵌入,也不仅仅是情境化的嵌入。ULM-FiT 引入了一个语言模型和一个过程,以针对各种任务有效地微调该语言模型。

ULMFiT 遵循三个步骤来实现对下游语言分类任务的良好迁移学习结果

1)一般 LM 预培训—基于维基百科文本。

2)目标任务 LM 微调——ul mfit 提出了两种稳定微调过程的训练技术。见下文。

  • 区别性微调的动机是 LM 的不同层捕获不同类型的信息。ULMFiT 提出用不同的学习速率来调整每一层。
  • 斜三角学习率(STLR) 指一种特殊的学习率调度,先线性增加学习率,再线性衰减。

3)目标任务分类器微调——预训练的 LM 增加了两个标准前馈层,并在最后增加了 softmax 归一化,以预测目标标签分布。

  • 串联池提取隐藏状态历史上的最大轮询和*均池,并将它们与最终隐藏状态串联。
  • 逐步解冻从最后一层开始逐步解冻模型层,有助于避免灾难性遗忘。首先,最后一层解冻并微调一个时期。然后下一层解冻。重复该过程,直到所有层都被调整。

打开人工智能 GPT (创成式预训练变压器)

遵循 ELMo 的类似想法,OpenAI GPT 通过对庞大的自由文本语料库进行训练,将无监督语言模型扩展到更大的规模。尽管相似,GPT 和埃尔莫有两个主要的不同之处。

  1. 模型架构是不同的:ELMo 使用独立训练的从左到右和从右到左的多层 LSTMs 的浅层级联,而 GPT 是多层变压器解码器。
  2. 在下游任务中上下文化嵌入的使用是不同的:ELMo 将嵌入作为附加功能提供给为特定任务定制的模型,而 GPT 为所有最终任务微调相同的基础模型。

什么是变压器?

一般来说,Transformer 包括两个独立的机制——一个读取文本输入的编码器和一个为任务生成预测的解码器。编码器获取输入序列,并将其映射到更高维度的空间(n 维向量)。这个抽象向量被输入到解码器,解码器把它变成一个输出序列。输出序列可以是另一种语言、符号、输入的副本等。

把编码器和解码器想象成只会说两种语言的人类翻译。他们的第一语言是他们的母语,这在他们之间是不同的(例如德语和法语),而他们的第二语言是他们共同的一种虚构的语言。为了将德语翻译成法语,编码器将德语句子转换成它知道的另一种语言,即想象语言。由于解码器能够阅读那种想象的语言,它现在可以从那种语言翻译成法语。模型(由编码器和解码器组成)一起可以将德语翻译成法语!

Transformer 使用了一种叫做“注意力”的东西。注意力机制查看输入序列,并在每一步决定序列的哪些其他部分是重要的。

这听起来很抽象,但让我们用一个简单的例子来澄清:当阅读这篇文章时,你总是专注于你所阅读的单词,但同时你的大脑仍然在记忆中保存着这篇文章的重要关键词,以便提供上下文。

对于一个给定的序列,注意机制的工作原理是相似的。对于我们的人类编码器和解码器的例子,想象一下,除了用想象的语言写下句子的翻译,编码器还写下对句子的语义重要的关键字,并且除了常规翻译之外,将它们交给解码器。这些新的关键字使翻译对解码器来说更容易,因为它知道句子的哪些部分是重要的,哪些关键术语给出了句子的上下文。关于注意力的更多细节,参考这篇优秀的文章。

正如在他们的论文中所描述的,OpenAI GPT 是对谷歌大脑 2017 年论文《注意力是你所需要的全部》中著名变形金刚的改编。

谷歌大脑的原始版本使用了相同的编码器-解码器 6 层堆栈,而 GPT 使用的是 12 层解码器专用堆栈。每层有两个子层,由多头自注意机制和全连接(位置式)前馈网络组成。

以下步骤用于训练 OpenAI 变压器:

1.无监督的预训练:transformer 语言模型以无监督的方式在谷歌图书语料库的几千本图书上进行训练,预训练的权重在 OpenAI GitHub repo 上公开以供他人使用。

2.监督微调:我们可以根据监督目标任务调整参数。输入通过预先训练的模型传递,以获得最终变压器块的激活。

第一步(无监督的预训练)是非常昂贵的,由 OpenAI(他在 8 个 GPU 上训练了一个月的模型!)—幸运的是,我们可以使用下载的预训练模型权重,并直接进行监督微调步骤。

GPT 的一个限制是它的单向性质-该模型仅被训练来预测未来从左到右的上下文。

变压器的双向编码器表示(BERT)

BERT 是 GPT 的直接后代——在自由文本上训练大型语言模型,然后在没有定制网络架构的情况下针对特定任务进行微调。与 GPT 相比,BERT 最大的不同和改进是使训练双向化。该模型学习预测左侧和右侧的上下文。BERT 的模型架构是多层双向变换器编码器。

这篇博客文章在深入研究每一个模型的技术细节方面做了惊人的工作。

迁移学习

迁移学习(Transfer learning)是指使用一个经过训练的模型来解决一个问题(如对 ImageNet 中的图像进行分类),作为解决其他一些有些类似问题的基础。一种常见的方法是通过微调原始模型。因为微调模型不必从头学习,所以它通常可以用比不使用迁移学习的模型少得多的数据和计算时间来达到更高的精度。

将学习转移到下游任务始于 2013 年左右,使用来自无监督单词模型包(word2vec,GloVe)的上下文无关单词向量,然后使用来自序列模型(Elmo)的上下文相关单词向量,到当前直接使用经过训练的变压器块,其中附加输出层堆叠用于任务特定的微调(ULMFiT,GPT,BERT)。

现成的预训练模型作为特征提取器

深度学习系统和模型是分层的架构,在不同的层学习不同的特征(分层特征的分层表示)。然后,这些层最终连接到最后一层(在监督学习的情况下,通常是完全连接的层),以获得最终输出。这种分层的体系结构允许我们利用预训练的网络,而没有它的最终层作为用于其他任务的固定特征提取器。

Transfer Learning with Pre-Trained Deep Learning Models as Feature Extractors

这里的关键思想是仅利用预训练模型的加权层来提取特征,而不是在为新任务训练新数据的过程中更新模型层的权重。

这种方法的主要优点是比微调需要更少的资源。然而,它还需要为每个下游任务定制一个模型,并且通常得分低于微调。

微调现成的预培训模型

这是一个更复杂的技术,我们不仅替换最后一层(用于分类/回归),而且我们还选择性地重新训练一些先前的层。深度神经网络是具有各种超参数的高度可配置的架构。正如前面所讨论的,最初的层被认为是捕捉一般的特征,而后来的层更关注手边的特定任务。利用这种洞察力,我们可以在重新训练时冻结(固定权重)某些层,或者微调其余层以满足我们的需要。

Transfer Learning with Fine Tuning Off-The-Shelf Pre-Trained Models

这种方法通常比基于特征的方法得分更高,但是由于重新训练原本很大的预训练模型,它需要更多的资源。

参考

[## 有插图的伯特、埃尔莫等人(NLP 如何破解迁移学习)

讨论:黑客新闻(98 分,19 条评论),Reddit r/MachineLearning (164 分,20 条评论)翻译…

jalammar.github.io](http://jalammar.github.io/illustrated-bert/) [## 自然语言处理中的迁移学习

迁移学习无疑是目前深度学习领域的新热点。在视觉上,它…

medium.com](https://medium.com/explorations-in-language-and-learning/transfer-learning-in-nlp-2d09c3dfaeb6) [## NLP 的 ImageNet 时刻已经到来

NLP 的世界正在发生巨大的变化。词向量作为自然语言处理核心表示技术的长期统治地位已经…

ruder.io](http://ruder.io/nlp-imagenet/) [## 什么是变压器?

机器学习中的变压器和序列对序列学习介绍

medium.com](https://medium.com/inside-machine-learning/what-is-a-transformer-d07dd1fbec04) [## 通用语言模型

作为单词嵌入帖子的后续,我们将讨论学习上下文化单词向量的模型,以及…

lilianweng.github.io](https://lilianweng.github.io/lil-log/2019/01/31/generalized-language-models.html) [## 在深度学习中通过真实世界的应用转移学习的综合实践指南

用知识转移的力量进行深度学习!

towardsdatascience.com](/a-comprehensive-hands-on-guide-to-transfer-learning-with-real-world-applications-in-deep-learning-212bf3b2f27a)

从 XML 到 Excel 进行数据分析

原文:https://towardsdatascience.com/from-xml-to-excel-for-data-analysis-ac0c0c765b7d?source=collection_archive---------5-----------------------

Python 中处理 XML 的介绍

根据您的角色和公司,有时您可能需要使用 XML。在本文中,我们将探讨如何利用 Python 来帮助您以一种使您能够进行分析的方式提取和形成数据。

XML 代表可扩展标记语言,它是一种主要用于存储和传输数据的语言。这种语言被设计成机器可读和人类可读的形式。这种语言的批评者通常会建议用 JSON 作为替代,这意味着更快的处理速度。

XML 语言由标签、元素和属性组成。理解这些术语以及我们如何使用它们的最好方法是通过例子的使用。

Photo by fabio on Unsplash

Python 中的 XML

当谈到用 Python 处理 XML 时,最流行的库被恰当地命名为 XML。你可以在这里查阅相关文档。如果您访问文档页面,您会发现有几个子模块可用于处理 XML,但出于我们的目的,我们将只使用XML . etree . element tree

XML 速成班

首先,让我们复习一下 XML 知识。让我们看看以下情况:

<catalog>
 <product description="Cardigan Sweater">
  <catalog_item gender="Men's">
   <item_number>QWZ5671</item_number>
   <price>39.95</price>
  </catalog_item>
 </product>
<catalog>

在上面的示例中,我们注意到以下情况:

  • 根元素是 catalog,并且只能存在一个
  • 所有标签都区分大小写,并且所有元素都需要有一个结束标签(比如价格)
  • 产品是子元素,目录是子元素,项目编号和价格是子元素。

Python 和 XML

对于我们的例子,我将使用这个样本 XML 文件;唯一的区别是我重复了 product 子元素两次。

Screenshot depicting a part of the sample XML

我们需要做的第一件事是导入库并将 XML 文件读入我们的应用程序:

import xml.etree.ElementTree as ET
#Example XML files:
#   sample2 from:  [https://www.service-architecture.com/articles/object-oriented-databases/xml_file_for_complex_data.html](https://www.service-architecture.com/articles/object-oriented-databases/xml_file_for_complex_data.html)
tree = ET.parse(r'C:\xml\sample2.xml')
root = tree.getroot()
tag = root.tag
att = root.attribprint(root,'\n',tag,'\n',att)

它返回以下内容:

<Element 'catalog' at 0x0093FC60>
 catalog
 {}

因此,我们可以看到如何识别没有属性的根节点。然后,让我们在 XML 树上再往下一层,使用:

for child in root:
    print(child.tag, child.attrib)

它返回:

product {'description': 'Cardigan Sweater', 'product_image': 'cardigan.jpg'}
product {'description': 'Cardigan Sweater', 'product_image': 'cardigan.jpg'}

太好了。我们现在可以识别标签及其属性。如果我们想提取值呢?让我们再深入两层,在那里我们有这样的例子(例如,在 <价格> 元素):

for child in root:
    #print(child.tag, child.attrib)
    for subchild in child:
        #print(subchild.tag, subchild.attrib, subchild.text)
        for subsubchild in subchild:
            print(subsubchild.tag, subsubchild.attrib, subsubchild.text)

给了我们:

item_number {} QWZ5671
price {} 39.95
size {'description': 'Medium'}size {'description': 'Large'}

有了上面的知识,您现在应该能够轻松地浏览 XML 树并提取您想要的任何信息。这个对你帮助不大;但是,当您试图对 XML 树中的数据进行分析时。

Photo by Markus Spiske on Unsplash

将数据展*为 CSV 格式,以便快速分析

在某些情况下,您只需要表格格式的数据,这样您就可以快速得出一些结论。也许您正试图查看特定标记的唯一值,或者您只是试图更好地理解数据。也许你想以你的利益相关者更熟悉的方式展示数据——比 excel 更熟悉的方式。

因此,我们接下来要使用的是 xml.etree.ElementTree python 库的 iter() 方法。这个方法将允许我们迭代每个 XML 元素:

for elem in root.iter():
    print(elem.tag, elem.attrib, elem.text)

如您所料,它会返回如下列表:

catalog {}product {'description': 'Cardigan Sweater', 'product_image': 'cardigan.jpg'}catalog_item {'gender': "Men's"}item_number {} QWZ5671
price {} 39.95
size {'description': 'Medium'}

假设我们想为每个产品(即第一级子产品)创建一行,我们可以使用以下脚本:

import xml.etree.ElementTree as ETtree = ET.parse(r'pathToXML')
root = tree.getroot()
tag = root.tag
att = root.attrib#Flatten XML to CSV
for child in root:
    mainlevel = child.tag
    xmltocsv = ''
    for elem in root.iter():
        if elem.tag == root.tag:
            continue
        if elem.tag == mainlevel:
            xmltocsv = xmltocsv + '\n'
        xmltocsv = xmltocsv + str(elem.tag).rstrip() + str(elem.attrib).rstrip() + ';' + str(elem.text).rstrip() + ';'print(xmltocsv)

我们可以用 Excel 打开哪个文件:

Part of the data as shown in Excel

这里值得注意的是,对于要对齐的数据(每行之间),假设每个子节点都有所有 XML 属性。如果不是这样,那么可能需要对数据进行一些清理。

我希望你觉得这是有用的。

如果您喜欢这篇文章,您可能也会喜欢:

[## 如何用 Python 从图像中提取文本

学习用 3 行代码从图像中提取文本

towardsdatascience.com](/how-to-extract-text-from-images-with-python-db9b87fe432b) [## 如何从 PDF 中提取文本

学习使用 Python 从 pdf 中提取文本

towardsdatascience.com](/how-to-extract-text-from-pdf-245482a96de7)

从零到旗杆英雄

原文:https://towardsdatascience.com/from-zero-to-flagpole-hero-ead14fc46fba?source=collection_archive---------21-----------------------

我是如何从一个强化学习新手到在两周内从零开始编写一个 AI,并在《新超级马里奥兄弟》中以 1 比 1 击败世界的。

Can computers learn to control the famous Italian plumber?

没有 I/O 就拼不出马里奥

两周前,我还是强化学习的新手。我不是在说“你什么都不知道,琼恩·雪诺”对这个问题的无知程度,而是理解尝试一个行动、获得奖励和把那个事件记在记忆中的基本原则是关于我在这个问题上的知识程度。概念性的想法是很棒的,但是我完全不知道如何将这些想法编码并写出实际可行的东西。快进两个星期,我写了一个程序,看到马里奥成功地到达了第一关的旗杆。你问我是怎么做到的?好吧,继续读下去找出答案吧!

然而,在深入本文之前,我应该指出,虽然我的目的是帮助其他人学习,以便他们可以自己构建强化学习应用程序,但我将而不是深入描述我在本文中的工作所涉及的代码或理论。我的计划是写后续文章,描述实际的代码以及我以后如何设计它。话虽如此,我相信在潜入 AI 时最好退一步,先学习如何学习。在这篇文章中,我希望传达一个对我来说成功的过程。

Photo by Ray Hennessy on Unsplash

学习爬行

你可能在生活中的某个时候听说过这句话“在你会走路之前,你需要先学会爬”。这个令人谦卑的表达提醒我们,无论我们是谁,来自哪里,在学会走路之前,我们都必须学会如何爬行。这也给我们上了一课,如果不先了解领域的基本基础,我们没有人能立即掌握一个给定的任务或主题。人工智能当然没有什么不同,因为期望某人在几个小时后或仅仅阅读一篇文章后立即成为该领域的专家是令人愤慨的。为了很好地掌握人工智能,一个人必须学习核心基础知识才能成功。

说到强化学习,我也没什么不同。没有人工智能的高级学位,也没有 20 多年的实践经验,我不得不从头开始理解什么是超越我的基本背景的强化学习。

“看一看,在一本书里!”

我生活中的许多讽刺之一是,我实际上是一个糟糕的读者,尽管经常阅读和半频繁地给一个大型博客网站投稿。不要误解我的意思,我可以读得很好,但是我读的速度相对较慢,而且经常会分心,很难带着新的概念离开。

尽管有这个限制,我还是选择通过阅读一些书籍来完成我的旅程。幸运的是,我的雇主是 O'Reilly Learning(以前的 Safari 在线图书)的合作伙伴,所以我可以“免费”访问他们的完整图书馆。如果你以前没有听说过他们,我鼓励你去看看他们,因为他们有很多很好的资源,尤其是对那些在技术领域工作的人来说。

我拿起的第一本书是 Praveen Palanisamy 写的《开放健身房的智能代理》,你可以在 O'Reilly Learning 或者任何你能买到 O'Reilly 书籍的地方找到。

我之所以选择这本书,是因为它关注我在工作中使用的 PyTorch,而且正如它的名字所暗示的,它还承诺了一种实践方法。我发现,当我真正动手做代码而不是纯粹阅读没有任何实际例子的理论片段时,我学得最好。在不把这变成一个完整的书评的情况下,我推荐这本书给任何想要深入强化学习的人。特别是前半部分在分解强化的关键原则方面做得很好,比如解释关键术语,给出简单的例子,以及演示如何实际配置一个环境。

在读完这本书的前半部分后,我觉得我对强化是如何在基础水*上学习的有了很好的理解,并对我如何编写一个能够学习玩并最终独自打败一个游戏的程序有了一些想法。有了这个新发现的知识,我决定下一步应该对它进行测试。

Work up a sweat in OpenAI’s Gym! Photo by Alora Griffiths on Unsplash

你举起过兄弟吗?

埃隆马斯克(Elon Musk)几年前共同创立的人工智能研究公司 OpenAI 开发了一种强化学习模型和技术的通用基准,称为健身房。这个工具提供了几十个独特的环境,开发人员和研究人员可以使用这些环境快速轻松地迭代特定的模型,而无需担心配置测试套件。这不仅加快了测试和开发过程,还为团队、组织和世界各地的开发人员和研究人员提供了重复工作的标准。有了一个共同的测试环境,我们可以开始在各种模型之间进行比较,以确定哪些模型可以在特定的游戏中获得更高的分数,或者可以适应各种各样的游戏,甚至比同行更快地收敛。

我提到的环境大多是一系列迷你游戏,每个都有自己的一套规则、边界、奖励和成功标准。Gym 甚至支持为 Atari 2600 制作的游戏,如 Pong、Breakout 和 Ms. Pacman,允许开发人员在真实的视频游戏中轻松测试他们的模型。

从我读过的书中获得一些经验后,我决定创建一个简单的 Q-Learning 模型来试试运气,它可以解决一些更琐碎的健身房环境,例如 CartPole-v0MountainCar-v0 ,这两个都是 OpenAI 团队开发的,是进入该领域的一个很好的切入点。幸运的是,我所读的这本书提供了一个很好的例子,它创建了一个 Q 学习模型来解决 MountainCar-v0 问题,该模型在几分钟内就成功地收敛了。由于 Q-Learning 模型和 Gym 的灵活性,我还能够在 CartPole-v0 上测试该算法,而只需更改一行代码。

虽然这些演示看起来很酷,但我知道它不可扩展,因为我没有使用任何深度学习技术,而且我直接读取内部环境的状态,而不是读取原始图像。这感觉像是作弊,因为模型能够获得人类玩家无法获得的环境信息(如位置、速度和角度)。在看到书中和网上的许多例子后,我修改了代码,使用深度 Q 网络(DQN)并利用卷积来处理屏幕上的实际图像,而不是读取魔法状态。通过这种方式,模型将像人类一样学习玩游戏,通过阅读屏幕,提供动作,并重复响应该动作的结果,直到满足结束标准。

有了这个新模型,与我以前的简单 Q 学习模型相比,我能够更快地解决 CartPole-v0 和 MountainCar-v0,并且在收敛后也获得了更高的分数。虽然这很令人兴奋,但这些环境在逻辑上很简单,因为可能的状态相对较少,并且动作空间也很小,因为在这两种情况下,您都可以向左、向右或原地不动。因此,我想在一个更复杂的环境中测试这些模型,然后再尝试我的最终目标——训练马里奥超越一个等级。幸运的是,我前面提到的 Atari 环境是测试具有更复杂规则集的游戏模型的极好的沙箱。

让我最初感到惊讶的是,在不改变我正在使用的任何核心代码的情况下,我能够将我的模型部署到几个 Atari 游戏中,并且它们成功地融合到一个点上,在这个点上它们能够掌握一个游戏,例如持续地以 21 比 0 赢得一场 Pong 游戏。

My trained model on the right easily beating the CPU.

事实上,我的代码能够以非常小的修改击败这些游戏,这是对最初的 DQN 模型的健壮性的一个证明。很快变得很明显,该模型将能够适应各种环境,并学习如何正确处理它们。

作为一名专业的软件工程师,我在 GitHub 上创建了一个存储库,其中包含我用来训练我的模型击败 Pong 和其他 Atari 游戏的所有代码,并包括几个参数,以便在不修改任何代码的情况下轻松测试变化并适应新环境。想亲自尝试一下吗?查看以下链接了解更多详情。

[## roclark/openai-gym-pytorch

OpenAI 的 Gym 是一个开源工具包,包含几个环境,可以用来比较强化…

github.com](https://github.com/roclark/openai-gym-pytorch)

我连续解决了多个游戏,但没有为新的场景定制我的软件,但我仍然有一个迫切的问题——人工智能真的可以学习如何在马里奥中击败一个级别吗?

The Mushroom Kingdom is a dangerous place! Photo by Florian van Duyn on Unsplash

蘑菇王国的审判

对于那些还在阅读的人来说,我上面提出的问题的答案显然是“是”,因为如果一切都悲惨地失败了,我就不会发表这篇文章。

Gym 本身不支持 NES 的游戏,所以我必须为超级马里奥兄弟设置一个环境,以便测试我的模型。幸运的是,GitHub 上的一些优秀的人已经创建了gym-super-mario-bros(可从 PyPI 获得),它为我们处理一切,允许我们只需几行代码就可以设置我们的环境,就像其他受支持的健身房环境一样。

设置好一切后,我运行了我在 Atari 游戏中使用的代码,但目标是超级马里奥兄弟的第一关……什么也没发生。我等了一个小时,但马里奥只知道他会被关卡中的第一个古姆巴杀死,他通常不喜欢被杀死,所以更好的策略是站在原地,安全地等待时间结束。

显然,这不是我想要发生的,因为我希望马里奥能够完成这个级别,所以它回到了绘图板。

与任何数据科学项目一样,首先了解您试图解决的问题是什么,包括任何成功标准和限制,这一点至关重要。当我试图在没有真正思考问题的情况下解决马里奥时,我的兴奋占据了我的全部。

以今天的标准来看,Mario 和 Atari 游戏的复杂性都被认为是极其简单的,所以我天真地认为这个模型可以轻松处理这两种情况。然而,退一步讲,考虑到可能遇到的各种状态,很明显马里奥比像 Pong 这样的游戏复杂几个数量级。有了 Pong,你就有了上下移动的两个球拍和一个在屏幕上浮动的球。一个神经网络真的只需要学习如何上下移动并理解击球是好的,让它在你身后漂浮是坏的,同时也只需要担心单一的屏幕。然而,对于马里奥,你一次只能看到关卡的一小部分,还有许多不同的物体和敌人需要他去正确地研究和理解。

如果你回想一下你第一次玩马里奥的时候,你是否直觉地知道古姆巴和库帕斯是坏的,蘑菇是好的,曲管可以通向新的地方,同时也会产生敌人,问号可以提供能量和硬币?如果是这样,你比我小时候第一次玩这个游戏时要聪明得多。不过,你很可能没有立即知道所有这些信息。就像我们这些凡人不理解马里奥在蘑菇王国的旅程中遇到的一切一样,我的 DQN 也没有学会如何正确地通过关卡。

因为我发现这通常是强化学习中最棘手的部分,所以我必须为马里奥定制一个奖励系统,这样他才能积极地对环境做出反应。为了做到这一点,我不得不再次考虑如何完成这个关卡。我通常喜欢尽可能快地到达终点,同时踩死敌人,获得能量,收集硬币,如果他们方便接*的话,否则就不打扰了。当然,我也想不惜一切代价避免死亡,因为那只会让我从头开始。基于这种理解,我创建了一个定制的奖励系统,当马里奥到达旗帜时,它会给马里奥一堆额外的分数,他向右移动得越快(接*关卡末尾),他得到的分数就越多。每当他被击中、死亡或时间耗尽时,我都会扣他几分,鼓励他避免这些情况。

在添加了我的自定义奖励后,是第二轮的时候了!我开始写剧本,但…还是一无所获。我看着马里奥一次又一次悲惨地失败。在经历了似乎永无止境的挫折后,我终于看到马里奥踩在了他的第一个古姆巴上,并第一次继续这个水*。也许,只是也许我是对的东西,我缺乏耐心需要在这里退居二线。

在让马里奥跑了一整夜(部分是双关语)后,我醒来时发现了一个美丽的地方:

My computer showing me how it’s done.

他做到了!他不仅学会了如何通过关卡,还想出了几个技巧,使他在一路上踩着 Goombas 时比我完成得更快。虽然我对结果非常激动,但我也突然意识到,我很可能永远不会如此擅长击败游戏。但是,看着马里奥毫不费力地再次通过关卡,我的悲伤很快就消失了,因为我知道我完成了我的一个目标。

Photo by Aditya Chinchure on Unsplash

“你们都给我收回去!”

在结束之前,我想快速总结一下我的旅程,并提供一些额外的资源。

简单回顾一下,在两周的时间里,我从强化学习的完全新手变成了从零开始编写程序,解决了超级马里奥兄弟的第一关。对我来说,阅读一本书证明是至关重要的,因为它帮助我快速理解强化学习的核心概念,并使我能够应用它们。我个人觉得阅读是一个经常被忽视的知识来源,它对理解一个新的主题有很大的帮助,尤其是在我们被技术包围的时代。

在读完这本书(或者更确切地说,是前半部分)后,我将我的知识用于测试,并创建了实际实现我所读到的主题的程序。正如阅读对于理解一个新话题至关重要一样,实际动手尝试是真正巩固知识的唯一途径。

最后,抓住机会!如果你有一个你正在追逐的目标,那就去追求它吧!准备总是至关重要的,但最终你必须尝试,从经验中学习最终只会有所帮助。

当然,因为我在上面贴了我的 Atari 库的链接,所以我也在这里提供我的 Mario 库的链接才公*。请随意看看,甚至帮我解决一些更具挑战性的水*,在我寻求击败整个游戏使用强化学习。您可以在下面找到存储库:

[## 罗克拉克/超级马里奥兄弟-dqn

一个强化学习项目,旨在学习和完成原来的任天堂超级马里奥兄弟…

github.com](https://github.com/roclark/super-mario-bros-dqn)

正如在开始时提到的,我将在以后的文章中提供更多的细节,告诉那些感兴趣的人我是如何在更高的技术层面上实现这个程序的,敬请关注!否则,去跳,跳过,跳进强化学习的新冒险!哇哦!

XGBoost 调优从零到英雄

原文:https://towardsdatascience.com/from-zero-to-hero-in-xgboost-tuning-e48b59bfaf58?source=collection_archive---------1-----------------------

走过一些最常见的(也不太常见!)XGBoost 的超参数

Boosted Trees by Chen Shikun.

XGBoost 或极端梯度增强是梯度增强算法的优化实现。自 2014 年推出以来,XGBoost 因其预测性能和处理时间而成为机器学习黑客马拉松和竞赛的宠儿。

这一切都始于助推…

增强是一种合奏技术。集成学习借鉴了孔多塞的陪审团定理和群体智慧的思想。因此,集成技术结合了不同模型的结果,以提高整体结果和性能

多数票正确分类的概率比任何人(模型)都高,随着人(模型)的数量变大,多数票的准确率接* 100% — Scott Page,模型思考者。

在基于决策树的机器学习中,Boosting 算法实现了一个顺序过程,其中每个模型都试图纠正以前模型的错误。这个想法是将许多弱学习者转化为一个强学习者。梯度推进采用梯度下降算法来最小化顺序模型中的误差。梯度推进的主要低效之处在于它一次只创建一个决策树。

为了克服这一点,陈天奇和卡洛斯·盖斯特林建立了一个可扩展的树增强系统。它具有并行树构建、缓存感知访问、稀疏感知、正则化和加权分位数草图,作为其系统优化和算法增强的一部分。

如有疑问,请使用欧文·张的智慧之言。

为了向您介绍 XGBoost 及其超参数,我们将使用时尚 MNIST 数据集构建一个简单的分类模型。

预处理数据

时尚 MNIST 数据集由与 10 个分类标签相关联的 60,000 幅 28x28 灰度图像的训练集和 10,000 幅图像的测试集组成。标签如下:

  • 0 T 恤/上衣
  • 1 条裤子
  • 2 件套头衫
  • 3 连衣裙
  • 4 件外套
  • 5 凉鞋
  • 6 衬衫
  • 7 运动鞋
  • 8 袋
  • 9 踝靴

让我们来看看第一个和最后一个图像。

数据集中的每个实例(图像)有 784 个特征(每个像素一个),每个特征中的值范围从 0 到 255,因此我们将使用 Scikit-Learn 的 [StandardScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html)将这些值重新调整到一个更小的范围,*均值为零,单位方差。

基线模型

我们将使用一个[XGBoostClassifier](https://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.sklearn)来预测给定图像的标签。建造一个[XGBoostClassifier](https://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.sklearn)非常简单。我们将从一个简单的基线模型开始,然后继续前进。

对于第一次迭代,我们将只指定一个超参数:objective,并将其设置为“multi:softmax”objective是学习任务超参数的一部分,它指定了要使用的学习任务(回归、分类、排序等)和函数。

让我们回顾一下。什么是超参数?-它们是在训练模型之前初始化的参数,因为它们无法从算法中学习。它们控制定型算法的行为,并对模型的性能有很大影响。典型的比喻是这样的:超参数是人们用来调整机器学习模型的旋钮。它们对于优化和改进评估指标是必不可少的。

现在,让我们看看我们的模型和结果。

Training F1 Micro Average:  0.8794833333333333
Test F1 Micro Average:  0.8674
Test Accuracy:  0.8674

不算太寒酸!但是我们可以通过一些调整和旋钮转动来尝试打破这些最初的分数。

像老板一样调音!

XGBoost 的最大优势之一是可定制的程度,一个令人生畏的长列表,您可以调整这些参数,它们主要是为了防止过度调整。

在这种情况下,最重要的问题是调整什么以及如何调整?对于什么是理想的超参数没有基准,因为这些将取决于您的具体问题、您的数据和您优化的目标。但是一旦你理解了甚至是最模糊的超参数的概念,你就可以像老板一样调优了

为了找到我们的最佳超参数,我们可以使用 Scikit-Learn 的或[GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)。两者之间的区别是分别在较低的运行时间和更好的性能之间进行权衡。考虑数据集的大小[RandomizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)是这一次要走的路。

我们首先创建一个[XGBClassifier](https://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.sklearn)对象,就像基线模型一样,除了objective之外,我们还直接传递超参数tree_methodpredictorverbosityeval_metric,而不是通过参数网格。前两个允许我们直接访问 GPU 功能,verbosity让我们实时了解模型正在运行什么,eval_metric是用于验证数据的评估指标——如您所见,您可以以Python list的形式传递多个评估指标。

不幸的是,使用tree_methodpredictor我们不断得到同样的错误。您可以在此处跟踪该错误的状态。

Kernel error:
In: /workspace/include/xgboost/./../../src/common/span.h, 	line: 489
	T &xgboost::common::Span<T, Extent>::operator[](long) const [with T = xgboost::detail::GradientPairInternal<float>, Extent = -1L]
	Expecting: _idx >= 0 && _idx < size()
terminate called after throwing an instance of 'thrust::system::system_error'
  what():  function_attributes(): after cudaFuncGetAttributes: unspecified launch failure

鉴于我们无法修复根本问题(双关语为),该模型必须在 CPU 上运行。所以我们的[RandomizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)的最终代码看起来像这样:

[RandomizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)允许我们从参数网格给出的选项中找到超参数的最佳组合。然后我们可以通过model_xgboost.best_estimator_.get_params()访问它们,这样我们就可以在模型的下一次迭代中使用它们。下面是这个模型的最佳估计。

Learning Rate: 0.1
Gamma: 0.1
Max Depth: 4
Subsample: 0.7
Max Features at Split: 1
Alpha: 0
Lambda: 1
Minimum Sum of the Instance Weight Hessian to Make Child: 7
Number of Trees: 100
Accuracy Score: 0.883

我们的准确率提高了 2%!对于一个运行了 60 多个小时的模型来说,这已经不错了!

现在,让我们单独看看每个超参数。

  • 首先,让我们澄清一下这个学习率和梯度下降中的学习率是不一样的。在梯度推进的情况下,学习率意味着 减少每个附加树对模型的影响。在他们的论文A Scalable Tree Boosting SystemTianchi Chen 和 Carlos Guestrin 将这种正则化技术称为收缩,它是一种防止过拟合的附加方法。学习率越低,模型在防止过度拟合方面就越稳健。
  • gamma:数学上,这被称为拉格朗日乘数,其目的是控制复杂度。它是损失函数的伪正则项;它代表在考虑分割时,为了使分割发生,损失必须减少多少。**
  • max_depth:指一棵树的深度。它设置了在根和最远的叶子之间可以存在的最大节点数。请记住,较深的树容易过度拟合。
  • colsample_bytreee:表示在构建每棵树时要考虑的列(特性)的一部分,因此它在构建每棵树时出现一次。在陈天琦和 Carlos Guestrin 的论文 中提到了一种可扩展的树提升系统 ,作为防止过拟合和提高计算速度的另一种主要技术。
  • subsample:表示在构建每个子树时要考虑的行(观察值)的一部分。陈天琦和卡洛斯·盖斯特林在他们的论文 中提出了一种可扩展的树提升系统 推荐colsample_bytree而不是subsample来防止过拟合,因为他们发现前者在这方面更有效。
  • reg_alpha : L1 正则项。L1 正则化鼓励稀疏性(意味着将权重拉至 0)。当objective是逻辑回归时,它会更有用,因为您可能需要在特征选择方面得到帮助。
  • reg_lambda : L2 正则项。L2 鼓励更小的权重,这种方法在树模型中更有用,在树模型中归零特性可能没有太大意义。
  • min_child_weight:类似于gamma,因为它在分割步骤执行规则化。这是创建一个新节点所需的最小 Hessian 权重。黑森是二阶导数。
  • n_estimators:适合的树数。

The Ugly Truth

但是等等!还有更多。根据您试图解决的问题或您试图优化的内容,您还可以修改其他超参数:

  • booster:允许您选择使用哪个助推器:gbtreegblineardart。我们一直在使用gbtree,但是dartgblinear也有它们自己额外的超参数需要探索。
  • scale_pos_weight:正负权重之间的*衡,在数据呈现高等级不*衡的情况下绝对应该使用。
  • importance_type:指[feature_importances_](https://datascience.stackexchange.com/questions/12318/how-do-i-interpret-the-output-of-xgboost-importance) 方法要使用的特征重要性类型。gain计算一个特征对模型中所有树的相对贡献(相对增益越高,该特征越相关)。cover当用于决定叶节点时,计算与特征相关的观察值的相对数量。weight测量某个特征被用于在模型的所有树上分割数据的相对次数。
  • base_score:全局偏差。这个参数在处理高等级不*衡时很有用。
  • max_delta_step:设置重量的最大可能绝对值。在处理不*衡的类时也很有用。

****注意:我们使用 Scikit-Learn 包装器接口为 XGBoost 执行了[RandomizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)

接下来是什么

一旦你有了模型的最佳估值器,你就可以做许多不同的事情。我建议将它们用作 XGBoost 内置交叉验证的超参数,这样您就可以利用early_stopping_rounds功能——这是优化和防止过度拟合的又一步。但那是以后的事了!

从零到一

原文:https://towardsdatascience.com/from-zero-to-one-9b1926b7d7f6?source=collection_archive---------22-----------------------

开始一个新的 Python ML 项目

首先,我想宣布我将制作一部关于构建信用卡交易欺诈模型的新视频系列,作为 IEEE-CIS 欺诈检测 Kaggle 竞赛的一部分。

这将主要是我从零开始构建东西的截屏。这一挑战之旅将被用作探索各种建模技术和数据科学实践的背景。

设置新项目

首先,我想制作一个简短的视频,介绍我如何为一个全新的项目设置环境。有时候,观察某人是如何完成任务的是很有帮助的——尤其是那些被认为是理所当然的、不经常讨论的任务。也许你会学到新的技巧。如果你做得更好,请在评论中分享!

【https://blog.zakjost.com】原载于

利用 OpenCV、Tensorflow 和 Fastai,在五个月内从零到实时手关键点检测

原文:https://towardsdatascience.com/from-zero-to-real-time-hand-keypoints-detection-in-five-months-with-opencv-tensorflow-and-fastai-f98e87221475?source=collection_archive---------12-----------------------

在这篇文章中,我将一步一步地向你展示如何用 OpenCV、Tensorflow 和 Fastai (Python 3.7)构建你自己的实时手部关键点检测器。在为期 5 个月的精彩旅程中,我将专注于我在建造它时所面临的挑战。

你可以在这里看到这些模型:

The light green box detects the hand on the image, then i crop around the image by connecting the magenta dots before feeding a CNN for hand keypoints detection

动机:

这一切都始于对理解人工智能核心动态的难以置信的痴迷。五个月前,我在谷歌上搜索了“人工智能 vs 机器学习 vs 深度学习”,这是我第一次试图抓住不同概念之间的细微差别😊。

在查看了多个视频和文章后,我决定从计算机视觉开始,使用移动相机开发自己的手部关键点检测器。

我知道人脑只需要 20 瓦的能量就能运作,我的目标一直是保持事物的简单性,尽可能降低任何模型的计算要求。复杂的事物需要复杂的微积分,而复杂的微积分本身是高度耗能的。

简单说说我的学习曲线:

我有土木工程的学术背景,有一些 visual basic 的编码技能。毕业后一直在金融领域工作。

很不一般,我是从学习 Javascript ( ex1 , ex2 )开始我的旅程的。这帮助我理解了代码背后的一般逻辑,当我后来开始学习 Python & Django 时,这当然很有用。

在密集编码的三个半月之后,我开始了吴恩达机器学习课程,同时阅读了成百上千的文章。通过从头开始构建我自己的人工神经网络,并对传播和反向传播进行编码,理解所有的机制是很重要的。

管道:

我用相机检测手部关键点的过程遵循以下架构:

pipline for hand keypoints detection

⁃的图像被摄像机捕捉到;

⁃第一深度学习模型检测图像上的手,并估计其周围方框的坐标(通过重新训练手检测上的 tensorflow 对象检测 API 模型来完成,您也可以通过构建定制的深度学习模型来实现);

⁃第二个深度学习回归模型采用盒子内部的图像,并估计所有手部关键点的坐标(通过用定制的头部微调 resnet34 来实现)。

手检测:

对于这一部分,我决定在 hand 数据集上重新训练 tensorflow 的对象检测模型(在 COCO 数据集上训练)。为了速度,我选择了 MobileNet_v2。

这部分我就不细说了。你可以从公共资源中找到很多教程。

如果您使用 Open Image dataset,我已经编写了一个自定义脚本来将数据转换为所需的格式:

我花了大约 6 个小时重新训练模型。

关键点检测:

在坚持使用 Fastai 之前,我尝试了不同的方法:

1-我第一次尝试使用 Keras 和 Tensorflow,但在早期阶段面临着数据扩充的挑战。我别无选择,只能使用 Tensorpack(一种低级 api)用 Python 实现自己的数据扩充,这相当复杂,因为我必须执行大量的转换(缩放、裁剪、拉伸、闪电和旋转)…并且因为所有的图像转换都必须影响以 Json 或 Csv 格式存储的坐标。

2-第二种方法是在灰度图像上画出与每只手相关的坐标位置(参见下面的蒙版图),并使用 Keras 的 DataImageGenerator 对图像及其相应的蒙版进行数据扩充。就指标(损失和准确性)而言,该模型表现良好,但预测是混乱的。我想不出哪里出了问题,于是采取了不同的方法。Keras 是一个很好的 API,但是在我的例子中很难调试。

Hand keypoints mask (grayscale image)

3-下一步证明是成功的。看了 Fastai,决定试一试。Fastai 的第一个优势在于您可以调试所有代码。第二个优点是坐标扩充是库核心开发的一部分。

我按照的第一课教程来习惯它,并立即开始在 Jupyter 笔记本上实现我的代码。

关于 Fastai 和 Pytorch 最有趣的事情是整个代码总结成下面的脚本(简单,对吧😊!):

在执行了“learn.lr_find()”和“learn.recorder.plot()”之后,为了确定最优的学习速率,我在不同的周期内总共运行了 3 天代码(在一个 CPU 上!).

最后一个循环“learn.fit_one_cycle(36,slice(6e-3))”以以下结果结束:

要对单个图像进行预测,请使用以下代码之一:

img = im . open _ image(' path _ to/hand _ image . png ')

preds = learn . predict(img)

img.show(y=preds[0])

或者:

img = im . open _ image(' path _ to/hand _ image . png ')

preds = learn . predict(img)

preds = preds[1]+torch . ones(21,2) #反规格化

preds=torch.mm(preds,torch.tensor([[img.size[0]/2,0],

[0,img.size[1]/2]],dtype=torch.float))

预测值=图像点(流场(图像大小,预测值))

img.show(y=preds)

推理和可视化:

使用 learn.export()导出模型用于推理。您应该注意到 Fastai 在导出整形函数和自定义损失类时失败。在调用模型进行推理之前,应该将这些合并到您的脚本中。

要绘制关键点,您需要将以下内容添加到可视化代码中:

首先:

learn = load _ learner(' path _ to _ export . pkl ')#加载之前用 learn.export()保存的推理模型

然后:

我该何去何从?

1-我想利用深度学习开发一个股票交易模型。我在过去开发了几个定量模型,它们实现起来冗长而复杂。现在我很好奇通过 DL 看市场是什么样子的。

2-此外,我想在计算机视觉和增强现实的交叉点上推出一些有趣的端到端 ios 应用程序。

感谢您的关注。

如果你有任何问题,请随时加入我的 linkedin。

中年危机

原文:https://towardsdatascience.com/frostbite-stories-part-1-mount-middle-life-crisis-97df574d58d7?source=collection_archive---------10-----------------------

使用数据科学从喜马拉雅数据库中获得新的见解。谁正在攀登珠穆朗玛峰?

Image by David Mark from Pixabay

你一定听说过今年五月人们在死亡地带排队登上珠穆朗玛峰。Nirmal Purja 的照片引起了媒体的关注,引发了一场关于珠穆朗玛峰如今的情况有多复杂的激烈辩论,不仅仅是因为人群,还有大量没有经验的登山者和不可靠的机构。我自己不是登山运动员,我很好奇:那里怎么会有这么多人?他们是谁?我对这个话题越来越感兴趣,不久之后,通过艾伦·阿内特的优秀的博客,他广泛而频繁地报道喜马拉雅山的登山活动,我了解到了喜马拉雅山数据库。

喜马拉雅山数据库是一个真正独特的项目,它的存在是因为驻加德满都的记者伊丽莎白·霍利的决心,她的雄心是追踪自 1905 年以来喜马拉雅山的所有登山活动。在某种程度上,你可以说,没有她的同意,没有人可以声称他们已经登上了顶峰!虽然她在 2018 年不幸去世,但她已经围绕这个项目聚集了一小群爱好者,他们继续并延伸着她的工作。该数据库定期维护和更新,没有探险队可以不输入他们的详细资料就回家。

该数据库的特色是关于成员——付费登山的人——雇佣的员工——作为夏尔巴人或厨师被付费帮助成员的人,或保护路线的山地工人的数据。该数据库还包含关于所有喜马拉雅山峰的探险详细信息(谁参加了探险、所走的路线、赞助者和机构、伤亡人数、登顶出价、探险终止的原因、作为自由文本的进一步注释……)和参与人员(姓名、年龄、性别、职业、国籍、氧气或其他特殊设备如滑雪板的使用、死亡/受伤……)的信息。这些数据在很大程度上是经过整理的,但不时会有缺失值,因此并非所有经过分析的数字都能 100%地相互交叉核对。虽然数据库已经在夫妇 的 分析中精选,甚至包括整本书、喜马拉雅山的数字、包含各种各样的一般统计数据和故事,我觉得数据科学可以带来更多新的见解(也因为我相信在栏 地块之外的世界)。由于数据库现在可以作为 SQL 文件在网上免费获得,我释放了 Python 等人的力量。在过去的几周里,我一直在这个数据集上进行一次真正迷人的旅行。

对数据库的探索性分析已经做了一些实质性的工作。例如,参见 Alan Arnette 的博客文章、Sandeep Nakarmi 的Power BI dashboard以及可在线访问的两个版本的The Himalaya by Numbers(2007、 2011 )。在这里,我不打算重复这项工作,但建立在他们的见解。

对于讲故事的情况,我将把我的见解作为一系列数据故事发布,敬请关注!

峰会上的高流量是整个十年的问题

为了了解过去几年里峰会上发生了什么,我将所有峰会日绘制成热图,其中一行对应于给定年份的所有峰会,一列对应于特定日期。我从数据库中汇总了所有成功的峰会投标,并用颜色对它们进行了编码——深蓝色表示某一天有更多的人参加。左侧是一个条形图,显示了给定年份中所有成功的峰会投标的总和。右边是一个条形图,记录了顶部至少有一个人的所有天数。

背景说明:一般来说,攀登珠穆朗玛峰的最佳季节是春天。秋天还有一个登顶窗口,但是在商业探险中非常冷门。因此,我将自己的时间限制在 4 月 14 日至 6 月 15 日,因为这涵盖了 1980 年至 2019 年之间的所有峰会日期。2014 年和 2015 年,由于雪崩和地震,登顶次数很少,这使得登顶变得危险甚至无法通行。

It is a calendar, but looks like a Himalayan version of Minesweeper

我们可以在这里看到一些东西。

首先,早在 2003 年,珠穆朗玛峰就出现过超过 100 人登顶的情况,之前的纪录是在 2012 年创下的,当时有 266 人登顶。你还可以看到,2018 年至 2019 年期间,登顶人数没有大幅增加——从很久以前开始就一直在稳步增长,早在 2007 年,人数就超过了 600 人。

然而,2019 年很特别,不仅因为它在 5 月 23 日打破了 357 人登顶的记录(注意,这是-假设 24 小时内稳定人流的不切实际的最佳情况-几乎每小时 15 人,因此全天每 4 分钟就有一个新人!实际上,我们稍后会看到,登山运动员在一天中更短的时间内登顶,这使得交通更加混乱。如果你仔细观察,前一天有 224 人登顶——这意味着那个季节大约 66%的登顶都是在这两天完成的!路透社图形最*发表了一篇优秀的文章,讨论了导致这种结果的气象因素。

让我也简单评论一下其他见解。在 20 世纪 80 年代和 90 年代,不同探险队的登顶尝试遍布整个季节——早在 4 月份就有成功的投标。这些大多是探索性的考察,T2 有时间和资源在那里呆更长时间,尝试一些东西。此外,30 年后,他们无法像我们现在一样获得如此精确的天气预报。现在大多数探险都带有商业性质。他们的参与者通常没有时间来等待几个星期的时间窗口——他们在一年中的最佳时间到达,并试图在第一次机会到来时登顶。此外,他们可能需要依靠所谓的冰医生准备的固定绳索,这些医生是负责路线的山地工人,通常要到五月初才准备好。在这里,您可以从数据中看到总峰值窗口是如何逐年减少的。在过去的几年里,所有的峰会申办都集中在 5 月 10 日到 30 日之间的三周时间内。虽然至少有一次成功登顶的天数多年来比较少,但每个季节大约有 10-15 天,依赖于一个小的可用时间窗口的大群人使这座山更容易受到随机拥挤的影响。2017 年和 2018 年的可用人数和天数非常接*,但由于天气更加稳定和其他一些随机因素,人们更加*等地分配了他们的峰会出价。

在山顶看日出

现在我们知道了大多数人在一年中的哪一天登顶,那么我们能对登顶时间说些什么呢?我过滤了数据库中包含这些信息的记录,并对它们进行了分组,以获得给定年份顶部的*均每小时流量概况。顶部和底部的图表是相关年份的*均值。我还标出了五月的日出和日落时间。

正如我们所看到的,高峰时间已经逐渐转移到一天中更早的时间。25 年前,大多数人在中午时分登顶。*年来,大约 25%的人甚至在太阳升起之前就登顶了,几乎所有的登山者都在下午 12 点离开了峰顶。这意味着大多数在顶端的人在 8-12 小时内出现,这进一步加剧了路线的堵塞。

这不仅是因为登顶者想从世界之巅观看日出。尽早登顶要安全得多。下降通常比上升更困难,因为没有肾上腺素激增,身体会因上升和长时间停留在 8000 米以上的死亡区而变得虚弱。在白天从危险区下降会大大增加在没有任何伤亡的情况下回家的机会。

这种向更早、更安全的登顶时间的整体转变也意味着,在过去的几十年里,登山界积累了大量关于路线和不同安全因素的知识。稍后将详细介绍。

中年富人正涌入这座山

正如我们之前所看到的,这些年来,到达并登顶这座山的成员一直在稳步增加。我想更多地了解这些人是谁。

当然,大多数接*珠穆朗玛峰的登山者被定义为男性(自 1980 年以来稳步下降,目前男性占 80%)。我感兴趣的是它们的年龄以及它是如何随着时间而变化的。因此,我创建了自 1950 年以来每年会员人口的年龄分布图,并将其与时间相对照绘制出来(下图,左边的热图)。我还查看了三个时期的*均人口金字塔:1980-1987 年(所谓的“过渡期”的结束,在喜马拉雅山由数字定义),1988-1995 年(“商业期”开始),以及 2016-2019 年。

我们可以看到,在 20 世纪 80 年代,大多数人的年龄在 30+/-5 岁之间,这是一个人的身体能力与拥有足够的经验、成熟和精神力量来应对登山挑战之间的最佳状态。1990 年代初,移民人数有了相当大的增长,但与 1980 年代相比,同一年龄组的移民分布不太均匀。如果你将它与最* 4 年的人口金字塔进行比较,你会发现*均年龄已经向 40 岁转移。与 20 世纪 80 年代相比,*年来 30 岁左右的人几乎没有变化。大部分增长是由老年人口推动的。自 20 世纪 90 年代以来,这一趋势一直保持稳定,并且在热图上表现为最高年龄不断增加,并且两个年龄组都没有变暗。还要注意最*一个特殊的趋势:登山者试图在 18 岁生日之前或当天攀登珠穆朗玛峰。

为了量化这一趋势,我将人口分为三个主要年龄组:(1)35 岁以下,(2)35-50 岁,(3)50 岁以上。让我们来看看这三个人群自 1980 年以来在两种情况下是如何变化的:到达珠穆朗玛峰的成员(左)和成功登顶的成员(右)。

从 1980 年到 1990 年,所有年龄组的人口数量都在*均增长。自 1990 年以来,随着 35-50 岁的移民数量稳定在每年 250 人左右,50 岁的移民数量开始增加。

所以从绝对数字来看,大部分是中年男人,他们足够富有,能够支付或筹集*均 45 000 美元的探险费用,他们淹没了这座山,也是营地和峰顶附*危险人群的来源。

如今几乎每个人都能登上顶峰

如果你比较上面的两幅图,你会发现在最*几年,登顶的人数实际上与试图攀登的人数相差不远,这与 20 世纪 80 年代的情况形成了鲜明的对比。让我们来看看这三个年龄组在某一年的最高比率。

令人惊讶的是,现在 50 岁以下的人的峰值比率已经高达 80 %, 50 岁以上的人超过了 50%!同样引人入胜的是,自 1990 年以来,峰值利率几乎一直呈线性增长。尽管 35-50 岁的人可能不如年轻成员健康,但他们登顶的比率几乎与 50 岁的人相同,但相差不大,更大的登顶比率差距仅在 2005 年左右出现。

如果像我们倾向于认为的那样,攀登珠穆朗玛峰是一项如此艰难的成就——总而言之,它是世界之巅——那么登顶率为何如此之高?

一件事是,典型的珠穆朗玛峰探险已经从探险性质转变为商业性质。探险队遵循众所周知的、标准化的、安全的路线,有大量关于途中可能遇到的危险和陷阱的知识,登山装备在技术上比 30 年前好很多倍。所有这些都使得体能相对较差的人(虽然,还是有高于*均水*的体能!)和经历才能成功。

但这也有其黑暗的一面:投入大量自己积蓄来追求目标的人更有动力推动登顶,有时会危险地打破安全界限,一些机构和导游不愿意建议不要这样做,或者无法提供足够的支持。也有一群人尝试攀登,不是因为他们是激情或经验的登山者,而是因为一旦他们到达顶峰并返回 T2,他们将获得非常切实的利益:社会认可、经济奖励、荣誉和奖牌。

众所周知,没有经验的登山者在很大程度上是由他们的夏尔巴人照看的,直到登顶并返回 T4。它实际上反映在数据中,为了定性地说明这一点,我设计了一个可视化工具,从全球角度看夏尔巴人与成员的比例,以及他们在不同年份的峰会出价。

这里一行是一个单独的探险队,一个正方形代表属于这个探险队的一个人。中间的黑线将至少有一人成功登顶的探险队与从未登顶的探险队区分开来。一个登顶的人被涂上了更深的颜色。成员以蓝色阴影显示,位于每个金字塔的右侧。他们雇佣的员工——左边,灰色的。

我们可以看到,直到 2005 年,大约一半的探险队根本没有登顶,而在那些成功登顶的探险队中,大部分都是队员独自成功登顶的。探险队也没有像现在一样雇佣那么多夏尔巴人。

自 2005 年以来,到达珠穆朗玛峰的探险队数量越来越少。然而,越来越多的探险队成功登顶。同样显而易见的是,随着时间的推移,越来越多的属于一个探险队的成员到达了顶端。此外,现在大多数探险队都有 ca。成员和雇佣人员之间的比例为 1:1,尽管夏尔巴人比成员多。同样,几乎所有被雇佣的员工都能和他们的成员一起晋升到高层,这在 20 世纪 80 年代、90 年代甚至 21 世纪初都是不可能的。在 2019 年,几乎没有哪个探险队的成员不会在峰顶带上夏尔巴人。

中年危机

那么这一切告诉我们什么呢?

在 20 世纪 80 年代,探险队更具探索性:他们包括更年轻的成员,更少的夏尔巴人,并且在春季分散了几个星期。多亏了这些年的探索,人们在某种程度上知道了如何以正确的方式爬山。因此,探险可能变得更加标准化和商业化。如今,几乎所有的登顶都是在 5 月底的最佳时间,沿着相同的登山路线,包括不是专业登山运动员的老年成员,而且夏尔巴人与探险队成员的比例要大得多。

尽管受到广泛批评的事实是,那里有许多缺乏经验、身体不健康的探险队员,而且许多探险队是由没有适当喜马拉雅专业知识的新机构组织的,但大多数队员都成功登顶,与喜马拉雅其他山峰相比,伤亡率非常低(2019 年 900 人中有 11 人的死亡率为 1.2%)。

一方面,这意味着良好的设备、对路线的了解和良好的规划、足够的雇佣员工和良好的准备可以弥补经验、体能和人群存在的不足。另一方面,尽管珠穆朗玛峰是最高的,而且被媒体认为非常危险,但它现在看起来是一座在技术上相对容易攀登的山峰,而且对于一座 8000 米的山峰来说也是安全的。

登顶的队伍呢?这一分析表明,珠穆朗玛峰上的人群似乎很大一部分是中年富人和他们的高空保姆。但话虽如此,最好记住他们实际上成功到达顶部并返回——这是我,一个久坐不动的数据书呆子,永远无法复制的成就。

下一步是什么?

然而,这并不是结束。在接下来的故事中,我将探讨以下问题:

  • 与新的或经验较少的机构一起攀登更危险吗?他们中谁的伤亡率最大?
  • 现在的伤亡多与经验不足,准备不足有关吗?
  • 先前的喜马拉雅山登山经历如何影响登顶成功?
  • 不同的路线会发生什么?
  • 一些国家比其他国家更有可能成功申办峰会吗?
  • 喜马拉雅山的其他山峰呢?
  • …以及更多—敬请关注!

Waiting to summit on 23.05.2019 — Nirmal Purja

句子嵌入。请快点!

原文:https://towardsdatascience.com/fse-2b1ffa791cf9?source=collection_archive---------3-----------------------

句子嵌入是现代自然语言处理应用中的一个关键因素。使用 Gensim、Cython 和 BLAS 将句子嵌入计算速度提高 38 倍。

Photo by Bernard Hermant on Unsplash

本文中的 fse 代码已弃用。请确保使用Github上概述的更新代码。

介绍

当在机器学习管道中处理文本数据时,您可能会遇到计算句子嵌入的需要。类似于常规的单词嵌入(如 Word2Vec、GloVE、Elmo、Bert 或 Fasttext),句子嵌入将一个完整的句子嵌入到一个向量空间。实际上,一个句子嵌入可能看起来像这样:

《我枪杀了警长》→[0.2;0.1 ;-0.3 ;0.9 ;…]

这些句子嵌入保留了一些好的特性,因为它们继承了潜在单词嵌入的特征[1]。因此,我们可以出于不同的目的使用句子嵌入:

  • 基于句子的嵌入计算句子的相似度矩阵。
  • 用一种普通的绘图技术来画句子,比如 t-SNE。
  • 预测句子的某些值,即情感。

在“深度*均网络”[2]中可以看到一个非常简单的句子嵌入的监督应用,其中作者在情感分析和问题回答中使用句子嵌入。事实上,当你处理文本数据时,句子嵌入是一个看似简单的基线。幸运的是,如果(预训练的)单词嵌入已经可用,它们不需要任何形式的基于梯度的优化。

Photo by Álvaro Serrano on Unsplash

这篇文章的目标读者是技术数据科学受众。我们将探索*滑逆频率(SIF)句子嵌入[1]。具体来说,我们正在通过手工制作一个函数来优化 SIF 嵌入的计算,这个函数是专门为尽快计算 SIF 嵌入而定制的。为此,我们首先使用 Python,然后迁移到 Cython,最后迁移到基本线性代数子程序(BLAS)。Cython 和 BLAS 是 Gensims Word2Vec 实现中使用的核心组件。我必须感谢拉迪姆·řehůřek,因为 Gensims 的实现是这篇文章的基础。对于类似的帖子,请随意阅读原始 Word2Vec 优化博客。下面的优化允许我们将 SIF 嵌入的计算速度提高 38 倍(!)。

SIF 嵌入

*滑逆频率嵌入最初由[1]构思,相应的论文已在 2017 年 ICLR 上发表。原始论文的代码可从 Github 获得。作者为逆频率加权连续词袋模型提出了一个很好的概率动机。我们不讨论数学的技术细节,而是讨论计算 SIF 嵌入的算法的优化。如果您必须计算数百万个句子的 SIF 嵌入,您需要一个例程在一生中完成这项任务。在本帖中,我们只是在寻找速度。Gensim 提供了相当多的信息。

Algorithm to compute the SIF embeddings. Source: [1].

辨别算法,我们可以推断大部分工作将在第 1 & 2 行完成。虽然看起来很简单,但是在使用 Python 时,有足够的空间来优化第 1 行和第 2 行。任务如下:尽可能快地为 brown 语料库中的所有句子计算 SIF 嵌入。我们将依靠 Gensims Word2Vec 实现来获得单词向量,并且只使用一点预处理。

实现

这个项目的全部代码可以在 Github 获得。可以安装我用 pip 写的 快速句子嵌入库 :

pip install fse

您将需要常规的 Python 包,特别是 Numpy、Scipy、Cython 和 Gensim。TL;DR:如果你需要快速的句子嵌入,就用:

from gensim.models import Word2Vec
sentences = [[“cat”, “say”, “meow”], [“dog”, “say”, “woof”]]
model = Word2Vec(sentences, min_count=1)from fse.models import Sentence2Vec
se = Sentence2Vec(model)
sentences_emb = se.train(sentences)

优化

为了优化 SIF 功能,我们首先需要一个能够正常工作的原型。让我们来看看原型:

代码应该是不言自明的。我们首先定义变量 vlookup ,它将我们指向 gensims vocab 类。在此我们可以访问一个单词索引计数Vectors 将我们指向 gensim wv 类,它包含单词 Vectors 本身。然后我们迭代所有的句子。对于每个句子,我们将句子中所有单词的向量相加,同时乘以它们的 SIF 权重。最后,我们用向量除以句子的长度。不要太花哨。

我们需要一个嵌入来度量这个函数的执行时间。让我们使用一个 100 维的 Word2Vec 嵌入,它是在通常可用的 Brown 语料库上训练的。然后我们使用语料库的前 400 个句子,并对函数计时。 5.70 秒

那太慢了。敏锐的眼睛已经注意到了这个缺陷:我在向量加法中使用了 for 循环。这正是在这种情况下不使用 python for-loops 的原因。他们太慢了。为了避免这一点,让我们重写第 37–40 行来使用 numpy 例程。

结果是惊人的: 0.041434 秒。比基准版本快137 倍。然而,我们仍然可以做得更好。好多了。您可能已经注意到,vectors[w]充当单词向量的查找表。如果我们预先计算句子的单词索引,我们可以直接使用 numpy 索引一次访问所有向量,这样要快得多。在同一步骤中,我们必须预先计算向量的 SIF 权重,以便通过索引访问它们。

运行时间为 0.011987 秒,这些小的增加导致该函数比我们建立的基线快476 倍

为了进一步加速实现,我们可能实际上预先计算所有的加权向量,因为权重和单词向量本身不会改变。因此,我们将运行时间减少到 0.008674 秒,比基线增加了**658 倍但是等等。有一个陷阱:

通过预先计算 SIF 向量,我们可能不得不计算一个相当大的矩阵,如果我们只有几个句子和大量的词汇,这不是时间有效的。它也不节省空间,因为我们必须在 RAM 中存储一个单独的加权嵌入矩阵。因此,我们正在内存和时间效率之间进行权衡。只有当句子中用于训练的有效单词数大于词汇量时,预计算加权向量才有意义。

我会稍微破坏一下,声明这是不必要的,因为我们稍后将使用 BLAS 函数,但是现在记住它。

我们已经获得了相当大的加速。我们要优化的下一件事是向量的求和,我们仍然可以获得显著的加速。然而,为了更好地对结果进行基准测试,我们将语句到索引的转换从等式中去掉。因此,我们预计算了以下基准的所有句子索引:

sentences_idx = [np.asarray([int(model.wv.vocab[w].index) for w in s if w in model.wv.vocab], dtype=np.intc) for s in sentences]

你会立即意识到这在实践中是一个非常糟糕的想法,因为我们现在必须存储第二个数据集。然而,目前它很好地服务于我们的基准测试目的。

0.004472 秒的情况下,新函数——使用预先计算的加权向量和句子索引——以基准实现速度的1276 倍计时。然而,由于基线没有使用预先计算的指数,这种比较有些偏离。因此,这是我们目前的新基准。

下一步是迁移到 Cython 。请注意,我们仍然在使用预先计算的指数和加权向量。我们将所有东西包装到一个漂亮的 Cython 文件中,然后编译它。

cdef float[:,:]命令允许我们访问预先计算的向量的内存视图。关于更详细的解释,Cython 网站提供了一个关于内存视图的简洁的教程。记得用

# cython: boundscheck=False
# cython: wraparound=False

在文件的开头。这两个命令移除了安全网,这可能会降低我们的速度。前者检查我们是否超出了数组的边界,而后者允许我们执行负索引(我们不打算使用)。我们现在运行的比之前的纯 numpy 实现快 2.42 倍,后者也依赖于预先计算的句子索引。因此,这种比较又是公*的。

请注意,我们已经将所有必要的结构预定义为 C 变量,我们可以在纯 C 循环中使用它们,而没有任何 Pythonic 干扰。因此,我们也可以释放全局解释器锁( GIL ),当我们考虑 fse 的多线程实现时,这可能会在未来的某个时间点派上用场。我们基本上重写了用于对句子中所有单词求和的代码部分:

因此,我们将运行时间减少到 0.000805 秒,这标志着比第一次 Cython 实现又增加了 2.28 倍

最后,我们将进行爆破。基本线性代数子程序描述低级线性代数例程。它们分为三级:第一级:向量运算,第二级:向量-矩阵运算,第三级:矩阵-矩阵运算。出于我们的目的,我们只需要访问 1 级。确切地说,我们需要:

  • SAXPY : (Single)常量乘以一个向量加上一个向量
  • SSCAL : (Single)用常数缩放一个向量

Gensims 核心类大量使用这些高度优化的例程来加速 Word2Vec、Doc2Vec 和 Fasttext。

现在回想一下我们之前写的关于预计算 SIF 加权向量的内容。SAXPY 函数接受参数 a ,它用在 y = ax + y 中。因此,我们无论如何都要做权重向量乘法。因此,预先计算 SIF 向量实际上毕竟是一个低效的想法。

此外,我们正在放弃 Cython 内存视图,以便通过指针和内存地址直接不安全地访问 numpy 变量。

我们必须在其他地方定义 sscal 和 saxpy 指针,这在代码片段中是多余的(通常在*。pxd 文件)。

我们从这些额外的麻烦中得到了什么?运行时间 0.000267 秒,这再次标志着3.01 倍的增长(!)超过以前的实现。如果我们只看使用预先计算的向量和索引的函数,我们将运行时间从 0.004472 减少到 0.000267 秒,速度增加了16.76 倍。随着我们增加向量和数据的大小,这些值可能会发生显著变化。总的来说,我们将代码的速度提高了 21,400 倍,尽管由于预先计算的不同,这有点像苹果和橘子的比较。

验证&申请

为了测试一切是否正常,我们现在看两个任务:
STS 句子相似性基准[3]和在句子水*上预测情绪[4]。你可以在相应的 Jupyter 笔记本中找到脚本。让我们使用预先训练的 GoogleNews-vectors-negative300 个向量来估计句子嵌入。

预测情绪的 reddit 数据集包含四个类别:令人毛骨悚然、血腥、快乐和愤怒。经过一些预处理后,我们得到了 2460 个句子和所有四种情感类别的*衡。

至于时间:使用我们之前开发的第二个变体计算句子嵌入,每个循环需要大约 991 ms 19.2 ms(*均标准时间。戴夫。7 次运行,每次 1 个循环)。fse.models.Sentence2Vec 中包含的最终实现在每个循环 25.9 ms 615 s 内完成任务(*均标准时间。戴夫。7 次运行,每次 10 个循环),一个38 倍的速度提升和一个公*的比较。

Source: Author.

在预测情绪方面,我们也能够很好地完成任务。注:多项逻辑回归,训练/测试分离 50%。

最后,我们接*句子相似度基准。数据在这里可用。我们只看开发集。最初的论文报道了 71.7 的 spearman 相关性,但是他们使用了手套向量。根据其他基准测试,实现工作正常。

Source: Author.

结论

句子嵌入是自然语言处理流水线的重要组成部分。这篇博文展示了如何实现*均和 SIF 加权 CBOW 嵌入,这可以作为后续任务的良好基线。由于它们的简单性和模块化,我们预计会有各种各样的应用。相应的 fse 包可以在 pip / Github 上获得,它为数据科学家提供了一种快速计算句子嵌入的方法。

如有疑问,欢迎联系 me 。

附加说明

这篇文章的代码可以在 Github 和 pip 上找到:

pip install fse

文学

  1. Arora S,Liang Y,Ma T (2017)一个简单但难以击败的句子嵌入基线。里面的糖膏剂学习。代表。(法国土伦),1-16 岁。
  2. Iyyer M,Manjunatha V,Boyd-Graber J,Daumé III H (2015)深度无序合成与文本分类的句法方法相匹敌。继续。第 53 届 Annu。见面。协会计算机。语言学家。第七国际。Jt。糖膏剂纳特。郎。过程。, 1681–1691.
  3. 埃内科·阿吉雷、丹尼尔·塞尔、莫娜·迪亚卜、伊戈·洛佩兹·加兹皮奥、露西娅·斯佩亚。Semeval-2017 任务 1:语义文本相似度多语种和跨语种聚焦评估。SemEval 2017 会议录。
  4. 杨志成、雷米·勒布雷特和卡尔·阿伯勒。"用于分析社交媒体的多模态分类."2017 年第 27 届欧洲机器学习和数据库知识发现原理与实践会议(ECML-PKDD)

放弃

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。作者对本网站内容的任何错误或遗漏不承担任何责任或义务。本网站包含的信息按“原样”提供,不保证完整性、准确性、有用性或及时性。

为深度学习加油:通过网络抓取创建自定义数据集

原文:https://towardsdatascience.com/fuel-up-the-deep-learning-custom-dataset-creation-with-web-scraping-ba0f44414cf7?source=collection_archive---------12-----------------------

Photo by Dev Leigh on Unsplash

我完全理解了深度学习的一件事。它需要大量的数据才能工作。没有数据,它只是一个高级算法。它不能单独产生任何有意义的输出。

当你从零开始开发深度学习模型时,这一点更加明显。

在上下文中, 开放图像数据集 包含 900 万张已经用图像级标签和对象边界框进行了注释的图像。准备如此庞大的数据集需要付出巨大的努力。

好消息是,你可以根据你的需要用相对较少的数据量 微调一个预训练的模型

在接下来的部分中,我将向您展示如何使用 ScrapyPython 创建这样一个数据集。希望这能帮助你开始你的第一个机器学习项目。

Photo by Jon Tyson on Unsplash

假设您想要开发一个机器学习模型,在提供的图像中检测衣服、鞋子、包和配件。您可能还想开发一个图像相似性模型,根据给定的输入图像为您提供相似衣服的图像。像购物一样,Pinterest、谷歌和许多其他公司提供的 look 功能。

对于这两种情况,您都需要大量与领域相关的图像和数据。网络抓取是一个工具,你可以用来克服这个困难。

Photo by NordWood Themes on Unsplash

让我以一种结构化的方式来解释 web 报废流程,从而一步一步地指导您:

第一步:了解礼貌刮擦的规则

在网络抓取中,你必须遵守几个规则,以免损害网站报废。在考虑网络抓取之前,请花时间去理解这些规则。这里有一个网站用具体的例子来解释它们。

第二步:决定刮哪个网站

这似乎是显而易见的,但这是第一步,其余的很大程度上取决于这一点。在投入时间和精力之前,想想你的兴趣是什么。这将有助于你缩小关注网站的选择范围。

在我的情况下,由于我计划开发时尚的深度学习模型,我将寻找在线购物网站。

我们的数据来源将是服装购物网站,因为我们的领域与时尚有关。所以我决定刮一下 'www2.hm.com/tr_tr ',来演示一下整个刮的过程。

如果你在另一个领域有一个特定的网站,你仍然可以按照这个例子来理解你可以很容易地应用到你的案例中的基础知识。

第三步:了解网站的结构

了解产品如何在 'www2.hm.com/tr_tr' 中列出和分页以加快抓取过程非常重要。在我们的例子中,产品分为女性、男性和儿童。网站上有一些页面,你可以在那里看到特定主要类别的所有产品。因此,我们不必搜索每个子类别,如男士衬衫、男鞋等。

如果你查看那些页面的 Url,你可以看到使用了两个参数: 【偏移量】【页面大小】。 我们将使用 offset 值来浏览产品列表,并使用 page-size 值来定义一页上要列出多少产品。更高的页面大小值需要更少的 Http 请求,因此减少了抓取时间。

https://www2 . hm . com/tr _ tr/erkek/u rune-gore-satin-al/view-all . html?sort = stock&image-size = small&image = model&offset = 0&page-size = 72

第四步:理解 HTML 中的模式

此时,我们应该检查列出了所有商品及其图片、产品名称和价格信息的 Html。

如果我们理解了网站上使用的 Html 和 CSS 模式,那么我们就可以很容易地找到我们想要抓取的部分。

在我们的例子中,您可以在下面的图片中看到,所有的条目都包含在具有“products-listing small”类名的

Inspecting HTML patterns for Web Scrapping

当我们进入具有“product-item”类名的单个

  • 元素的细节时,我们可以看到产品图片链接、产品名称和产品价格信息位于何处。您可以看到页面上显示的每个产品都使用了相同的 Html 模式。

Inspecting HTML patterns for Web Scrapping

步骤 5:构建并运行 Scrapy Spider

假设你的电脑上已经安装并运行了 Python,让我们从安装 Scrapy 开始。

使用您的 shell 终端安装 Scrapy 并生成您的 Scrapy 项目。

我们还需要安装图像库。这是 Scrapy 图像管道所要求的,我们将使用它来下载产品图像。

$ pip install scrapy
$ pip install image
$ scrapy startproject **fashionWebScraping**
$ cd **fashionWebScraping**
$ ls

完成后,您将看到 scrapy.cfg、items.py、pipelines.py、middlewares.py 和 settings.py 文件被填充到文件夹中。一个空的‘蜘蛛’文件夹也出现在项目主文件夹中,用于存储我们的蜘蛛 python 文件。

我们需要修改 settings.pyitems.py 并构建一个蜘蛛 python 文件开始抓取。

建立 Scrapy 项目

为了设置项目,我将修改setting . pyby包括几个行项目来定义图像管道。然后我会改一些基本设置礼貌刮。可以参考 Scrapy 网站了解更多设置。

*BOT_NAME = 'fashionWebScraping'SPIDER_MODULES = ['fashionWebScraping.spiders']
NEWSPIDER_MODULE = 'fashionWebScraping.spiders'**# Crawl responsibly by identifying yourself 
# (and your website) on the user-agent**
USER_AGENT = 'erdemisbilen@gmail.com'**# Obey robots.txt rules**
ROBOTSTXT_OBEY = True**# This to avoid hitting servers too hard**
DOWNLOAD_DELAY = 5**# Configure item pipelines**
ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}
IMAGES_STORE = '/Angular/fashionWebScraping/images_scraped'*

items.py 定义项目

为了定义通用的输出数据格式,Scrapy 提供了[***Item***](https://doc.scrapy.org/en/1.0/topics/items.html#scrapy.item.Item)类。[***Item***](https://doc.scrapy.org/en/1.0/topics/items.html#scrapy.item.Item)对象是用来收集抓取数据的简单容器。

出自scrapy.org

让我们在 items.py 中定义我们的项目:

*import scrapyclass FashionwebscrapingItem(scrapy.Item):**#items to store product details**
  gender=Field()
  productId=Field()
  productName=Field()
  priceOriginal=Field()
  priceSale=Field()**#items to store links**
  imageLink = Field()
  productLink=Field()**#item for company name**
  company = Field()**#items for image pipeline**
  image_urls = scrapy.Field()
  images = scrapy.Field()pass*

编写我们的蜘蛛

蜘蛛是定义如何抓取某个站点(或一组站点)的类,包括如何执行抓取(即跟随链接)以及如何从页面中提取结构化数据(即抓取项目)。换句话说,蜘蛛是为特定站点(或者,在某些情况下,一组站点)定义抓取和解析页面的自定义行为的地方。

出自scrapy.org

***fashionWebScraping $** scrapy genspider fashionHM hm.com
*Created spider 'fashionHM' using template 'basic' in module:
fashionWebScraping.spiders.fashionHM**

上面的 shell 命令创建了一个空的蜘蛛文件。让我们将代码写入我们的 fashionHM.py 文件:

*import scrapy
from fashionWebScraping.items import FashionwebscrapingItem
from scrapy.http import Request**#to read from a csv file**
import csvclass FashionhmSpider(scrapy.Spider):
 name = 'fashionHM'
 allowed_domains = ['www2.hm.com']
 start_urls = ['http://www2.hm.com/']**# This function helps us to scrape the whole content of the website
 # by following the links in a csv file.**
 def start_requests(self):**# Read main category links from a csv file** 
  with open("SpiderMainCategoryLinks.csv", "rU") as f:
   reader=csv.DictReader(f)

   for row in reader:
    url=row['url']**# Change the offset value incrementally 
    # to navigate through the     product list
    # You can play with the range value 
    # according to maximum product quantity
**    link_urls = [url.format(i*100) for i in range(0,1)]

    for link_url in link_urls:
      print(link_url)

 **# Pass the each link containing 100 products, 
      # to parse_product_pages function with the gender metadata**request=Request(link_url, callback=self.parse_product_pages, meta={'gender': row['gender']})
      yield request**# This function scrapes the page with the help of xpath provided**
 def parse_product_pages(self,response):
  item=FashionwebscrapingItem()

 ** # Get the HTML block where all the products are listed
  # <ul> HTML element with the "products-listing small" class name**
  content=response.xpath('//ul[@class="products-listing small"]')

 **# loop through the <li> elements with the 
   # "product-item" class name in the content**
   for product_content in content.xpath('//li[@class="product-item"]'):
    image_urls = []

    **# get the product details and populate the items**
item['productId']=product_content.xpath('.//article[@class="hm-product-item"]/@data-articlecode').extract_first()item['productName']=product_content.xpath('.//a[@class="link"]/text()').extract_first()item['priceOriginal']=product_content.xpath('.//span[@class="price regular"]/text()').extract_first()item['priceSale']=product_content.xpath('.//span[@class="price sale"]/text()').extract_first()if item['priceSale']==None:
      item['priceSale']=item['priceOriginal']item['productLink']="https://www2.hm.com"+product_content.xpath('.//a[@class="link"]/@href').extract_first()item['imageLink']="https:"+product_content.xpath('.//img/@data-src').extract_first()
     image_urls.append(item['imageLink'])
     item['image_urls']=image_urls
     item['company']="H&M"
     item['gender']=response.meta['gender']

     if item['productId']==None: 
      break
     print(item['productId'])

     yield (item)def parse(self, response):
  pass*

首先,从 CSV 文件中读取主类别链接,然后循环使用偏移值遍历链接,以浏览产品列表。

这里的技巧是使用 XPath 来定位我们想要抓取的 Html 部分。剩下的就很简单了。

慢慢来,研究一下 XPath ,因为它是 web 报废的核心主题。它提供了在 HTML 中导航的工具。

运行我们的蜘蛛

***$** scrapy crawl -o rawdata_HM.json -t json fashionHM*

在几分钟内,这一行 shell 命令通过将图像和相关产品数据存储在一个 JSON 文件中,不仅生成了 10K 图像和相关产品数据。

像魔术一样!

结论

我们用 Scrapy 和 Python 经历了网页抓取的过程。如果你是数据科学机器学习爱好者,掌握网页抓取的基础知识会对你有很大帮助。

你可以在我的 GitHub 库中找到项目代码。

下载的服装图像可以用于训练与时尚相关的定制深度学习模型。在培训过程中使用这些图像之前,您可能需要对它们进行预处理和标记。

不幸的是,这是深度学习最耗时和最困难的任务。

我的下一篇文章将详细讨论这个主题。

完整管道项目:用于检测假新闻的 Python AI

原文:https://towardsdatascience.com/full-pipeline-project-python-ai-for-detecting-fake-news-with-nlp-bbb1eec4936d?source=collection_archive---------4-----------------------

太多关于机器学习的文章只关注建模。那些关键的模型构建和验证的中间部分当然值得关注,但是我想要更多——我希望你也一样。我对自己的项目写了一个完整的回顾,包括数据争论、前面提到的模型工作和公共接口的创建。如果你想直接跳到“笑点”,完整的节目可以在https://www.unslanted.net/newsbot/找到。

我一开始的想法是假新闻的措辞与标准新闻截然不同,机器学习可以检测到这种差异。在我自己对假新闻文章的检查中,我发现相对频繁使用的术语似乎是为了激起愤怒。我还发现,这类文章中明显的写作技巧通常比标准新闻中明显的要差得多。有了这些想法,我就有了一些基础,可以开始构建我的模型,将假新闻从其他新闻中分类出来。

为了找出这个假设是否正确,我们首先需要一个客观标记的数据集,它将为我们提供假新闻的例子和由专业事实检查员提供的真实新闻的例子。这些数据需要有指向新闻文章的 URL,以及对该文章的真实性或虚构性的判断。我找到了两个符合这个标准的数据集。第一个是来自广告丰特斯媒体的互动媒体偏见图。你可以访问他们的图表,在这里获得第一个数据集:【https://www.adfontesmedia.com/interactive-media-bias-chart/】T2 我们将使用的另一个数据集是 FakeNewsNet 数据集,在这里可以获得:【https://github.com/KaiDMML/FakeNewsNet】T4。我对数据集做了一些手动更改,以消除 pdf 和任何明显不是 URL 的内容,并通过对 FakeNewsNet 的 politifact_fake.csv 文件中的所有项目给予“假”评级,对 politifact_real.csv 文件中的所有项目给予“真”评级,来标准化评分系统。

一旦我们有了数据集,我们的下一个任务将是把这些数据集组合成一个单一的数据库表,然后我们可以用它来提取我们将要处理的文本。我使用 Django ORM 来管理到数据库的连接。后来,这也使得为我们的模型提供一个公共接口变得更加容易,因为 Django 是一个全功能的 MVC web 框架。通过 manage.py 启动我们的应用程序后,我必须通过 Django.db 模型类创建表:

from django.db import modelsclass ArticleExample(models.Model):
   # This will hold the visible text for this example
   body_text = models.TextField()
   # This bias score is a left-right bias provided by Media Bias
   # Chart, but not used in this project. 
   bias_score = models.FloatField()
   bias_class = models.IntegerField()
   # quality_score comes from the Media Bias Chart data
   quality_score = models.FloatField()
   # quality_class is based on the quality score and allows us to
   # integrate politifact data in their
   # 4-class way, True = 4, Mostly True = 3, Mostly Fake = 2,
   # Fake = 1
   quality_class = models.IntegerField()

   origin_url = models.TextField()
   origin_source = models.TextField()

很简单,对吧?接下来,我们回到 Django 的 manage.py 并运行 makemigrations 和 migrate 来设置我们的数据库。

现在我们必须将数据放入这个表中。这是一个数据争论的过程,也是机器学习中最困难和最耗时的部分之一。在大型 ML 环境中,有些数据工程师除了收集数据集之外,几乎什么也不做。

让我们深入研究这个问题。本质上,我们需要:

  1. 加载我们的网址和分数列表。
  2. 从 URL 加载页面并解析它
  3. 将解析后的版本与分数一起存储
  4. 通过*均分割数据,为任何没有类的数据点添加类。

首先,让我们看看除了解析页面部分之外的所有内容。现在,您只需要知道 SoupStrainer(我们将在一分钟内开发)将为我们处理所有这些。

这个程序的主要部分是 harvester.py。在 harvester 的第一部分,我们必须做一些初始设置,以允许我们的 django 程序从命令行运行,而不是通过 web 界面。

import os, sys, re, timeproj_path = “/home/jwales/eclipse-workspace/crowdnews/”
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “crowdnews.settings”)
sys.path.append(proj_path)
os.chdir(proj_path)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
from django.contrib.gis.views import feed

根据机器上项目路径的具体情况,您的里程会有所不同。接下来,我们需要加载并设置我们的模型和我们的解析器。我们很快会解释这是什么意思,听我说。

import pandas as pd
from newsbot.strainer import *
from newsbot.models import *ss = SoupStrainer()
print(“Initializing dictionary…”)
ss.init()

接下来,我们使用以下方法加载从 Politifact 获得的数据:

def harvest_Politifact_data():
   print(“Ready to harvest Politifact data.”)
   input(“[Enter to continue, Ctl+C to cancel]>>”)
   print(“Reading URLs file”) # Read the data file into a pandas dataframe
   df_csv = pd.read_csv(“newsbot/politifact_data.csv”,
   error_bad_lines=False, quotechar=’”’, thousands=’,’,
   low_memory=False) for index, row in df_csv.iterrows():
      print(“Attempting URL: “ + row[‘news_url’])
      if(ss.loadAddress(row[‘news_url’])):
         print(“Loaded OK”)
   # some of this data loads 404 pages b/c it is a little old, 
   # some load login pages. I’ve found that
   # ignoring anything under 500 characters is a decent 
   # strategy for weeding those out.
         if(len(ss.extractText)>500):
            ae = ArticleExample()
            ae.body_text = ss.extractText
            ae.origin_url = row[‘news_url’]
            ae.origin_source = ‘politifact data’
            ae.bias_score = 0 # Politifact data doesn’t have this
            ae.bias_class = 5 # 5 is ‘no data’
            ae.quality_score = row[‘score’]
            ae.quality_class = row[‘class’]
            ae.save()
            print(“Saved, napping for 1…”)
            time.sleep(1)
         else:
            print(“**** This URL produced insufficient data.”)
      else:
         print(“**** Error on that URL ^^^^^”)

通过这些,你会看到我们首先使用 Pandas 来读取 CSV 文件中的 URL 和分数。然后,我们将它发送给解析器,并将结果文本保存在 body_text 中。然后我们小睡一秒钟,善待我们正在收获的网站。媒体偏差图表数据的过程是类似的,我们只需将 quality_class 除以媒体偏差图表中质量分数的 1/4。

然而,真正的工作还没有开始!我们如何从这些网站获取数据,它看起来像什么,我们如何解析它?

对于这项任务,我们需要限制我们要看的单词的数量。我们希望确保这些单词是真正的英语单词,并且我们希望只保存单词 stem,因此像 programmer、programming 和 program 这样的单词都可以简化为 program。这将限制我们最终训练样本的规模,并使其在普通 PC 上易于管理。这个任务将会出现在我们在 harvester 中遇到的 SoupStrainer 类中,我告诉过你我们一会儿会解释。重要的时刻已经到来!

首先是我们的进口产品。我们将使用 BeautifulSoup 解析 HTML,使用 urllib3 从网上加载网页,使用 PorterStemmer 做词干处理。此外,我们还需要一些其他东西来处理这些数据:

import urllib3, re, string, json, html
from bs4 import BeautifulSoup
from bs4.element import Comment
from urllib3.exceptions import HTTPError
from io import StringIO
from nltk.stem import PorterStemmer

接下来,我们将设置我们的类,并从一个完整的字典中初始化我们的字典,您可以从:https://github.com/dwyl/english-words获得

class SoupStrainer():
   englishDictionary = {}
   haveHeadline = False
   recHeadline = ‘’
   locToGet = ‘’
   pageData = None
   errMsg = None
   soup = None
   msgOutput = True def init(self):
      with open(‘newsbot/words_dictionary.json’) as json_file:
         self.englishDictionary = json.load(json_file)

我们只对页面上的可见文本感兴趣,所以下一步是构建一个过滤器,它能够检测哪些标签是可见的,哪些是不可见的:

def tag_visible(self, element):
   if element.parent.name in [‘style’, ‘script’, 
          ‘head’, ‘title’, ‘meta’, ‘[document]’]:
      return False
   if isinstance(element, Comment):
      return False
   return True

我们将在下一个函数中使用它,该函数执行实际的加载和解析。系好安全带,这是一次有趣的旅行。

首先,我们将设置一些东西,并确保它看起来至少有点像 URL:

def loadAddress(self, address):
   self.locToGet = address
   self.haveHeadline = False htmatch = re.compile(‘.*http.*’)
   user_agent = {‘user-agent’: ‘Mozilla/5.0 (Windows NT 6.3;
                 rv:36.0) Gecko/20100101 Firefox/36.0’}
   ps = PorterStemmer()   if(htmatch.match(self.locToGet) is None):
      self.locToGet = “http://” + self.locToGet

接下来,让我们看看是否可以加载 URL:

if(len(self.locToGet) > 5):
   if(self.msgOutput):
     print(“Ready to load page data for: “ + self.locToGet +  
           “which was derived from “ + address)
   try:
      urllib3.disable_warnings(
             urllib3.exceptions.InsecureRequestWarning)
      http = urllib3.PoolManager(2, headers=user_agent)
      r = http.request(‘GET’, self.locToGet)
      self.pageData = r.data
      if(self.msgOutput):
         print(“Page data loaded OK”)
   except:
      self.errMsg = ‘Error on HTTP request’
      if(self.msgOutput):
         print(“Problem loading the page”)
      return False

到目前为止,一切顺利,我们只是加载网页并获取结果 HTML 文件。接下来,我们应该提取可见文本,去掉标点符号,确保它是一个真实的单词,然后对其进行词干处理。我留下了一行注释,告诉你如何复习字典中没有的单词。

 self.extractText = ‘’
 self.recHeadline = self.locToGet
 self.soup = BeautifulSoup(self.pageData, ‘html.parser’)
 ttexts = self.soup.findAll(text=True)
 viz_text = filter(self.tag_visible, ttexts)
 allVisText = u””.join(t.strip() for t in viz_text) for word in allVisText.split():
    canonWord = word.lower()
    canonWord = canonWord.translate(
         str.maketrans(‘’, ‘’, string.punctuation))
    canonWord = canonWord.strip(string.punctuation)
    if(canonWord in self.englishDictionary):
       canonWord = ps.stem(canonWord)
       self.extractText = self.extractText + canonWord + “ “

 return True

现在,当我们运行 harvester.py 时,我们将得到一组完整的示例,包括带词干的真实单词、一个 URL 和一个 quality_class,它告诉我们它是假的还是真的。

为了理解下一部分,我们需要看一下我们将要构建的模型。该计划的核心是创建一个示例矩阵,其中每行是一个示例。该行由一组 1 和 0 组成,表示匹配该索引的单词是否出现在示例中。因此,我们需要做的下一步是为我们刚刚下载并放入数据库的所有示例中的每个单词附加一个唯一的索引。所以我们需要建立一个字典。第一步是构建这项任务所需的数据模型和表格。回到 models.py,添加以下内容:

class DictEntry(models.Model):
 canonWord = models.TextField()

走到您的终端,跳 makemigrations/migrate 舞,然后我们就可以开始构建字典了。为此,我们需要看一下脚本 dictbuilder.py。

一旦我们加载了所需的 django 库,我们就可以使用当前在我们的规范单词字典表中的任何单词构建一个 python 字典。这为我们提供了一种快速的方法来查看字典中是否已经有某个内容,而不必进行数据库查找。如果您通过为每个单词测试访问数据库来做到这一点,您的速度将会降低至少 10 倍,因此这一部分绝对是值得的。碰巧的是,我们将在整个过程中重复这样做,所以这里我们将创建一个文件 util.py,并创建一个函数来返回我们的规范单词字典:

def loadCanonDict():
    canonDict = DictEntry.objects.all()
    dictSize = canonDict.count() + 1
    cDict = {}
    for cw in canonDict:
        cDict[cw.canonWord] = cw.pk

    return cDict

最后,我们准备用所有示例中的所有单词来构建字典表:

qs_Examples = ArticleExample.objects.all() #filter(pk__gt = 2942)
print(“Examples: “ + str(qs_Examples.count()))
for ex in qs_Examples:
   cwords = ex.body_text.split()
   for cwrd in cwords:
      if(cwrd in cDict.keys()):
         print(‘.’, end=’’, flush=True)
      else:
         print(‘X’, end=’’, flush=True)
         nde = DictEntry(canonWord = cwrd)
         nde.save()
         cDict[cwrd] = nde.pk

这将为每个单词分配一个主键 ID,这些单词将按顺序编号。这样,当我们构建一个示例时,我们可以使用主键作为列号来更新任何特定的示例,并确保相同的列对于每个示例都意味着相同的事情。请注意,如果您需要清空字典并重新构建,您还需要重置主键计数器。我不得不在开发过程中这样做,也许这篇文章会帮你解决这个头疼的问题!

退一步说,我们现在有了一个数据集,我们有了一种方法来指出在任何特定的例子中存在哪些单词。我们(在我的数据集中)有 20,870 个单词和 2,500 个带分数的独特例子。现在我们准备开始学习我们的模型。如果你是我这样的书呆子,你现在绝对是昏了头。

我们面临的问题是将新闻分为四类,假的,不可靠的,合法的和真实的。这是分类器模型的一个问题。我们使用的模型库是 scikit-learn。我们将测试几个模型,看看哪个效果好。我认为这种类型的问题对于支持向量机或神经网络来说非常好。

对于每一篇文章,我们现在都有一个经过精简和词干处理的文本副本。每个单词都有一个唯一的 ID。我们将把每个例子构建为一个 numpy 行向量,如果单词 ID n 出现在文章中,每个例子[n]将为 1,否则为 0。然后,我们将所有这些行向量堆叠成一个巨大的 20,870 x 2,500 的矩阵。然后我们将把我们的数据集提供的质量类别存储在一个列向量中,并使用这个矩阵和列向量来训练和测试我们的模型。

例如,我们需要一种方法将一篇文章处理成一行。如果我们测试任何新的示例,这是一个我们需要再次重复的任务,所以我们将再次为它创建一个实用函数:

def buildExampleRow(body_text, cDict):
    dictSize = len(cDict.keys())
    one_ex_vector = np.zeros(dictSize+2)
    cwords = body_text.split()
    for word in cwords:
        if(word in cDict.keys()):
            one_ex_vector[cDict[word]-1] = 1
        else:
            print("This word doesn't exist in the dict:" + word)

    return(one_ex_vector)

接下来,我们构建一个函数来从数据库中加载我们的示例。

def processExamples(qs_Examples, cDict):
    Y_vector = np.zeros(qs_Examples.count(), dtype=np.int8)
    Y_vec_count = 0
    examplesMatrix = None

    for ex in qs_Examples:
        Y_vector[Y_vec_count] = int(ex.quality_class)
        Y_vec_count = Y_vec_count + 1
        if(examplesMatrix is None):
            examplesMatrix = buildExampleRow(ex.body_text, cDict)
        else:
            examplesMatrix = np.vstack(
               [examplesMatrix, 
               buildExampleRow(ex.body_text, cDict)])
            print('.', end='', flush=True)

    return( (Y_vector, examplesMatrix))

现在,我们可以在 class_learner.py 中快速轻松地设置培训内容:

from newsbot.util import *

print("Setting up..")
cDict = loadCanonDict()
qs_Examples = ArticleExample.objects.filter(quality_class__lt = 5)

print("Processing examples")
(Y_vector, examplesMatrix) = processExamples(qs_Examples, cDict)

现在是训练和测试模型的时候了。我们将把我们的数据分成一个训练和测试集,然后我们将训练我们的多层感知器分类器。很简单,事实证明:

X_train, X_test, y_train, y_test = train_test_split(examplesMatrix, Y_vector, test_size=0.2)model = MLPClassifier(hidden_layer_sizes=(128,64,32,16,8), max_iter=2500)model.fit(X_train, y_train)

使用像 SciKit 这样强大的库的好处在于,这个过程的基础对于几个不同的模型是相同的。当你想改变模型时,你可以把 model=MLPClassifier(…)改为另一个模型,你通常会得到一个工作程序。

现在,我们有了一个训练有素的模型,我们终于有时间去发现它是否有效,以及我们是否可以从中构建一些很酷的东西。为了找到答案,我们需要做一些测试并理解它们。这样就开始了模型验证的过程。对于分类模型,我们可以很好地了解我们是如何对新闻进行分类的。

print(“***************”)
print(“Classification based:”)
print(accuracy_score(predictions, y_test))
print(confusion_matrix(predictions, y_test))
print(classification_report(predictions, y_test))
print(“***************”)

请敲鼓…

***************
Accuracy score: 0.546
Confusion Matrix: 
[[ 35   8   3   2]
 [ 10  44  28   5]
 [ 21  40  83  58]
 [  3   4  45 111]]
Classification report: 
              precision    recall  f1-score   support1       0.51      0.73      0.60        48
           2       0.46      0.51      0.48        87
           3       0.52      0.41      0.46       202
           4       0.63      0.68      0.65       163accuracy                           0.55       500
   macro avg       0.53      0.58      0.55       500
weighted avg       0.54      0.55      0.54       500***************

解读这些数字,我们得到:

准确性得分,0.546: 这意味着我们的预测有 54.6%是准确的。由于我们有 4 个类,随机猜测会产生 25%的准确率,所以这实际上是一个改进。

混淆矩阵:这组 16 个数字给了我们一些非常有趣的信息。我在下面用一种更易读的格式绘制了它。每一行代表一个类预测类,每一列代表真实类。在行和列的交叉处的数字是被预测为每个预测类的真实类的数量。例如,你在第二行第二列看到的数字 44 是真实类为 2,预测值也为 2 的例子数。您在同一行的下一列中看到的 28 是实际上是 2 的示例数,但我们的模型预测的是 3。请注意,在实际得分为 1 的文章中,1/2 的权重很大。类似地,在最下面一行,我们有实际上被评为 a 4 的例子,注意最后两列比前两列大得多。这是好消息!

分类报告:

在这里,每一行代表一个类,并显示精度、召回和 F1 分数。你在这里看到的数字从很大到不太大不等。总的来说,看起来我们更善于定位真实的新闻而不是虚假的,但是如果我们能做到这一点,我们仍然可以足够接*地工作。如果您继续往下,您会看到我们还会得到一个总体加权*均精度/召回率/F1 分数,这让我们对模型的总体表现有了更清晰的了解。我们的 0.54 F1 分数为我们提供了精确度和召回分数之间的*衡,并且是用于评估分类模型的良好的单一度量。如果我们在另一款车型上获得更高的 F1,我们应该选择它而不是这款。准确性得分也是一个很好的单一指标,在实践中,这两者通常非常接*。

早些时候,我在混淆矩阵中注意到,分类器似乎经常偏离 1。如果我也看看我的模型的*均绝对误差:

mae = mean_absolute_error(y_test, predictions)
print(“Mean absolute Error: “ + str(mae))

我会得到:

Mean absolute Error: 0.54

这进一步证明,*均而言,该模型与实际答案相差不超过 1 类。这将为我们模型的进一步开发和最终交付提供信息。如果我们要将这个模型交付给最终用户,让他们清楚地了解我们的模型在想什么,我们将需要生成概率估计。大多数模型可以自动处理,支持向量分类器需要“概率=真”标志来在训练时产生概率估计器。

既然您已经知道如何阅读混淆矩阵和分类报告,并且我们已经选择了用于模型评估的单一指标,现在我们可以测试一大堆不同的模型。在存储库中可用的代码中,我刚刚注释掉了这里显示的所有各种模型的调用,因此您可以看到 scikit 允许您通过简单地更改模型声明来切换学习模型,其他一切都保持不变。

3 小时后

经过大量的训练和结果分类,下面是我们对这个问题的各种不同模型的测试结果:

嗯,我很惊讶逻辑回归得到了第二名。对于 K-Neighbors 和决策树我并不感到惊讶,它们看起来并不适合这个问题。SVC 是明显的赢家。

思考我们的界面

现在我们对模型的表现有了清晰的了解。接下来我们需要看看他们在真实例子上的表现。我们知道模型往往接*正确,即使它们不正确。我们接下来需要知道更多关于他们是否提供了相互矛盾的答案,或者他们是否给了我们一致的答案。我们将不得不保存我们的前 3 个模型,并构建一些东西来测试它们。

拯救我们的模型

对于任务的这一部分,我创建了一个名为 class_saver.py 的新文件。这样,我可以加载数据一次,运行并测试所有三个顶级模型,并使用 pickle 保存它们。我们将设置我们的环境,然后将我们的前三个模型放入一个可迭代的 python 字典中:

print("Setting up..")
cDict = loadCanonDict()
qs_Examples = ArticleExample.objects.filter(quality_class__lt = 5)
print("Processing examples")
(Y_vector, examplesMatrix) = processExamples(qs_Examples, cDict)
X_train, X_test, y_train, y_test =
     train_test_split(examplesMatrix, Y_vector, test_size=0.2)
chosen_models = {}chosen_models['newsbot/MLPC_model.sav'] = MLPClassifier(hidden_layer_sizes=(128,64,32,16,8), max_iter=2500)chosen_models['newsbot/svc_model.sav'] = 
SVC(gamma='scale', probability = True)chosen_models['newsbot/log_model.sav'] = 
LogisticRegression()

接下来,我们将循环选择模型,训练它们,并决定是否要保留它们。注意,这些模型有随机的初始化,多次运行它们会产生稍微不同的结果,所以你需要看一下它们的统计数据,以确保你得到了一个好的结果。

for fname, model in chosen_models.items():
    print("Working on " + fname)
    model.fit(X_train, y_train)
    predictions = model.predict(X_test)
    print("Classification report: ")
    print(classification_report(predictions, y_test))
    print("***************")
    dosave = input("Save " + fname + "? ")
    if(dosave == 'y' or dosave == 'Y'):
        print("Saving...")
        pickle.dump(model, open(fname, 'wb'))
        print("Saved!")
    else:
        print("Not saved!")

训练完模型并保存后,您将得到 3 个文件。我的 3 个文件非常大,总共约 391 兆字节。

现在,让我们构建一个命令行界面,它将给出我们对真实例子的估计。这里我们可以重用很多代码。如果您在资源库中跟进,我们现在将使用 classify_news.py。

在我们完成了添加所需导入和为 ORM 访问设置 Django 的常规设置后,接下来我们需要加载之前设计的 3 个模型。

print(“Loading brain…”)
log_model = pickle.load(open(‘newsbot/log_model.sav’, ‘rb’))
svc_model = pickle.load(open(‘newsbot/svc_model.sav’, ‘rb’))
mlp_model = pickle.load(open(‘newsbot/mlp_model.sav’, ‘rb’))print(“Brain load successful.”)

接下来,我们需要初始化所有东西,以便将一篇文章变成一个例子,就像我们之前做的那样:

print("Initializing dictionaries...")
cDict = loadCanonDict()
ss = SoupStrainer()
ss.init()

然后,我们将文章转化为模型的输入行:

url = input("URL to analyze: ")

print("Attempting URL: " + url)
if(ss.loadAddress(url)):
    articleX = buildExampleRow(ss.extractText, cDict)
else:
    print("Error on URL, exiting")
    exit(0)

articleX = articleX.reshape(1, -1)

最后,当我们设置好适当的行向量后,我们可以预测并生成每个模型的概率:

log_prediction = log_model.predict(articleX)
log_probabilities = log_model.predict_proba(articleX)svc_prediction = svc_model.predict(articleX)
svc_probabilities = svc_model.predict_proba(articleX)mlp_prediction = mlp_model.predict(articleX)
mlp_probabilities = mlp_model.predict_proba(articleX)# 6\. Display the processed text and the results
print(“*** SVC “)
print(“Prediction on this article is: “)
print(svc_prediction)
print(“Probabilities:”)
print(svc_probabilities)print(“*** Logistic “)
print(“Prediction on this article is: “)
print(log_prediction)
print(“Probabilities:”)
print(log_probabilities)print(“*** MLP “)
print(“Prediction on this article is: “)
print(mlp_prediction)
print(“Probabilities:”)
print(mlp_probabilities)

现在我运行分类器。大约需要 1 到 2 秒的加载时间来解开我的模型和加载字典,这有点长,但仍然可以接受。如果我们要大规模推广,我们需要找到一种方法将模型和字典加载到内存中,并让它们一直存在,直到被删除。对于我们的开发版本,这仍然有效。如果我粘贴一个我认为真实的文章 URL,我会得到以下输出:

*** SVC 
Prediction on this article is: 
[3]
Probabilities:
[[0.01111608 0.0503078 0.70502378 0.23355233]]
*** Logistic 
Prediction on this article is: 
[3]
Probabilities:
[[5.61033543e-04 5.89780773e-03 7.63196217e-01 2.30344942e-01]]
*** MLP 
Prediction on this article is: 
[4]
Probabilities:
[[1.18020372e-04 1.93965844e-09 4.88694225e-01 5.11187753e-01]]

这些概率向我展示了与我的 4 个类别相关的概率,第一个是完全虚假的,最后一个是完全真实的。在支持向量分类器中,真实或大部分真实的几率为 70.5+ 23.4 = 93.9%!其他两个国家也取得了类似的数字。我所有的分类者都同意,这篇文章看起来很真实。在我写这篇文章的时候,它是华盛顿邮报的头条。接下来,我去了一个非常不可靠的新闻来源,这是一个众所周知的虚假和不可靠的新闻故事的供应商,并从他们的头版随机选择一个故事。以下是输出:

*** SVC 
Prediction on this article is: 
[1]
Probabilities:
[[0.80220529 0.18501285 0.01051862 0.00226324]]
*** Logistic 
Prediction on this article is: 
[1]
Probabilities:
[[0.53989611 0.45269964 0.0005857 0.00681855]]
*** MLP 
Prediction on this article is: 
[1]
Probabilities:
[[8.38376936e-01 1.84104358e-03 1.59391877e-01 3.90143317e-04]]

找到了。三个分类器都同意,这篇文章是假的。这里的概率很有趣。SVC 和逻辑模型非常确定这是假的/不可靠的。请注意,MLP 给出了 15.9%的文章大部分是真实的可能性。

最后,我将测试我的一个读者发给我的一篇文章,我邀请他做测试者。他发现这个项目的早期版本产生了不一致的结果,特别是我的 SVC 和 MLP 模型的第一个版本不一致。在这个版本中,它也引起了很大的争议:

*** SVC 
Prediction on this article is: 
[3]
Probabilities:
[[0.28233338 0.38757642 0.26880828 0.06128192]]
*** Logistic 
Prediction on this article is: 
[3]
Probabilities:
[[3.93710544e-01 1.68049849e-01 4.38124141e-01 1.15466230e-04]]
*** MLP 
Prediction on this article is: 
[3]
Probabilities:
[[3.67580348e-03 1.66093528e-05 9.96254861e-01 5.27264258e-05]]

请注意,SVC 几乎不知道这是怎么回事,在类别 1、2 和 3 中给它一个相当*等的评级,然后它选择预测类别 3,即使类别 2 具有最高的概率。在逻辑模型中可以看到相同的基本结果:1 和 3 的概率有些相似,加上 2 的 16.8%的概率,它最终预测了 3。MLP 模型确定这篇文章是 3。有趣的是,这篇文章是关于经济的,但它来自一个不可靠的来源,并且使用了很多类似假新闻的语言。我认为分类器有困难,因为它是关于训练领域之外的主题。培训中使用的文章通常是关于美国政治的,而不是关于经济的,所以这可能是我们看到这种结果的原因。

构建网络界面

咻。各位,这是一段漫长的旅程。现在,我们有了 3 个看起来运行良好的模型,我们希望部署它们,以便公众可以使用它们。我们知道,在许多情况下,一篇文章应该属于第 4 类,我们的模型通常将它们的大部分权重归入第 3 类和第 4 类,并且它们在天*的另一端工作类似。我们知道他们有时会有分歧,尤其是在涉及具体概率的细节上。我们知道,典型的用户不会安装 python 和大量的库来使用这个工具。我们必须让它易于使用,易于理解,并且每个人都可以使用。

好消息,我们最初把这个小东西放在 Django MVC 框架中,所以从这里开始构建一个 web 界面是一个相对简单的过程。

首先,当我们使用 startapp 启动整个过程时,我们更新了 django 提供的 views.py。

在这一部分中,我们看到了一些我们以前在命令行界面中使用过的熟悉代码,这些代码用于设置模型、解析示例并返回表示提交文章的单词内容的行向量:

from django.shortcuts import render
import pandas as pd
import numpy as np
import pickle

from .models import *
from .forms import *
from newsbot.strainer import *
from newsbot.util import *

def index(request):

    url = request.GET.get('u')
    if((url is not None) and (len(url) > 5)):
        print("Setting up")
        svc_model = pickle.load(open('newsbot/svc_model.sav', 'rb'))
        mlp_model = pickle.load(open('newsbot/MLPC_model.sav', 'rb'))
        log_model = pickle.load(open('newsbot/log_model.sav', 'rb'))
        cDict = loadCanonDict()        
        ss = SoupStrainer()
        ss.init()
        print("Setup complete")
        print("Attempting URL: " + url)
        if(ss.loadAddress(url)):
            articleX = buildExampleRow(ss.extractText, cDict)
        else:
            print("Error on URL, exiting")
            return render(request, 'urlFail.html', {'URL', url})

        articleX = articleX.reshape(1, -1)

Shazam,我们在一个由 1 和 0 组成的 numpy 数组中找到了 articleX 作为我们的文章,它代表了文章中出现的规范单词。

现在我们需要从所有模型中得到一个结果:

 svc_prediction = svc_model.predict(articleX)
 svc_probabilities = svc_model.predict_proba(articleX)

 mlp_prediction = mlp_model.predict(articleX)
 mlp_probabilities = mlp_model.predict_proba(articleX)

 log_prediction = log_model.predict(articleX)
 log_probabilities = log_model.predict_proba(articleX)

接下来,我需要为我们的模板设置一些显示变量。我们希望模板中尽可能少的数学和逻辑,所以我们用显示友好的百分点来设置概率,而不是统计学家熟悉的 0 比 1 浮动形式。我们为每个模型创建一个总虚假和总真实指标,如下所示:

总伪造率=伪造(0 级)概率+欺骗(1 级)概率

总真实=看似合法(3 级)概率+真实(3 级)概率

这使得我们只需在模板中进行一次比较,就可以决定我们是要显示“看起来真实”还是“看起来虚假”作为我们的规则。

svc_prb = (svc_probabilities[0][0]*100, svc_probabilities[0][1]*100, svc_probabilities[0][2]*100, svc_probabilities[0][3]*100)
 svc_totFake = (svc_probabilities[0][0]*100) + (svc_probabilities[0][1]*100)
 svc_totReal = (svc_probabilities[0][2]*100) + (svc_probabilities[0][3]*100) mlp_prb = (mlp_probabilities[0][0]*100, mlp_probabilities[0][1]*100, mlp_probabilities[0][2]*100, mlp_probabilities[0][3]*100)
 mlp_totFake = (mlp_probabilities[0][0]*100) + (mlp_probabilities[0][1]*100)
 mlp_totReal = (mlp_probabilities[0][2]*100) + (mlp_probabilities[0][3]*100) log_prb = (log_probabilities[0][0]*100, log_probabilities[0][1]*100, log_probabilities[0][2]*100, log_probabilities[0][3]*100)
 log_totFake = (log_probabilities[0][0]*100) + (log_probabilities[0][1]*100)
 log_totReal = (log_probabilities[0][2]*100) + (log_probabilities[0][3]*100)

然后我们想把这三种模式结合起来。这将处理有争议裁决的案件。如果我们的三个模型中的两个强烈倾向于一个方向,而另一个强烈倾向于另一个方向,那么将它们*均在一起将解决争端。这给了我们一个概率分布,我们可以使用它作为我们的最终用户想要的页面顶部的单一预测:它是真的还是假的?

fin_prb = ( (((svc_probabilities[0][0]*100)+(mlp_probabilities[0][0]*100)+(log_probabilities[0][0]*100))/3), 
 (((svc_probabilities[0][1]*100)+(mlp_probabilities[0][1]*100)+(log_probabilities[0][1]*100))/3),
 (((svc_probabilities[0][2]*100)+(mlp_probabilities[0][2]*100)+(log_probabilities[0][2]*100))/3),
 (((svc_probabilities[0][3]*100)+(mlp_probabilities[0][3]*100)+(log_probabilities[0][3]*100))/3) )
 fin_totFake = (svc_totFake + mlp_totFake + log_totFake)/3
 fin_totReal = (svc_totReal + mlp_totReal + log_totReal)/3

然后,我们将所有这些内容转储到一个上下文中,并将小狗发送到我们的模板:

context = {‘headline’:ss.recHeadline, ‘words’: ss.extractText, ‘url’ : url,
 ‘svc_totFake’: svc_totFake, 
 ‘svc_totReal’: svc_totReal, 
 ‘svc_prediction’: svc_prediction, 
 ‘svc_probabilities’: svc_prb, 
 ‘mlp_totFake’: mlp_totFake, 
 ‘mlp_totReal’: mlp_totReal, 
 ‘mlp_prediction’: mlp_prediction, 
 ‘mlp_probabilities’: mlp_prb,
 ‘log_totFake’: log_totFake, 
 ‘log_totReal’: log_totReal, 
 ‘log_prediction’: log_prediction, 
 ‘log_probabilities’: log_prb,
 ‘fin_totFake’: fin_totFake, 
 ‘fin_totReal’: fin_totReal, 
 ‘fin_probabilities’: fin_prb
 } return render(request, ‘newsbot/results.html’, context)

如果没有提供 URL,您需要在表单的末尾添加这一点来呈现要求用户输入 URL 的表单:

else:
 return render(request, ‘newsbot/urlForm.html’)

在 results.html 中,我们只需为每个结果创建一个快速表。这是最后的裁决表:

<h3 style=”text-align: center;”>
 Combined Result:<br>
 {% if fin_totFake >= fin_totReal %}
 Fake/Dodgy
 {% else %}
 Seems Legit/True
 {% endif %}
 </h3>

 <br>Probability of Fake: {{ fin_probabilities.0|floatformat }}% chance of Fake
<div class=”progress”>
 <div class=”progress-bar” id=”fakeProb_bar” role=”progressbar” aria-valuenow=”{{ fin_probabilities.0 }}”
 aria-valuemin=”0" aria-valuemax=”100" style=”width:{{ fin_probabilities.0 }}%”></div>
</div>

 <br>Probability of Dodgy: {{ fin_probabilities.1|floatformat }}% chance of Dodgy
<div class=”progress”>
 <div class=”progress-bar” id=”MfakeProb_bar” role=”progressbar” aria-valuenow=”{{ fin_probabilities.1 }}”
 aria-valuemin=”0" aria-valuemax=”100" style=”width:{{ fin_probabilities.1 }}%”></div>
</div>

 <br>Probability of Mostly True: {{ fin_probabilities.2|floatformat }}% chance of Mostly True
<div class=”progress”>
 <div class=”progress-bar” id=”MtrueProb_bar” role=”progressbar” aria-valuenow=”{{ fin_probabilities.2 }}”
 aria-valuemin=”0" aria-valuemax=”100" style=”width:{{ fin_probabilities.2 }}%”></div>
</div>

 <br>Probability of True: {{ fin_probabilities.3|floatformat }}% chance of True
<div class=”progress”>
 <div class=”progress-bar” id=”trueProb_bar” role=”progressbar” aria-valuenow=”{{ fin_probabilities.3 }}”
 aria-valuemin=”0" aria-valuemax=”100" style=”width:{{ fin_probabilities.3 }}%”></div>
</div>

对要显示的任何其他模型重复上述步骤。

重述

如果你已经走了这么远,我们已经走了很长一段路了。我们从一个机器无法理解的假设开始。我们找到数据来训练我们的机器,把数据哄成我们的机器可以处理的形式,然后训练机器。然后我们用真实数据进行了测试,出乎所有人意料的是,我们发现它实际上有一个合理的答案。完成这样一个漫长的项目让你对整个机器学习管道有了一个完整的了解。尽管这个项目很长,但仍有很大的改进余地。更多想法包括:

询问用户他们认为机器人是对还是错,并记录他们的答案以备将来可能的训练。

从更多来源查找更多数据集或获取更多数据集。

写一个爬虫挖掘假新闻网站收集越来越多的例子。

调整超参数。

将领域知识扩展到其他国家或其他学科。

使用域名或标题作为数据特征。

想办法统计页面上的广告数量,假设假新闻网站通常有更多的广告。

既然您已经看到了分类器可能做的事情,特别是在解释结果的帮助下,天空是无限的。感谢你的到来,我希望我帮助启发和教育!

全栈深度学习步骤和工具

原文:https://towardsdatascience.com/full-stack-deep-learning-steps-and-tools-a21eda6227b1?source=collection_archive---------7-----------------------

我从一门关于全栈深度学习的课程中学到的总结

Photo by Fatos Bytyqi on Unsplash

大家好,一切都好吗?今天,我要写一篇文章,谈谈我从看到全栈深度学习(FSDL)2019 年 3 月课程中学到了什么。这是一个很棒的在线课程,它告诉我们用全栈深度学习来做项目。我最喜欢的是他们如何教我们一个项目,不仅教我们如何创建深度学习架构,还告诉我们在做深度学习项目时应该关注的软件工程内容。

Source : https://fullstackdeeplearning.com/

当我们做一个深度学习项目时,我们需要知道我们应该使用哪些步骤和技术。我们需要知道这些来提高项目的质量。这将是非常有用的,特别是当我们想在一个团队中做项目的时候。当团队协作时,我们不希望项目变得混乱。

本文将根据 FSDL 课程重点介绍全栈深度学习项目每个步骤中的工具做什么(加上一些我所知道的工具的补充)。将有一个简短的描述在每个步骤做什么。本文将只展示我在那门课程中注意到的工具。本文重点介绍的编程语言是 Python。

2020 年 7 月 12 日更新:可在此访问全栈深度学习课程https://course.fullstackdeeplearning.com/。来看看吧:)。

概述

  1. 步伐
  2. 规划和项目设置
  3. 数据收集和标记
  4. 代码库开发
  5. 培训和调试
  6. 部署
  7. 结论
  8. 编后记

步伐

Figure 1 : Step on doing Full Stack Deep Learning project

这些是 FSDL 课程告诉我们的步骤:

  1. 规划和项目设置
  2. 数据收集和标记
  3. 培训和调试
  4. 部署和测试

其中的每一步都可以返回到上一步或前一步(不是瀑布)。课程还建议我们迭代地进行这个过程,这意味着我们从小的进步开始,并不断地提高它。例如,我们开始使用小数据的简单模型,然后随着时间的推移改进它。

规划和项目设置

这一步将是你要做的第一步。我们需要说明项目要做什么和项目的目标。我们还需要陈述项目的度量和基线。该步骤的子步骤如下:

Figure 2 : Substeps of planning and project setup

定义项目目标

Photo by Patrick Perkins on Unsplash

首先,我们需要定义这个项目要做什么。选择制作什么有两个考虑因素。它们是影响力和可行性。

我们需要确保这个项目是有影响力的。你的应用程序的价值是什么,我们希望在这个项目中。您需要回答的两个问题是

  1. 哪里可以利用廉价预测的优势?
  2. 您可以在哪里自动化复杂的手动软件管道?

对于我们选择的应用程序产生的廉价预测,我们可以产生巨大的价值,从而降低其他任务的成本。

可行性也是我们需要注意的。由于深度学习关注数据,我们需要确保数据可用,并符合项目要求和成本预算。

Figure 3 : The relation of project cost and required accuracy

在需要设定最低目标时,我们需要考虑准确性要求。因为项目成本往往与项目成本呈超线性相关,所以我们需要考虑我们的需求和我们可以承受的最大成本。还要考虑到可能会有一些情况,其中预测失败并不重要,以及一些情况,其中模型必须具有尽可能低的误差

最后,需要看到问题难度。项目有多难。为了衡量难度,我们可以看一些类似问题的已发表的作品。比如在 ARXIV 中搜索一些论文或者任何与项目有类似问题的会议。有了这些,我们就可以把握项目的难度了。

有关评估项目可行性的更多详细信息,请参见图 4。

Figure 4 : Assessing feasibility of ML project

选择指标

Figure 5 : example of metrics. src: https://towardsdatascience.com/precision-vs-recall-386cf9f89488

度量是对系统性能或效率的特定特征的测量

由于机器学习中的系统在优化单个数字上工作得最好,所以我们需要定义一个满足单个数字要求的度量,即使可能有许多度量需要计算。对于一个我们需要使用很多指标的问题,我们需要选择一个公式来组合这些指标。有:

  1. 简单*均/加权*均
  2. 阈值 n-1 度量,评估第 n 个度量
  3. 特定于领域的公式(例如地图)

以下是如何结合两个指标(精确度和召回率)的一些例子:

Figure 6 : Combining Precision and Recall

选择基线

Photo by Nik Shuliahin on Unsplash

在我们选择了度量标准之后,我们需要选择我们的基线。基线是一个预期值或条件,绩效将根据它来衡量,以便与我们的工作进行比较。它将给我们一个预期模型性能的下限。基线越紧,基线就越有用。

Figure 7 : Baseline

那么为什么基线很重要呢?为什么不跳过这一步?我们可以通过与基线比较来衡量我们的模型有多好。通过了解模型的好坏,我们可以选择下一步要调整的地方。

要寻找基线,您可以使用几个来源:

  1. 外部基线,您从业务或工程需求中形成基线。您也可以使用发布的工作结果作为基线。
  2. 内部基线,使用脚本基线或创建简单的机器学习(ML)模型,如使用基于标准特征的单词或使用简单模型。

基线是根据你的需要选择的。例如,如果您想要一个超越人类系统,您需要添加一个人类基线。

设置基本代码

创建您的代码库,这将是如何做进一步的核心步骤。代码库中的源代码可以根据项目当前要做的事情的当前需要来开发。例如,如果当前步骤是收集数据,我们将编写用于收集数据的代码(如果需要)。我们通常会来回进行这一步。

我们应该确保代码库中的源代码是可复制的和可扩展的,尤其是在团队中做项目的时候。要做到这一点,你需要使用正确的工具。这篇文章稍后会告诉我们。

数据收集和标记

Figure 8 : Tweet about poll time spent as data scientist

在我们定义了我们将在项目中创建什么、基线和度量标准之后,最痛苦的步骤将开始,数据收集和标记

大多数深度学习应用都需要大量需要标注的数据。时间会大部分消耗在这个过程中。虽然您也可以使用公共数据集,但是我们项目所需的带标签的数据集通常是不公开的。

下面是子步骤:

Figure 9 : substeps of data collection and labeling

战略

Photo by Campaign Creators on Unsplash

我们需要计划如何获得完整的数据集。有多种方法可以获得数据。你应该考虑的一点是,数据需要根据我们想要在项目中创建的内容进行对齐。

吸收

Source : https://pushshift.io/ingesting-data%E2%80%8A-%E2%80%8Ausing-high-performance-python-code-to-collect-data/

如果获取数据的策略是通过互联网抓取一些网站,我们需要使用一些工具来完成。Scrapy 是对项目有帮助的工具之一

刺儿头

Source : http://rafaelsilva.com/for-students/directed-research/scrapy-logo-big/

这是一个 Python scrapper 和数据爬虫库,可以用来抓取和抓取网站。它可用于收集网站上的图像和文本等数据。我们也可以用这个从必应、谷歌或 Instagram 上删除图片。要使用这个库,我们需要学习也可以在它的网站上找到的教程。别担心,这不难学。

在我们收集数据之后,你需要考虑的下一个问题是把你收集的数据发送到哪里。因为你不是一个人在做这个项目,所以你需要确保每个人都可以访问这些数据。此外,我们需要选择将要保存的数据的格式。当我们想把数据保存在云中时,下面是一个解决方案。

对象存储

Source : https://cloudacademy.com/blog/amazon-s3-vs-amazon-glacier-a-simple-backup-strategy-in-the-cloud/

对于存储图像和视频等二进制数据,您可以使用云存储,如 【亚马逊 3】等,通过 API 在文件系统上构建对象存储。我们还可以在服务中内置版本控制。更多详情请见他们的网站。需要付费才能使用(也有免费计划)。

数据库

Source : https://aws.amazon.com/rds/postgresql/

数据库用于结构化数据的持久、快速、可伸缩的存储和检索。数据库用于保存经常被连续访问的非二进制数据。您将在这里保存元数据(标签、用户活动)。你可以使用一些工具。推荐的一个是PostgreSQL

它可以存储结构化的 SQL 数据库,也可以用来保存非结构化的 json 数据。它仍在积极维护中。

数据湖

Figure 10 : Data lake pattern

当您的数据是来自多个来源和多种格式的非结构化聚集,并且转换成本很高时,您可以使用数据湖。基本上,你把所有的数据都转储到它上面,它就会把这些数据转化成特定的需求。

Figure 11 : Amazon redshift

亚马逊红移是解决数据湖的一个可行方案。

当我们进行训练过程时,我们需要将您的模型所需的数据移动到您的文件系统中。

数据应该版本化以确保进度是可恢复的。版本控制不仅适用于源代码,也适用于数据。在讨论完数据标记之后,我们将深入研究数据版本控制。

数据标记

Figure 12 : Data labeling solution

在这一节中,我们将知道如何标记数据。您可以使用以下资源来标记数据:

  1. 自己雇佣注释者
  2. 众包(土耳其机器人)
  3. 使用figure eightscale . ailabel box等全业务数据标注公司

如果您希望团队对其进行注释,您可以使用以下几个工具:

data Turks

Source : dataturks.com

在线协作注释工具 Data Turks。对于免费计划,它被限制为 10000 个注释,并且数据必须是公开的。它为 NLP(序列标记、分类等)和计算机视觉(图像分割、图像包围盒、分类等)的一些任务提供了一些注释工具。FSDL 的课程用这个作为标记的工具。

多卡诺

Source : https://github.com/chakki-works/doccano

NLP 任务的免费开源注释工具。它还支持序列标记、分类和机器翻译任务。也可以设置成一个协作注释工具,但它需要一个服务器。

CVAT

Source : https://github.com/opencv/cvat

用于计算机视觉任务的离线注释工具。它是由英特尔作为开源软件发布的。它可以标记边界框和图像分割。

公共数据集

如果您想搜索任何公共数据集,请参见 Stacy Stanford创建的这篇文章以了解任何公共数据集的列表。

**** [## 机器学习和数据科学的最佳公共数据集

机器学习和数据科学最好的数据集是什么?经过数小时对数据集的审查,我们已经…

medium.com](https://medium.com/towards-artificial-intelligence/the-50-best-public-datasets-for-machine-learning-d80e9f030279)

它仍在积极地更新和维护。

数据版本化

关于如何进行数据版本控制,有几个层次:

  1. 0 级:未版本化。我们不应该尝试这样做。部署需要版本化。如果数据没有版本化,那么部署的模型也没有版本化。如果我们使用未版本化的,会有一个问题,那就是无法回到以前的结果。
  2. 一级:通过快照版本化。我们存储不同版本上使用的所有数据。我们可以说它有点粗糙。我们仍然需要像编写代码一样简单地编写数据版本
  3. 级别 2 :数据被版本化为代码和资产的混合。沉重的文件将被存储在其他服务器(如亚马逊 S3),那里有一个 JSON 或类似类型的相关元数据的参考。相关元数据可以包含标签、用户活动等。JSON 文件将被版本化。JSON 文件会变得很大。为了更简单,我们可以使用 git-lfs 来版本化它。这个水*做项目应该是可以接受的。
  4. 第三级:使用专门的软件解决方案对数据进行版本控制。如果你觉得 2 级对你的项目来说还不够,可以这样做。数据版本化的工具之一是 DVC

DVC

Source : https://dvc.org/

DVC 的建立是为了让 ML 模型可以共享和复制。它旨在处理大型文件、数据集、机器学习模型、指标和代码。这是一个为 ML 模型及其数据集版本化的解决方案。我们可以将版本控制连接到云存储中,如亚马逊 S3 和 GCP。****

代码库开发

当我们做项目时,期望在做好每一步的基础上编写代码。当我们写代码时,可再现性是我们必须关心的一件事。我们需要确保我们的代码库具有可重复性。

在我们深入工具之前,我们需要选择我们代码库的语言和框架。

程序设计语言

Source : https://www.python.org/

对于选择编程语言,我更喜欢 Python 而不是其他。Python 拥有最大的数据科学社区,非常值得开发。流行的深度学习软件也大多由 Python 支持。这种语言也很容易学。

深度学习框架

Figure 13 : DL Framework production and development diagram

对于深度学习框架,您可以做出几种选择。Python 中最流行框架是 Tensorflow、Keras 和 PyTorch。用你喜欢的那个。

为了更容易调试,可以使用 PyTorch 作为深度学习框架。 Keras 也很好用,有很好的 UX。它是 Tensorflow、Theano 和其他深度学习框架的包装器,使其更易于使用。 Tensorflow 如果你喜欢他们的环境也是一个选择。Tensorflow 能够做出明智的决策,是因为它的社区提供了支持,并且拥有出色的部署工具。

不要担心部署。有一种软件可以将模型格式转换成另一种格式。例如,您可以将由 Pytorch 生成的模型转换为 Tensorflow 。我们稍后会看到这一点。

我认为选择语言和框架的因素是它背后的社区有多活跃。因为它将产生大量可以集成到其中定制包。

版本控制

Source : https://www.reddit.com/r/ProgrammerHumor/comments/72rki5/the_real_version_control/

做项目的时候很重要的一件事就是版本控制。当我们做项目时,我们不希望当有人意外破坏我们的代码库时无法重做。我们还需要跟踪每次更新的代码,以查看其他人更新了哪些更改。如果我们不使用一些工具,这是不可能的。 Git 是做这件事的解决方案之一。

好的,我们知道版本控制很重要,尤其是在协作工作中。目前, git 是做版本控制的最佳方案之一。它也可以用来和你团队中的其他人分享你的代码。没有这一点,我不认为你能在项目中与其他人合作得很好。

Source : GitHub

有几个可以使用 Git 的服务,比如 GitHubBitBucketGitLab

代码审查

Figure 14 : Code Review

还有一件重要的事情应该做,那就是代码审查。代码审查是对通过单元或集成测试的不正确代码或质量差的代码的早期保护。当您进行协作时,让某人检查您的代码并对其进行评审。大多数版本控制服务应该支持这个特性。

项目结构

Figure 15 : Example of folder structure. Source : https://drivendata.github.io/cookiecutter-data-science/

当我们第一次创建项目结构文件夹时,我们一定想知道如何创建文件夹结构。然后,我们放弃,把所有的代码放到根项目文件夹里。给出质量差的代码是一种不好的做法。

我发现的解决方案之一是烹饪数据科学。它给出了一个模板,我们应该如何创建项目结构。它也给出了如何给创建的文件命名,以及你应该把它放在哪里。一定要用它来使你的代码库不会变得凌乱。考虑阅读网站来使用它。

集成开发环境(IDE)

IDE 是可以用来加速编写代码的工具之一。它集成了对开发有用的工具。有几种 ide 可供您使用:

皮查姆

Source : http://www.jetbrains.com/pycharm

JetBrains 发布的 IDE。该 IDE 不仅可以用于深度学习项目,还可以用于其他项目,如 web 开发。Pycharm 具有自动代码完成、代码清理、重构功能,并与其他工具集成,这对于使用 Python 开发非常重要(首先需要安装插件)。它有很好的调试环境。它还可以运行笔记本(。ipynb)文件。

Source : https://github.com/jupyterlab/

Jupyter Lab 是一个易于使用的 IDE,交互式数据科学环境工具,它不仅可以用作 IDE,还可以用作演示工具。用户界面(UI)最好把这个作为一个可视化工具或者一个教程工具。我们可以用 markdown 格式制作文档,也可以在笔记本上插入图片。

就我个人而言,我使用 Pycharm 编写源代码。当我创建一些教程来测试一些东西或进行探索性数据分析(EDA)时,我会使用 Jupyter Lab 来完成。只是不要把你的可重用代码放到你的笔记本文件里,它的可复制性很差。

连续累计

“嘿,什么鬼东西!?为什么我无法在此版本中运行培训流程”-A

“Idk,我只是推我的代码,我认为它在我的笔记本上工作..等一下..我在这条线上得到一个错误..我没有将所有代码复制到我的实现中”——B

“那你为什么推!?!?"—答

在我们将我们的工作推送到存储库之前,我们需要确保代码确实有效并且没有错误。为此,我们应该在将模型和代码推送到存储库之前测试代码。必须完成单元或集成测试。

单元测试测试代码应该通过的模块功能。集成测试测试模块的集成。它会检查你的逻辑是否正确。这样做是为了在做实验前发现你的错误。

Source : circleci.com

CircleCI 是做持续集成的解决方案之一。它可以进行单元测试和集成测试。它可以使用 Docker Image(我们稍后将深入讨论)作为环境的容器化(我们应该使用它)。可以做到这一点的类似工具有TravisCI**。**********

如果您想用 Python 测试代码,可以使用以下几个库:

[pipenv check](https://github.com/pypa/pipenv) : 扫描我们的 Python 包依赖图,寻找已知的安全漏洞

[pylint](https://github.com/PyCQA/pylint):对 Python 文件进行静态分析,并报告样式和 bug 问题。

[mypy](https://github.com/python/mypy):对 Python 文件进行静态分析检查

[bandit](https://github.com/PyCQA/bandit):执行静态分析,查找 Python 代码中常见的安全漏洞

[shellcheck](https://github.com/koalaman/shellcheck):查找 shell 脚本中的错误和潜在错误(如果使用的话)

[pytest](https://github.com/pytest-dev/pytest):用于进行单元和集成测试的 Python 测试库

将它们写入您的 CI,并确保通过这些测试。如果失败了,那么重写你的代码,并知道代码中的错误在哪里。

这是一个在深度学习系统上编写单元测试的例子。

Figure 16 : Example of doing unit test in ML experiments

海关环境和集装箱化

“嘿,我已经在我的电脑上测试过了,效果很好”

“什么?不,老兄,它在我的电脑上失败了?它是如何在你的电脑上工作的!?"

有过这种经历吗?我有。造成这种情况的原因之一是你的工作环境与其他人的不同。例如,你在 Windows 上工作,另一个在 Linux 上工作。你的库和他们的库的差异也可能是问题的导火索。

为了解决这个问题,您需要在一个名为requirements.txt的文本中显式地编写您的库依赖关系。然后运行 Python 虚拟环境如[pipenv](https://github.com/pypa/pipenv).这将解决库依赖。尽管如此,它仍然不能解决团队的环境和操作系统的差异。要解决,可以用 Docker。

Source : docker.com

Docker 是一个可以设置成虚拟环境的容器。我们可以安装我们在 Docker 中设置的库依赖项和其他环境变量。有了这个,你就不用担心会因为环境的不同而产生误差。当我们想要部署应用程序时,Docker 也是一个重要的工具。它会强制部署的地方使用期望的环境。

为了共享容器,首先,我们需要将创建环境的所有步骤写入 Dockerfile ,然后创建一个 DockerImage 。可以推入 DockerHub 中。然后另一个人可以从 DockerHub 中拉出 DockerImage 并从他/她的机器上运行它。

要了解关于 Docker 的更多信息,有一篇由 Preethi Kasireddy 撰写的初学者友好的好文章。

**** [## 对初学者友好的容器、虚拟机和 Docker 介绍

如果你是一个程序员或技术人员,你可能至少听说过 Docker:一个打包、运输…

medium.freecodecamp.org](https://medium.freecodecamp.org/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b)

图 17 是一个如何创建 Dockerfile 文件的例子。

Figure 17 : Example of Dockerfile****

培训和调试

现在我们正处于训练和调试阶段。这是你做实验和制作模型的步骤。这一步的子步骤如下:

FIgure 18 : Substeps Training and Debugging

从简单开始

使用您选择的深度学习框架,用简单的架构对神经网络进行编码(例如:具有 1 个隐藏层的神经网络)。然后使用默认的超参数,如无正则化和默认的 Adam 优化器。如果需要,不要忘记规范化输入。最后,使用模型的简单版本(例如:小数据集)。

实施和调试

实现神经网络,有几个技巧,你应该按照顺序。

  1. 让模型运行

我们应该做的是让你用你的 DL 框架创建的模型运行。这意味着要确保在更新权重的过程中没有异常发生。

经常发生的异常如下:

  1. 形状不匹配
  2. 铸造问题
  3. 被遗忘

2。超配单个批次

之后,我们应该对单个批次进行过度拟合,以观察模型是否可以学习。过度拟合意味着我们根本不关心验证,而是关注我们的模型是否能够根据我们的需要进行学习。我们这样做,直到模型的质量变得过拟合(~100%)。以下是此过程中出现的常见问题:

  1. 错误上升(可能由以下原因引起:学习率过高、错误的损失函数符号等)
  2. 错误爆发/变得异常(可能由以下原因引起:数值问题,如对数运算、经验或高学习率等)
  3. 错误振荡(可能由以下原因引起:损坏的数据标签、学习率过高等)
  4. 错误*台(可能由以下原因引起:学习率太低、数据标签损坏等)

3。与已知结果比较

在我们确保我们的模型训练良好之后,我们需要将结果与其他已知结果进行比较。下面是已知结果的层次结构:

Figure 19 : Hierarchy of known results

我们这样做是为了确保我们的模型能够真正学习数据,并看到模型在学习任务的正确轨道上。我们将需要不断迭代,直到模型能够达到预期的性能。

评价

我们将通过计算误差来计算偏差-方差分解,该误差是用我们当前最佳模型的所选度量来计算的。偏差-方差分解的计算公式如下:

其中:

**irreducible error = the error of the baseline
bias = training error - iredducible error
variance = validation error - train error
validation overfitting = test error - validation error**

下面是一些实现偏差-方差分解的例子。

Figure 20 : Breakdown of test error

通过了解偏差、方差和验证过拟合的值,它可以帮助我们选择下一步要改进的内容。

如果模型已经满足了需求,那么就部署模型。如果没有,那么通过使用评估的结果来解决是改进数据还是调整超参数的问题。在预测某组实例时,考虑看看模型有什么问题。迭代直到满足需求(或者放弃)。

这里有一些工具对这一步很有帮助:

版本控制

又来了,版本控制。是的,我们对代码和数据进行了版本控制,现在是对模型进行版本控制的时候了。以下是可用于版本控制的工具:

WANDB

Source : Wandb.com

模型结果的版本控制。它有很好的用户界面和体验。然后,它可以保存模型上使用的参数、模型结果的样本,并且还可以保存将被版本化的模型的权重和偏差。此外,它可以实时可视化模型的结果。此外,我们还可以将模型恢复到之前的运行(也可以将模型的权重更改为之前的运行),这使得模型的重现更加容易。它可以随时运行。它还可以很好地扩展,因为它可以与 Kubeflow (Kubernetes for ML,它为容器化的应用程序管理资源和服务)集成。

无损耗

Source : Losswise.com

它也是对模型进行版本控制的版本控制。它还实时保存用于实验的模型和超参数的结果。它还可以估计模型何时完成训练。每当您将代码推送到存储库(在指定的分支上)时,它都会训练模型。它还可以实时显示模型的结果。

超参数优化

当优化或调整学习率这样的超参数时,有一些库和工具可以用来做这件事。有:

对于 Keras DL 框架: Hyperas ,

对于 Pytorch DL 框架:超搜索

其他:远视

WANDB 还提供超参数优化解决方案。不过,您需要先联系他们才能启用它。

部署

最后一步将是这一步。子步骤如下:

Figure 21 : Substeps of Deploying & Testing

试生产意味着您将通过在选定的最终用户群中测试来验证系统。通过这样做,我们希望能够在全面部署之前获得系统的反馈。对于测试,除了单元测试和集成测试之外,你还可以对你的系统进行一些测试,例如:渗透测试、压力测试等等。

在我们确定模型和系统已经满足需求之后,就该部署模型了。首先,有几种部署模型的方法。有:

  1. Web 服务器部署
  2. 嵌入式系统和移动设备

Web 服务器部署

如果我们想部署到网站上,我们可以使用几种策略。在此之前,我们需要确保我们创建了一个 RESTful API,用于响应 HTTP 请求(GET、POST、DELETE 等)的预测。这些战略如下:

  1. 将代码部署到云实例。通过添加实例进行缩放。
  2. 将代码部署为容器(Docker),通过编排进行扩展。应用程序代码被打包到 Docker 容器中。例子:AWS Fargate。
  3. 将代码部署为“无服务器功能”。应用程序代码被打包成 zip 文件。无服务器功能将管理一切。例如:即时扩展、每秒请求数、负载*衡等。它不同于上述两个,无服务器功能只支付计算时间,而不是正常运行时间。例如: AWS LambdaGoogle Cloud FunctionsAzure Functions

Figure 22 : Amazon Lambda

嵌入式系统和手机

Source : https://developers.googleblog.com/2017/11/announcing-tensorflow-lite.html

要部署到嵌入式系统或手机上,我们可以使用tensor flow Lite。与 Tensorflow 相比,它体积更小,速度更快,依赖性更小,因此可以部署到嵌入式系统或移动设备中。不幸的是,它的操作数有限。

Source : https://devblogs.nvidia.com/speed-up-inference-tensorrt/

还有一个工具叫 TensorRT 。它优化了用于预测的推理机,从而加快了推理过程。它是基于 CUDA 构建的。在嵌入式系统上,NVIDIA Jetson TX2 可以很好地配合它。

在苹果上,有一个叫做 CoreML 的工具,可以更容易的将 ML 系统集成到 IPhone 上。还有类似的工具叫做 MLKit ,可以用来帮助将 ML 系统部署到 Android 上。

交换

Source : https://onnx.ai/

ONNX (开放神经网络交换)是深度学习模型的开源格式,可以很容易地将模型转换成支持的深度学习框架。ONNX 支持 Tensorflow、Pytorch 和 Caffe2。它可以混合不同的框架,这样适合开发的框架(Pytorch)不需要擅长部署和推理(Tensorflow / Caffe2)。

监视

Figure 23 : Example of monitoing in AWS

如果把应用部署到云服务器,应该有监控系统的解决方案。当事情出错时,我们可以通过在监控系统中写入相关记录来设置警报。有了这个,我们就知道模型可以改进什么,并解决问题。

结论

在这篇文章中,我们根据 2019 年 3 月的 FSDL 课程,了解了做全栈深度学习的步骤。首先,我们需要设置和计划项目。在这一步中,我们需要定义目标、指标和基线。然后,我们收集数据并用可用的工具对其进行标记。在构建代码库的过程中,有一些工具可以保持上面描述的项目的质量。然后我们通过测试和调试进行建模。在模型满足需求之后,我们最终知道了将应用程序部署和监控到所需界面的步骤和工具。

编后记

Photo by Joshua Hoehne on Unsplash

就是这样,我的关于我所学课程介绍的工具和步骤的文章。我为什么写这篇文章?我发现我的大脑可以很容易地记住并让我更好地理解我需要的东西的内容。此外,在我写作的过程中,我有机会复习课程内容。此外,它可以让我分享我的知识给每个人。我很乐意把好的东西分享给大家:)。

在学习那门课程的过程中,我获得了很多新的东西,尤其是关于深度学习堆栈的工具。我还知道如何在深度学习中排除模型故障,因为它不容易调试。它还教会了我进行全栈深度学习的工具、步骤和技巧。总而言之,这是一门很棒的课程,而且可以免费使用。所以我推荐给任何想学习深度学习做项目的人。

说实话,我还没有尝试过本文所写的所有工具。本文介绍的工具及其描述摘自 FSDL 课程和我读过的一些资料。你可以告诉我是否有错误的信息,尤其是关于工具的。

因此,

我欢迎任何可以提高我自己和这篇文章的反馈。我正在学习写作,学习变得更好。我感激能让我变得更好的反馈。确保以适当的方式给出反馈😄。

在我的下一篇文章中再见。

Source : https://cdn.pixabay.com/photo/2017/07/10/16/07/thank-you-2490552_1280.png

来源

**** [## 什么是试点测试?定义、含义、示例

试点测试是在实时操作条件下验证系统的一个组件或整个系统。它…

www.guru99.com](https://www.guru99.com/pilot-testing.html) [## 把你的数据扔进湖里

许多企业在不同的孤岛中组织数据,这使得询问需要数据的问题变得更加困难…

medium.com](https://medium.com/data-ops/throw-your-data-in-a-lake-32cd21b6de02)

由数据厨房

https://docs . Google . com/Presentation/d/1 yhlpvphus 2 kgi 5 zwo 0 su-pku 3 gimak 3 its 38 z-B5Gw/(ICLR 2019 关于再现性的演讲由 Joel Grus )。图 14 和 16 取自这个来源。

[## 全栈深度学习

面向熟悉深度学习基础、寻求扩展技能的软件开发人员的实践计划。

fullstackdeeplearning.com](https://fullstackdeeplearning.com/)

其他数字取自这一来源。****

全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中

原文:https://towardsdatascience.com/full-stack-development-tutorial-integrate-aws-lambda-serverless-service-into-angular-spa-abb70bcf417f?source=collection_archive---------9-----------------------

Photo by Stephen Dawson on Unsplash

(这篇文章也可以在我的博客中找到)

这篇文章是我的全栈开发教程系列的最后一篇文章。在这篇文章中,我们将把后端 Lambda REST API 集成到我们之前开发的 Angular App 中。以前的帖子是在 Angular SPA 上可视化交易数据和在 AWS Lambda 上运行无服务器 REST API 提供交易数据。

更新 angular 服务,从 Lambda 调用 REST API

首先,我们需要更新 SPA 中的服务,从 Lambda 调用 REST API,而不是返回哑数据。注意,我们已经定义了一个主题,以便图表组件可以被订阅。REST API 调用完成后。它发出历史数据。从图表组件中,它将接收该响应并对其进行一些业务逻辑处理。

更新图表组件以使用 Lambda 中的历史数据来可视化图表。在这个 typescript 中,我们从 StockDataService 订阅了 Observerable。然后,它将 Lambda 的响应分配给图表。

发布 web 应用

现在,我们可以为您的应用程序创建一个公共网站。首先,我们需要为 angular 应用程序部署构建生产代码。从终端运行以下命令。

ng build --prod

此命令将导致 dist 文件夹,其中包含此 SPA 的所有静态文件。我们将部署到 S3 建立一个公共网站。

创建一个 S3 存储桶

创建新的存储桶。除非您购买了自己的域名并为您的 web 应用程序设置了域名,否则您的域名将成为网站 url 的一部分。

接受所有默认选项并创建它。然后选择新创建的存储桶,单击 permisions。在阻止公共访问中,我们必须取消选中阻止“通过新公共存储桶策略授予的对存储桶和对象的公共访问”和“通过任何公共存储桶策略阻止对存储桶和对象的公共和跨帐户访问”,以便公共用户可以访问此 web 应用程序。

我们还需要添加一个存储桶策略。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow", 
            "Principal": "*", 
            "Action": "s3:GetObject", 
            "Resource": "arn:aws:s3:::[YOUR_BUCKET_NAME]/*" 
        } 
    ] 
}

上传内容

将 dist/stock-app 文件夹中的文件上传到存储桶

启用虚拟主机

打开属性,选择“静态网站托管”。为索引 documemt 键入 index.html,然后选中“使用此存储桶托管网站”。

现在,你应该可以在 http:// < bucket_name >开你的 SPA 了。. Amazon AWS . com/,我这里是 http://stock-spa-jli.s3-website-us-west-2.amazonaws.com/。但是,你会遇到一个问题。您看不到任何数据。那是因为我们的 REST API 和 API 网关不允许 CORS。我们将明确地启用它。

启用 CORS

接下来,我们需要在 API 网关中启用 CORS,以便 Lambda 中的 API 可以接受跨源请求。

在 AWS 控制台中打开 API 网关服务,并为我们在上一篇文章中开发的 Lambda 选择网关。选择要启用 CORS 的端点。为简单起见,我选择任意。然后在操作下拉列表中,选择启用 CORS 并确认。

验证

现在,我们都准备好了。您的 Lambda 应该能够为您的 SPA 提供数据。回到你在 S3 的网站。你会看到间谍的股票图表。

仅此而已。我们用 Angular 开发了一个简单的全栈 web 应用,使用无服务器框架,AWS Lambda,API gateway,S3。它是用云编队部署的。几乎所有后端 AWS Lambda 都由无服务器框架轻松处理。

建议读取:

全面了解亚马逊网络服务(AWS)

AWS Lambda 在行动:事件驱动的无服务器应用第 1 版

亚马逊网络服务第二版

我的旧帖子:

我关于金融和科技的帖子

我关于 FAANG 访谈的帖子

从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅

全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据

全栈开发教程:在 Angular SPA 上可视化交易数据

强化学习:Q 学习简介

全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据

原文:https://towardsdatascience.com/full-stack-development-tutorial-serverless-rest-api-running-on-aws-lambda-a9a501f54405?source=collection_archive---------23-----------------------

无服务器计算是一种云计算 执行模式,云提供商运行服务器,动态管理机器资源的分配。定价基于应用程序消耗的实际资源量,而不是预先购买的容量单位。—维基百科

Photo by Anthony Cantin on Unsplash

(这篇文章也可以在我的博客中找到)

这是我的全栈开发教程系列的第二篇文章。上一篇文章— 全栈开发教程:在 Angular SPA 上可视化交易数据

无服务器计算的优势在于它可以在需要时执行。价格完全取决于使用情况。开发者无需维护服务器、修补安全漏洞、升级软件等。

亚马逊的 AWS 是一个事件驱动的无服务器计算*台。它拥有强大的运行时支持,包括 Node.js、Python、Java、Go、Ruby 和 C#。作为一个事件驱动的*台,Lambda 非常适合处理事件变化的场景,如“文件正在上传到 S3”,“数据库正在更新”,“物联网中接收到传感器数据”等。

在本教程中,我们将利用无服务器框架为本教程中的股票应用程序创建一个无服务器 REST API。无服务器框架是一个开源框架,帮助在包括 AWS Lambda 在内的多个云环境中开发和部署无服务器功能。

设计我们的端点

遵循 REST 实践,让我们定义我们的端点/价格?ticker= <ticker_name>。和响应将如下所示,以在 UI 中显示图表。</ticker_name>

[
  {
    "name": "Ticker",
    "series": [
      {
        "name": "2018-11-05",
        "value": 1
      },
      {
        "name": "2018-11-07",
        "value": 1.0784432590958841
      }
    ]
  }
]

安装和设置

AWS

首先你需要一个 AWS 账户。如果您还没有 AWS 帐户,请注册。然后创建一个 IAM 用户。最后,您将获得 IAM 用户的凭据。您将需要它来设置无服务器 cli,以便可以在 AWS 上部署和运行无服务器服务。

serverless config credentials --provider aws --key <ACCESS KEY ID> --secret <SECRET KEY>

无服务器安装

按照说明安装 docker 进行部署。

初始化无服务器项目

为服务创建 serverless.yml 文件。它需要插件 wsgi 作为 web 服务器来运行 REST 服务。内置的 flask 开发服务器对于生产来说性能不够。注意 pythonRequirements 中的 slim 标志有助于限制源代码的大小。Lambda 的源代码有大小限制。纤细的旗帜有助于减小尺寸。因此,排除所有不必要的文件也很重要,比如 venv 中的文件。zip 标志有助于在上传到 S3 进行部署之前压缩源代码。配置的其余部分不言自明。

部署过程总结如下。无服务器框架将文件构建并打包为 zip 文件。然后,它使用 IAM 凭据将源代码上传到 S3 存储桶(该存储桶由无服务器 cli 自动创建)。然后,它利用 CloudFormation 部署 Lambda 服务。所有这些都发生在一个单一的命令中。

实施

实际的实现很简单。当请求历史数据时,它从 S3 抓取数据(csv 文件)并读入熊猫数据帧(S3 是一个 AWS 存储服务)。然后我们将迭代 dataframe 来构造我们上面定义的响应。当我们在 serverless.yml 中定义 Lambda 入口点 app.app 时,我们将在 app.py 中编写我们的服务。

在运行我们的应用程序之前,从 Yahoo finance 下载历史股票数据,并将其放在一个名为 data 的目录中。

然后运行本地启动应用程序。

(venv) **➜  stock-backend** python app.py* Serving Flask app "app" (lazy loading)* Environment: productionWARNING: This is a development server. Do not use it in a production deployment.Use a production WSGI server instead.* Debug mode: on* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)* Restarting with stat* Debugger is active!* Debugger PIN: 248-351-201

从现在开始,您可以验证您的 REST 端点是否工作。假设您在数据目录中有一个 SPY.csv 文件。打开浏览器输入http://127 . 0 . 0 . 1:5000/price?地址栏里的 ticker=SPY 。JSON 响应的结果将显示在您的浏览器中。

[
  {
    "name": "SPY", 
    "series": [
      {
        "name": "2014-10-20", 
        "value": 190.300003
      }, 
      {
        "name": "2014-10-21", 
        "value": 194.070007
      }, 
      {
        "name": "2014-10-22", 
        "value": 192.690002
      }, 
      {
        "name": "2014-10-23", 
        "value": 194.929993
      }...
]

或者你可以使用 curl 命令来做同样的测试

curl [http://127.0.0.1:5000/price?ticker=SPY](http://127.0.0.1:5000/price?ticker=SPY)

使用 S3 存储历史股票数据

上述实现依赖于本地存储来保存历史股票数据。我们可以利用 AWS S3 来托管数据。转到 AWS 控制台并选择 S3。创建一个 S3 存储桶并命名。确保该名称是全局唯一的。

现在,我们可以将 csv 文件上传到存储桶。

接下来,为了让 Lambda 能够访问这个 S3 存储桶,我们需要为 Lambda 的角色分配一个 S3 只读策略。是的,这可以通过 serverless.yml 配置文件完成,无需与 AWS 控制台交互。serverless.yml 中更新后的提供程序如下所示

**provider**:
  **name**: aws
  **runtime**: python3.7
  **stage**: prod
  **region**: us-west-2
  **iamRoleStatements**:
    - **Effect**: **'Allow'
      Action**:
        - **'s3:ListBucket'
      Resource**: { **'Fn::Join'**: [**''**, [**'arn:aws:s3:::<YOUR_S3_BUCKET_NAME>'**]] }
    - **Effect**: **'Allow'
      Action**:
        - **'s3:getObject'
      Resource**:
        **Fn::Join**:
          - **''** - - **'arn:aws:s3:::<YOUR_S3_BUCKET_NAME>'** - **'/*'**

在 app.py 中,确保我们从 S3 加载数据,而不是从本地磁盘读取数据。

*# path = '{}/data/{}.csv'.format(os.path.dirname(os.path.realpath(__file__)), ticker)
# df = pd.read_csv(path, index_col='Date', parse_dates=True, usecols=['Date', 'Close'],
#                               na_values=['nan'])* df = pd.read_csv(**'s3://<YOUR_S3_BUCKET_NAME>/{}.csv'**.format(ticker), index_col=**'Date'**, parse_dates=**True**,
            usecols=[**'Date'**, **'Close'**], na_values=[**'nan'**])

部署到 AWS Lambda

现在到了激动人心的部分。让我们将服务部署到 Lambda。

(venv) **➜  stock-backend** sls deployServerless: Adding Python requirements helper.......Service Informationservice: stock-backendstage: prodregion: us-west-2stack: stock-backend-prodresources: 11api keys:Noneendpoints:ANY - https://9rn0mg6p6b.execute-api.us-west-2.amazonaws.com/prodANY - https://9rn0mg6p6b.execute-api.us-west-2.amazonaws.com/prod/{proxy+}functions:app: stock-backend-prod-applayers:NoneServerless: Run the "serverless" command to setup monitoring, troubleshooting and testing.

最后,您将获得新 API 的端点。这是来自 API 网关的 URL。你可以在你的浏览器上测试一下。请注意,您的 URL 会有所不同。我们用浏览器或者 curl 来测试一下。以下是结果。现在我们有了运行在 AWS Lambda 上的后端服务。部署很容易。

如果你对 AWS 创造了什么感兴趣,你可以登录你的 AWS 控制台找到答案。它创建用于部署的 S3 桶和云形成资源。使用 Lambda 执行的新 IAM 角色创建 Lambda 函数。此外,该角色还具有用户定义的角色,可以访问股票数据 S3 时段。

下一步是什么?

我将把上一篇文章中的 UI 与运行在 lambda 上的后端连接起来,然后将 UI 部署到 AWS。敬请期待!

建议读取:

全面了解亚马逊网络服务(AWS)

AWS Lambda 在行动:事件驱动的无服务器应用第一版

亚马逊网络服务第二版

以前的帖子:

我关于金融和科技的帖子

我关于 FAANG 访谈的帖子

从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅

全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中

全栈开发教程:在 Angular SPA 上可视化交易数据

强化学习:Q 学习简介

全栈开发教程:在 Angular SPA 上可视化交易数据

原文:https://towardsdatascience.com/full-stack-development-tutorial-visualize-trading-data-on-angular-spa-7ec2a5749a38?source=collection_archive---------22-----------------------

Photo by Carlos Muza on Unsplash

(这篇文章也可以在我的博客中找到)

本系列的下一篇文章:全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据

作为一名数据科学家,您是否曾想过如何在 web 应用程序中为您的用户可视化您的数据?我将演示一系列的全栈开发教程来创建一个简单的 web 应用程序——stock graph 的 Angular 用于 UI,AWS serverless Lambda 用于后端,AWS API gateway 用于 API 管理,CloudFormation 用于持续部署。

这篇文章演示了如何在 Angular 单页应用程序(SPA)中可视化股票数据。在本教程的最后,您将创建一个带有组件的 Angular 应用程序,用于在客户端显示股票数据。本教程中没有服务器交互。所有数据都存储在客户端。源代码可以从这里下载。

安装 node.js 和 Angular CLI

创建新的 Angular 应用程序并安装依赖项

运行以下命令并相应地回答问题,以创建新的角度应用程序。然后安装用于造型的 ng-bootstrap 和用于显示图表的泳道/ngx-charts 。

在 app.module.ts 中包含 NgxChartsModule 和 browseranimentsmodule。Ngx-charts 在 app 模块中使用 browseranimentsmodule,以便随时可以使用。

在 angular.json 的 styles 数组中添加“node _ modules/bootstrap/dist/CSS/bootstrap . min . CSS”

现在,打开终端并运行 ng serve,您应该能够在 http://localhost:4200/ 中看到下面的示例应用程序

创建一个组件来显示股票图

在终端中运行以下命令创建一个新组件

ng generate component chart

该命令完成后,将创建一个新的目录“chart”。它包含一个 spec 文件(用于单元测试),一个 TypeScript 文件(。ts 文件),它包含用于呈现 UI 的逻辑和模板文件(.html 文件),它包含 UI 的标记。在模板 chart.component.html 中,用以下代码替换代码以正确配置图表。颜色方案、结果数据集、x 轴或 y 轴标签等属性是 ngx-charts-line-charts 的属性。我们用相应的变量来设置它们,这些变量将在 chart.component.ts 中声明和赋值。

在我们跳到 chart.component.ts 中的业务逻辑之前,让我们创建一个存储历史股票数据的界面。在 src/app 目录下创建一个 model.ts,内容如下。

现在让我们生成一个服务来提供历史数据。对于本教程,数据将被稳定地存储在 typescript 文件中。在现实世界中,它应该从远程服务器获取。我将有另一个教程来涵盖这个主题。在终端运行 ng 生成服务库存数据

一旦我们有了服务来提供数据,我们需要更新 chart.component.ts 来更新绑定到 UI 的变量。下面是 typescript 中更新后的 ChartComponent。

接下来,我们需要更新 app.component.html,以确保应用程序显示我们刚刚创建的图表组件。

现在,您应该能够在 http://localhost:4200/ 中看到新创建的图表

下一篇教程,我将展示如何用 python 构建后端 API,用 AWS Lambda 无服务器服务提供数据。保持调谐!

建议读取:

全面了解亚马逊网络服务(AWS)

AWS Lambda 在行动:事件驱动的无服务器应用第一版

亚马逊网络服务第二版

我的帖子:

我关于金融和科技的帖子

我关于 FAANG 访谈的帖子

从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅

全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中

全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据

强化学习:Q 学习简介

全栈开发教程:在 Angular SPA 上可视化交易数据(1)

Azure 上的全栈机器学习

原文:https://towardsdatascience.com/full-stack-machine-learning-on-azure-f0f6b77be07e?source=collection_archive---------14-----------------------

使用 MERN 在 Azure 上构建全栈机器学习网站指南(Mongo,Express,React (Node.js))

Tech stack and flow for http://diamonds.foostack.ai

在对最新技术感到生疏后,我决定同时学习一系列东西,并开发了http://diamonds . foo stack . ai,现在已经上线。(基础机器学习 app 给钻石定价)。

我的女朋友让我给她买一枚钻戒,我告诉她“不,等等!!!我必须先建立一个定价应用程序/网站……(在家试试)”

本博客中的步骤和章节概述:

  1. 使用 Python 获取数据
  2. 使用 ScikitLearn 在 Jupyter 笔记本电脑中培训 ML 模型
  3. 将 ML 模型部署到 Azure
  4. 在 React w/ Express 上构建前端
  5. 构建后端 Express,MongoDB
  6. Azure Web 应用部署和 CI/CD
  7. 总结、提示和技巧

回顾我的 github 签到记录,这个项目花了我 1 个月(26 天)——可能每周花 8-10 个小时,所以大概 40 个小时以上。最终产品还不算太差:

http://diamonds.foostack.ai

步骤 1:获取数据

我在网上搜索好的钻石数据。我发现:

  • Kaggle 的钻石数据集有 50k 行,但与我找到的其他数据集进行交叉比较时,它似乎缺乏真实世界的定价准确性。
  • 其他“[实验数据集](https://datasciencereview.com/case-study-does-the-size-of-diamonds-affect-its-price -- https://vincentarelbundock.github.io/Rdatasets/csv/Ecdat/Diamond.csv)”是旧的或者类似地与当前价格不同步。
  • 一些商业供应商出售更新的钻石库存/价格数据,但我不愿意付钱。
  • 零售网站有数据,但需要搜集(bluenile.com,rarecarat.com 等)

解决:被爆料加强刮不违法 —我在刮BLUENILE.COM——(感谢安德鲁·马尔德的首发码)。

My source of data!

安德鲁斯的代码基本有效,除了:

  • 它是用 Python 2.7 写的,所以有一些问题
  • 自从他写了以后,网站上的数据格式改变了
  • Bluenile 不断发展,目前已经阻止了运行此类脚本的吸血鬼

我唯一的黑客/贡献是在他们一直关闭我的时候添加重试循环:

# (bluenile API restricts to 1,000 page chunks at a time)
home = requests.get('http://www.bluenile.com/')
while True:
   url = 'http://www.bluenile.com/api/public/diamond-search-grid/v2'
   try:
      response = requests.get(url, params, cookies=home.cookies)
   except:  # request api exception, usually timeout
      time.sleep(60*30)
      next
   if (response.ok == False):  # server may have disconnected us
      time.sleep(60*30)
      next
   else:   # all going well
      time.sleep(60*4)
      next

最初的脚本进行了内联清理——我选择了下游清理(通常是个坏主意)。

输出示例 1 行(注意需要清理的$逗号引号等):

carat,clarity,color,culet,cut,date,dateSet,depth,detailsPageUrl,fluorescence,hasVisualization,id,imageUrl,lxwRatio,measurements,polish,price,pricePerCarat,sellingIndex,shapeCode,shapeName,skus,symmetry,table,v360BaseUrl,visualizationImageUrl,willArriveForHoliday
['0.23'],['FL'],['D'],['None'],"[{'label': 'Ideal', 'labelSmall': 'Ideal'}]",['Sep 30'],['Oct 1'],['58.8'],./diamond-details/LD12750672,['None'],[True],LD12750672,,['1.01'],"[{'label': '4.04 x 4.00 x 2.36 mm', 'labelSmall': '4.04 x 4.00 x 2.36'}]",['Excellent'],871,"['$3,787']",0.7348354,['RD'],['Round'],['LD12750672'],['Excellent'],['60.0'],https://bluenile.v360.in/50/imaged/gia-7313767639/1/,https://bnsec.bluenile.com/bnsecure/diamondvis/gia-7313767639/still_230x230.jpg,False

最后,我的抢劫成功了 14 万颗圆钻!我将这些保存到一个 CSV 文件中,用于清理和模型训练。

第二步:用 Jupyter 和 SKLearn 训练模型

Jupyter 笔记本很棒(看我的全笔记本这里):

  • 当我试验不同的想法时,用简单的方法来注释我的想法——有助于以后修改或传递给其他人!
  • 比 VS 代码项目设置和运行更快——隔离细胞和独立运行的能力就像修改过的 REPL!
  • 可视化更容易操作,因为您可以重新运行单元,只绘制图形,而不是重新运行整个程序!
  • (上面的一些可以用调试器和 REPL shell 来完成,但是看起来更干净&更容易在笔记本上重现)

对于数据清理,一些选项:

  1. 通过 python 脚本清理:CSV -> scrub.py -> CSV
  2. 在笔记本内拖动:CSV ->笔记本-> pandas/python -> CSV
  3. 在数据库内部清理:CSV-> MongoDB-> SQL scrubbing-> CSV
  4. 使用其他工具,如 Alteryx、Trifacta 或 Informatica

选项#1 可以工作,但是为什么还要处理另一个脚本/env。#2 看起来是正确的方法,因为我们在 ML 之后使用 Python 和笔记本。#3 听起来我们在推迟不可避免的事情,而不是把垃圾放入数据库。#4 对像我这样的穷人来说不是一个真正的选择。

使用熊猫进行擦洗&数据帧

熊猫是令人惊奇的东西。加载我的 CSV 很容易,数据帧上的 describe()显示了一些基本的统计数据:

**import** **pandas** **as** **pd**
diamonds5 = pd.read_csv('./blue-nile-download-round-full.csv')
diamonds5.describe()

describe() and head() of the pandas.Dataframe

如前所述,数据存在一些问题,这是我的数据相关培训前任务清单:

  1. 确定在生产模型中使用哪些列
  2. 将文本转换为干净的文本(即删除[])
  3. 正确转换数字(删除$和,并删除[]和'')
  4. 处理关键字字段中的空值或超出范围的值
  5. 剔除异常值(使用≤ 4.5 克拉,因为此后会变得稀疏)

完成后,我们对克拉和切工(颜色)进行一点视觉图形检查,以确定价格——使用 Jupyter 非常简单:

fig, ax = plt.subplots()
**for** c, df **in** diamonds5a.groupby('cut'):
    ax.scatter(df['carat'], df['price'], label=c, s=np.pi*3)
fig.set_size_inches(18.5, 10.5)

Price to Carat (to Cut)

虽然形状和深度等一些指标可能对预测有价值,但我真的想只关注 4-C——克拉、净度、颜色和切割(加上 sku,这是 BlueNile 中的 ID)。我可以放弃剩下的。

(注意,我发现烦人的 DataFrame 有一些 mutator 函数就地改变 obj,还有一些返回改变后的对象。似乎有点不一致?)

# basic cleanup functions
def cleanBracketsToF(x):
    return float(cleanBracketsToS(x))def cleanBracketsToS(x):
    return x.replace("['",'').replace("']",'')def cleanCut(str):
    return str[str.index('label') + 9: str.index('labelSmall')-4]df.loc[:,'carat'] =   
    df.loc[:,'carat'].to_frame().applymap(cleanBracketsToF)
...*# clear nulls*
pd.set_option('use_inf_as_na', **True**)
df = df.loc[~df['carat'].isnull()]
...

在清理并仅包括培训所需的列后,我们有了这个(第一列是熊猫 DF 标识符,它是内部的,以及我们稍后为培训删除但稍后为显示/链接回 bluenile.com 而包括的 SKU):

Pre column encoded

接下来,我们需要转换非数字(切割,颜色,清晰度)。您有几个编码选项:

  1. Onehot 编码(可能是最常见的,将类别转换为二进制列)
  2. 顺序映射,如果它是分级的/连续的(例如,对于颜色,D->0,E->1,F->2 …)或者反过来(K->0,J-> 1…)

我用 sklearn 的 Pandas.get_dummies()调用去了 Onehot

cut = pd.get_dummies( diamonds5b['cut'], prefix='cut_')# result: cut__Astor Ideal', 'cut__Good', 'cut__Ideal','cut__Very Good'
# do the same for color, clarity...

OneHot 编码我们的数据现在看起来像这样:

Post OneHot encoded “cut”

我学到的一件棘手的事情是,如果你在一个 Hot 上对所有列进行编码,你可能会产生一个线性代数问题,这个问题是“奇异的”,这个小故事破坏了这个模型。阅读 这篇关于的假人陷阱。

这是将 one-hot 应用于所有列并测量系数的最终结果(将其视为每个特征的权重):

Column coefficients of for a linear model

以下是 reg 中的准确重量。_coeff

coefficients: [ 1122.35088004  -957.70046613   471.56252273  3604.24362627
  3443.65378177  3128.96414383  2340.71261083  1717.39519952
  1673.9767721    590.1060328  10566.54997464  1383.32878002
 -1131.5953868  -1340.53213295  -457.74564551  -848.77484115
   540.46973926 15014.89306894]
intercept: -8389.974398175218

这意味着线性预测模型主要基于克拉(有道理)和完美无瑕的钻石。该等式的结果类似于:

y = -8389 + 1122*(cut == Astor ? 1: 0) + ….. + carat*15014)….

例如,如果我们为 1.0 克拉、切割理想、颜色 G、净度 VVS1 的钻石定价,计算结果为:

y = -8389 + 1*15014 (carats)+ 1*471 (cut)+ 1*2340 (color)+ 1*540 (clarity) = $9,976 

在 SKLearn 中训练一个模型——大部分代码是这样的。警告——你可能会花很多时间调试错误的形状&数组&矩阵的方向!

regr = linear_model.LinearRegression()
regr.fit(X_train, y_train)               # training
y_pred = regr.predict(X_test)            # inference
r2score = regr.score(X_test, y_test)     # get r2 score

R2 分数值得一提——它不是一个“准确性”分数,所以不要期望得到 99%。这是对准确性/差异的一种衡量,更多信息请点击@ R2 维基。

我测试了其他的 SKLearn 模型:岭回归、套索回归、保序回归(克拉上的单一特征)、弹性正则回归。较新的 AutoML 框架(H2O、DataRobot、Azure AutoML、SageMaker 等)同时测试所有模型&超参数..让很多业余 DS 失业..

接下来,我再次使用相同的数据集应用树和集成方法。尝试各种超参数组合后的最佳性能(R2)不足为奇 XGBoost:

est = GradientBoostingRegressor(n_estimators=ne, learning_rate=lr,
    max_depth=md, random_state=8, loss='ls').fit(X_train, y_train)
score = est.score(X_test, y_test)

Rough feature weights w/ XGB

查看特征权重——克拉是最高的,其他具有中等影响(有趣的是,完美无瑕的清晰度不如线性回归有影响力)。

系数对于确定每个特征的“重要性”可能不是最佳的。 Shapley 值似乎更符合行业标准。

一旦在笔记本中进行了训练,我们就使用 SKLearn 的 joblib 库导出所有经过训练的模型,以便稍后进行部署(该库将文件“pickless”或序列化为专有格式(阅读 pickle 的一些不好的方面))。

joblib.dump(value=regr_full, filename='regr_model.pkl')
joblib.dump(value=model, filename='xgb_model.pkl')
joblib.dump(value=rfr, filename='randomforest_model.pkl')
joblib.dump(value=iso_reg, filename='isoridgelineartreg_model.pkl')

步骤 3:将模型部署到 Azure

退一步说,我们有几种方法可以在生产中运行模型:

  1. 将预先训练好的模型嵌入后端。在我们的例子中,我们使用的是 Express (Javascript ),这不是最好的嵌入方式..
  2. 将预先训练好的模型发布到某个地方(比如 Python Flask 容器),并通过 webservice 公开。
  3. 使用像 Azure ML 这样的 API 发布和部署到他们的容器中。
  4. 使用 Azure ML Studio 这样的框架进行设计、训练和发布(半自动)。

我们将做#2、#3 和#4

第一步是在 Azure 上进行设置——如果这对你来说是新的,有几个基本步骤:

  1. 在 portal.azure.com 上创建帐户
  2. 你可以获得一段时间的免费订阅,但最终你可能需要创建一个付费订阅(小心$$$)。

创建新的 ML 服务工作场所

New stuff in Azure — evolving fast

我们可以使用新的 Azure ML API(尽管你应该看看 ML GUI 工作区——你可以启动 Jupyter 笔记本,尝试他们的菜单驱动 AutoML,ML Studio Visual GUI(下图),以及其他现在不断变化的东西……

Drag-n-Drop ML… iffy distraction at best

通过 Python API 设置模型

使用 API 在 Azure 上设置服务有几个步骤

  1. 注册你的模型(你的泡菜。pkl]文件)
  2. 设置环境文件和评分回调文件(。py 接口)
  3. 设置 web 服务(AciWebService)、模型、推理配置和部署。

注册真的很简单,每个模型做一次(pkl 文件):

ws = Workspace.get(name='DiamondMLWS',
    subscription_id='****',resource_group='diamond-ml')new_model = Model.register(model_path="mymodel.pkl"model_name=name,
    description="mymodel descr",workspace=ws)

Env 文件可以用这样的脚本生成(一次):

myenv = CondaDependencies.create(conda_packages=['numpy',
   'scikit-learn'])
with open("myenv.yml","w") as f:
   f.write(myenv.serialize_to_string())

评分文件如下所示,为每个模型实现 init()和 run():

#score_mymodel.py
def init():
   global model
   model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'),
        'mymodel.pkl')
   model = joblib.load(model_path)def run(raw_data):
   data = np.array(json.loads(raw_data)['data'])
   y_hat = model.predict(data)
   return y_hat.tolist()

最后一步包括设置服务、模型,并为每个模型部署一次:

aciconfig = AciWebservice.deploy_configuration(cpu_cores=1,
   memory_gb=1,tags={"data": "diamonds","method": "sklearn"},
   description='Predict Diamonds with sklearn')
ws = Workspace.get(name='DiamondMLWS', subscription_id='****',
   resource_group='diamond-ml')
model = Model(ws, name)inference_config = InferenceConfig(runtime= "python",
   entry_script="score_mymodel.py", conda_file="myenv.yml")service = Model.deploy(workspace=ws,
   name=svcname, models=[model], inference_config=inference_config,
   deployment_config=aciconfig)
service.wait_for_deployment(show_output=True)

就是这样!您应该会看到输出声明服务已经部署并返回 URI 以供访问,并检查 Azure 门户以查看它是否在那里。

Running.......................
ACI service creation operation finished, operation "Succeeded"
http://dds2f-97f5eb5c4163.eastus.azurecontainer.io/score

差不多就是这样。输入格式和输出由您在第 2 部分中创建的模型细节定义。你可以用 Postman 或 curl 测试 API 确保它是定价的:

Testing via POSTman

发布到 azure web service——价格 1.1 克拉,F 色,未切割,VVS2 净度钻石→ $11,272 是预测!

我不会深入讨论使用 GUI 驱动的 Azure ML Studio 的细节。您可以拖放、训练并最终发布一个 web 服务 URL(使用不同的输入/输出格式)。对于我的应用程序,我在 GUI ML Studio 中发布了 3 个模型,在 SKLearn 中发布了 4 个模型。查看 web GUI 上定价请求的输出:

Target aggregated results

请注意神经网络模型是完全疲惫不堪…不知道我是否会麻烦修复它…

由于 Azure ML 容器的成本,我选择将模型转移到 Azure 托管的 Flask Python 服务。这是非常少的代码——而且成本只是 Azure ML ACI 的一小部分($ 2/天每项服务,所以部署了 w/ 4 个模型,大概是$ 8/天..迅速破产的老道格·福】。重新部署非常容易。烧瓶中的 pkl:

app = Flask(__name__)
models = {}
models['XGB2'] = joblib.load('models/sklearn_diamond_xgb_model.pkl')
models['ISO'] = joblib.load('models/sklearn_diamond_iso_model.pkl')
models['LR3'] = joblib.load('models/sklearn_diamond_regr_model.pkl')print('loaded models', models)@app.route('/models/<model>', methods=['POST'])
def predict(model):
   if (models.get(model) is None):
      print('model not found: ',model)
      return jsonify("[-1]")
   j_data = np.array(request.get_json()['data'])
   y_hat = np.array2string(models[model].predict(j_data))
   print('input: ',j_data, ', results:', y_hat)
   return y_hatif __name__ == '__main__':
   app.run(debug=True)

步骤 4:用 React 构建完整的堆栈 ML 前端

同样,关于启动 React 项目& Express.js 项目的故事数不胜数,所以我将跳过一些步骤..

  • express 安装到我的项目文件夹~/diamonds 中
  • 安装 react ,用 create-react-app 在一个名为~/diamonds/diamond-app 的子目录中创建起始项目
  • 对于生产部署,它们通过 webpack 合并成一个单一的 express 捆绑包

React 与我以前使用过的所有其他框架相比

我对 Web 开发非常熟悉,比如 Perl-CGI、Php、JSP、ASP 和所有那些“Web 2.0”框架,包括传统的 AJAX。我也用过 Django,仔细观察过 Angular。 React 不同——有一个学习曲线。经过一番挣扎,我现在是你的忠实粉丝了!需要记住的关键事项:

  • 组件— 编码使用 JSX 语言,看起来像 Javascript,但略有不同。你通过 JSX 类或函数来编码组件(<标签/ >)。顶层组件通常是 App.js,在这里你可以添加你的自定义 JSX 和其他组件,比如< MyTag/ >。
class MyTag extends React.Component {
    const constvar = "Text"
    render() { return (<div>Hi {constvar}</div>) }
}
  • 状态 —动态渲染流程与您可能习惯的非常不同。React 有自己的生命周期,主要由“状态”(特殊变量)变化控制。声明一组状态变量,然后像变魔术一样刷新受影响的组件。见下文,随着动态的值的改变,GUI 组件将自我刷新。
class MyTag extends React.Component {
    constructor(props) {
       super(props);
       this.state = { dynamic: 'Dyn txt' }
    }
    const constvar = "Const Txt";
    render() { 
       return (<div>Hi {constvar} and {this.state.dynamic}  </div>
    )}
}
// equiv as a function, bit tighter ?  also use MyTag
function MyTag2() {  
    const constvar = "Const Txt";
    const [dynamic, setDynamic] = React.useState('Dyn Txt');
    return (<div>Hi {constvar} and {dynamic} and <MyTag/> </div>);
}
  • Props — props 是标签属性和组件/标签的子组件—传递数据的一种方式。您可以通过 props 将数据 向下 传递,但是调用 向上 需要一个回调函数(例如在 caller/parent 中定义的 myCallbackFunc)。
function MyTag2(props) {  
  const constvar = "Const Txt";
  const [dynamic, setDynamic] = React.useState('Dyn Txt');
  return (
     <div> 
       Hi {constvar} and {dynamic} 
       Hi {props.var1} 
       <Button onClick={props.callback} />
     </div>);
  }
}
function App() {
  function myCallbackFunc() {
     // do something on button click
  }  return (
     <div> 
        <MyTag2 **var1**=’var' **callback**={myCallbackFunc}>Text</MyTag2> 
     </div>);
  }
}

上例——你的 app 根是,在里面我们调用 MyTag w/ "props" var1 和回调以及内部的" Text "。

这需要一些拨弄来学习,但它实际上非常优雅——试试吧!

使用材料设计启动用户界面

Google 的 Material-UI 是 React 的一个组件库/框架,它给你提供了很棒的小部件和默认主题,这样任何人都可以让网站看起来很棒!我浏览了画廊,选择了仪表盘(在左边)开始。

Material-UI 有类似于布局和容器的组件来管理反应式/自动调整组件。包括一个漂亮的侧菜单

我在默认仪表板上做的主要事情:

  • 设置左抽屉默认关闭,添加帮助弹出链接到外部网站。
  • 更新了顶栏和新文本,替换了通知铃声和帮助
  • 在网格中实现了 3 个主要的“纸”容器:随机钻石、库存选择器/过滤器和 ML Pricer。

今日随机钻石

这是最容易建立的一个。假设/diamonds/daily/上有一个服务器 REST 端点,它返回一个 json (data.price,data.carat,等等..)—我们只获取组件负载(useEffect())并从结果中设置状态变量。

export default function Daily() {
  const [diamond, setDiamond] = useState({
    price:0.0,carat:0.0,color:'',cut:'',clarity: '',skus: ''
  });  useEffect(() => {
    axios.get('/diamonds/daily/').then(response => {
      setDiamond({
         price: response.data.price, 
         carat: response.data.carat, 
         ...
      });
    })},
  []);  
  return (
    <React.Fragment><Title>Random Diamond Featured</Title>   
      <Typography>Price: {diamond.price}</Typography>
      <Typography>Carats: {diamond.carat}</Typography>
      ...
    </React.Fragment>
  );
}

钻石过滤器

我想要一个基本的搜索表单,让我通过 140k 钻石过滤-图表+表格中的细节。

我选择 Victory 作为我的制图/绘图工具,因为它适用于反应式(也考虑了反应式和重新制图)。我不喜欢 material-ui 数据表(缺乏更高层次的抽象),所以选择了更小的开源 Material-Table 项目。在 React-land 中,您可以选择许多组件!

创建该组件的主要步骤:

  1. 使用 Material-UI 表单组件,在表单组中添加复选框,并实现克拉滑块。
  2. 实现 SearchButton 的 onClick
  3. 模仿或构建您的后端来返回一个列表中的钻石 JSON,我们在一个图形+表格中呈现(通过选项卡)— 更多内容在第 5 部分

参考 github 获取完整源代码。下面显示了如何将选项传递给服务器:

class Chooser extends Component {
  constructor(props) {
  super(props);  this.state = {
    D: true,
    E: true,
    F: true,
    G: true,
    H: true,
    AstorIdeal: false,
    Ideal: true,
    diamonds: [],
    ...
  }  handleSubmit = event => {
    // call REST api, setState of return diamonds[] etc
  }  render() {
    return (
      <React.Fragment >
         <Title>Filter Diamonds</Title>
         <FormControl component="fieldset" >
           ... checkboxes and button 
         </FormControl>
         <Paper square className={classes.root}>
           <Chart diamonds={this.state.diamonds}/>
           <DiamondsTable diamonds={this.state.diamonds} />
         </Paper>
      </React.Fragment>
   )
}

DiamondsTable 是一个第三方表格组件来查看数据网格。把钻石[]当道具传就行了。钻石[]状态的任何变化都会强制重新渲染。反应刷新魔法!

Tab to DiamondTable (customized react-table component)

ML 定价—终于!

我们已经接*目标—根据我们训练集中的 14 万颗钻石预测钻石价格。

控件非常简单——很像过滤器/选择器,我们有一个基本的表单和按钮。

代码结构非常相似:

  1. 带有 submitPrice 回调的 FormGroup 和 Button
  2. submitPrice 调用 REST 服务,传递输入{克拉、净度、切工、颜色}并返回设置为状态变量的钻石列表[]。
  3. 钻石[]作为道具传递到图表和表格中。
  4. diamonds[]状态的初始和任何后续更改都会触发使用 diamonds[]重新渲染子组件。

Full results of model prices and analytic graphs + unseen tab view to tabular results

来自上一步的过滤器( Chooser.js )和 Pricer.js 非常相似。 Pricer 是作为函数而不是实现的,因此语法略有不同。带状态的函数是新的“钩子”,被添加到 React 中,是完整类的更好的替代品。

步骤 5:在 Express 中构建 REST 服务(w/ MongoDB)

Express 是 JavaScript Node.js webserver。我仍然更喜欢 Python 中的后端,但我猜这个教程是 MERN,所以我必须使用/学习 Express(这并不太难)。一个关键的优势是当您拥有相同的前端和后端库时可以重用。

同样,我不会深入安装的基础知识。我将跳转到托管我的 API 逻辑的 server.js 脚本。我需要的主要 REST 调用:

  • 获得/钻石/每日-每日随机钻石
  • POST /diamonds/q/ —获取具有某些过滤标准的列表
  • POST /diamonds/q2/ —获取符合定价标准的列表
  • POST/diamonds/price——使用我的 ML 模型为钻石定价

首先让我们设置 MongoDB

为 Express 设置一个 Mongoose 模型,创建一个数据库并批量加载该数据库。

  1. 设置 Express 端点
  2. MongoDB 在 MLab 上免费— FYI Azure 有 CosmoDB,它(大部分)与 MongoDB 有线兼容。CosmoDB 最便宜的计划是 24 美元/月!

Mongo is free — vs $24/month on Azure

创建数据库后,您需要上传数据或手工输入数据。对我来说,最简单的方法是使用批量加载器脚本——要求您在 PC 上安装 MongoDB 客户端,并指向 MLAB 连接字符串。

mongoimport --uri mongodb://user:pass@host.mlab.com:12122/diamonds --collection myc --type csv --headerline  --file jsonfile.csv

上传 150k 的钻石条目速度很快,只需几分钟,并且确实使用了接* 0.5gb 的限制。全部完成!

2。Mongoose 模型— 创建一个脚本,定义一个与您的 MongoDB 集合的 JSON 格式相匹配的模式:

#diamond.model.js
let Diamond = new Schema({
  carat: {
     type: Number,
     default: -1
  },
  color: {
     type: String,
     default: 'Default'
  },
  ...
}, { collection: 'myc' });module.exports = mongoose.model('Diamond', Diamond);

3。Express.js REST 端点(server . js)都是下一步。

在那里,大部分都是样板文件。打开一个要共享的连接,设置任何备用映射(在本例中为 react path),并监听一个端口。在这两者之间,我们为各种 GET/POST 处理程序创建路由(在下一节中定义)。

app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://user:pass@host:port/diamonds', 
   { useNewUrlParser: true, useUnifiedTopology: true  });const connection = mongoose.connection;
connection.once('open', function() {
  console.log("MongoDB connection established successfully");
})//-- fill w/ diamondRoutes start
... see below
//-- fill endapp.use('/diamonds', diamondRoutes);// for webpack'd react front end 
app.use(express.static("./diamond-app/build")); 
app.get("*", (req, res) => {
   res.sendFile(path.resolve(__dirname, "./diamond-app", 
       "build", "index.html"));
});
app.listen(PORT, function() {
   console.log("Server is running on Port..: " + PORT);
});

接下来,我们填写 diamondRoutes — /daily /q /q2 和/price。/daily 很简单——只是一个返回 1 个 diamond 的随机查询(使用 diamond.model.js 中定义的 json 模式)

diamondRoutes.route('/daily').get(function(req, res) {
   let random = Math.floor(Math.random() * 140000);  // skip n
   Diamond.findOne().skip(random).exec(function(err, diamonds) {
      res.json(diamonds);
   });
});

/q 和/q2 都是类似的查询搜索,接受 POST 参数并映射到一个 Mongoose 查询——POST 输入是一个 JSON,如{carat:3,color:'D ',cut:' ',clarity:''}

diamondRoutes.route('/q2').post(function(req, res) {
   const qobj = req.body;
   query = Diamond.find(); 
   query = query.where('carat').
       gt(qobj.carat-0.05).lt(qobj.carat+0.05);   
   if (qobj.cut !== '') query = query.where('cut').equals(qobj.cut);
   if (qobj.color !== '') query =
      query.where('color').equals(qobj.color);
   if (qobj.clarity !== '') query =
      query.where('clarity').equals(qobj.clarity);  
   query.exec(function(err, diamonds) {   
      res.json(diamonds);
   });
});

POSTman test

调用/价格机器学习推理调用是通过另一个 REST API 调用 Azure ML Studio 的 farm 完成的(现在大部分是对 Azure Flask 服务器)。

请求链:React 客户端-> Express.js -> ML 服务->返回 Express.js ->返回 React 客户端。

我认为以块的形式显示代码会令人困惑,所以只看关键步骤,即使用“异步”调用 callSvc 函数,然后“等待”它们全部加入结果:

let r0 = await callSvc(p2.XGB.url, p2.XGB.token, reqJson);
let r1 = await callSvc(p2.LR.url, p2.LR.token, reqJson);
let r2 = ...

callSvc 只是执行一个 axios http POST 来获取 ML 预测。注意函数上的“async”定义,以及上面配对异步调用的 await 调用。

async function callSvc(apiurl, token, reqJson) {
    return axios.post(apiurl, reqJson, 
        { headers: {
            'Content-Type': 'application/json',
            'Authorization': token,
            }
        })
        .catch(function (error){
            console.log(error);
        });
}

对于前端来说,响应被合并到单个响应 JSON 中,注意 ML Studio 格式不同于我的定制 SKLearn 模型:

res.json([
   { price:r0.data.Results.output1.value.Values[0][6],model:'XGB' }, 
   { price:r1.data.Results.output1.value.Values[0][6],model:'LR' },
   { price:r2.data.Results.output1.value.Values[0][6],model:'NN' },
   { price: r3.data[0], model: 'ISO' },
   { price: r4.data[0], model: 'XGB2' },
   { price: r5.data[0], model: 'LR3' },
   { price: r6.data[0], model: 'RF' },
]);

通过 POSTMAN 查看链的外观(调用 express,它调用 ML 服务,汇总所有 7 个模型的结果):

Final test via POSTMAN->Express.js->ML Services

完整的故事请看完整的源代码。这就是大部分——我们现在已经构建了 express.js 后端!

步骤 6:React+Express 的 Azure 部署

部署到 Azure 站点真的很简单(当它正常工作时)——当出现构建或部署错误时会非常沮丧。祝你好运!

首先,您应该理解在开发中您可能运行 2 个服务器:

  1. 反应开发引擎(默认端口 3000)
  2. 快速开发服务器(默认端口 4000)

在 prod 中,您只运行一台服务器(Express ), React 的内容通过“npm build”被“捆绑”到一个 webpack 中,结果是这样的:

webpack results

您的 express.js 有指向这个构建/静态文件夹的代码

app.use(express.static("./diamond-app/build"));
app.get("*", (req, res) => {
     res.sendFile(path.resolve(__dirname, "./diamond-app", 
                  "build", "index.html"));
});

将这个项目签入 github,你就可以开始了!()。git 忽略 express.js (~diamonds)和 react (~diamonds/diamond-app)级别的 node _ modules)。

登录 Azure 门户并创建 Web 应用

creating an azure webapp

“testwebapp23”将变成http://testwebapp23.azurewebsites.net所以要小心命名,它以后不能更改(如果你拥有一个域,你可以在外部给它起个 DNS 别名)。选择最便宜的尺寸,B1 将花费你大约 15 美元一个月!

我会检查 Azure Web App 的配置面板,确认一些事情:

double check the config

接下来,您需要在Azure devo PS(https://dev.azure.com)中创建一个项目来托管构建环境。然后,转到项目设置(左下角)并将其链接到您的 GitHub repo,并启用管道:

管道将启用您的 CI/CD 设置,因此对 GitHub 的签入将触发构建和部署。有几种方法来设置它,每种方法都有其缺陷。奇怪但半简单的方法是跳回 Azure Portal,用他们的 webapp-> 部署中心结束。

Select GitHub — then Azure Pipelines

你可以选择 Kudu App Build 或者 Azure Pipelines。Pipelines 是最新的 Azure CI/CD 工具集(取代了 TFS)。两者都有问题..但是我发现对于 node.js 管道部署效果更好(对于 Python 我更喜欢 Kudu)。

完成,这将创建您的第一个构建和部署。如果你幸运的话,它可以工作,你可以像这样在线查看你的应用程序:

It works!

跳回 Azure DevOps,你会看到它生成了一个管道(构建)和发布(部署):

Code successfully built in Azure Pipelines

如果通过,则进入发布(部署):

您可以定制每个步骤,并添加一些漂亮的东西,如前/后脚本或如下所示的批准流程,以在您的环境中传播更改。一个变更触发了一个预生产(演示)构建,然后一旦我验证了构建,我必须手动批准发布到生产(diamonds.foostack.ai)。

第七步:技巧和烦恼

我学到并想提醒你的最重要的事情:

  • Azure Insights 非常适合跟踪使用统计数据(设置起来比你想象的要困难,你必须将代码与你的每个组件挂钩,但之后你会得到一些很好的遥测数据)

  • Azure 正在发展(正在崩溃),所以准备好面对一些麻烦,尤其是机器学习和管道等新事物(linux 上的 node.js 版本突然崩溃..几个星期以来,Azure 团队一直在努力清理这场灾难:

  • Scrum Boards 和票证管理可以在 Azure DevOps 中完成,并与 GitHub 集成。它很新,但对于一个小项目来说还不错。

  • 成本管理 —密切跟踪。每个机器学习模型的成本有点疯狂(每个模型容器/天 2 美元,仅 12 天就花了我 100 多美元)。这促使我迁移到 Flask。在另一个项目中,SQL Warehouse 用了 2 天就超过了 100 美元!小心,设置成本警报!

  • Python Flask Deploy——因为上面的成本问题,我晚加了这个。我使用传统的来自 WebApp- > Deployment 的 Kudu build,而不是 Azure Pipelines,因为我一直使用 Azure Pipelines 时出现了一些错误。

Python Flask using older Kudu deployment (works !)

  • ****域名设置真的很简单——Azure 不这么做,去namecheap.com——然后在 Azure 上链接就行了。非常简单的说明。

编码快乐!在线阅读 livehttp://diamonds . foo stack . ai网站、 github 项目或 Jupyter 笔记本。

面向数据科学家的复杂解决方案全栈可视化

原文:https://towardsdatascience.com/full-stack-visualizations-for-complex-solutions-for-data-scientists-5afc488f60d?source=collection_archive---------8-----------------------

笔记本不够用怎么办?

这篇文章主要面向那些希望围绕他们的解决方案快速开发一个界面的数据科学家。虽然您确实可以在 Jupyter 笔记本或其他地方构建一些 交互式 仪表盘 ,但我个人在我的几个项目中遇到了它们的局限性。此外,有时让人们去玩解决方案比你向他们解释要容易得多。

我的目的是向您展示一个路线图&一些片段让您尽可能快地开始,这样您就可以制作类似于这个简单的演示(下面的快照)的东西,它在后端运行 python(在更复杂的版本中用于集群的 DBSCAN ),并在客户端呈现结果,以便您将结果发送给公司的决策者,让他们大吃一惊。

Route optimization demo using Google Constraint Solver (DBSCAN is used in a more complex version all on the back-end)

无论是创建演示,还是将其添加到您的投资组合中,或者是向公司的管理层和利益相关者传达一些故事,能够快速将简单的用户界面包装在您的解决方案周围都可以极大地帮助您实现目标。在大多数情况下,您可能能够在笔记本或档案中包含一些图表&漂亮的图表,但是如果您需要某种程度的用户交互,而这在 Jupyter 笔记本或合作实验室中是不可能的,该怎么办呢?如果老板问“你能不能把一些东西组装起来,这样我以后可以玩玩?”或者“你能做一个演示,让我在你不参加的会议上使用吗?”。基本上,他们要求一个 URL 来点击并看到它的神奇之处,此外,这确保它每次都能按预期工作,而不会有人不小心弄乱你的代码,等等。

对于一个对 HTML 知之甚少的人来说,在没有任何教程的情况下从头开始开发这样的演示可能要花费一周的时间。然而,我希望在完成下面的步骤后,你能在几个小时内完成这样的事情。

您可能已经发现,这样的接口需要两个方面。在后端,您可以运行您的 python 魔术,在客户端,您可以将结果呈现为一些迷人的、令人瞠目结舌的图形,以便在给用户一些自由度来进一步探索您的解决方案的同时传递信息。我通常把我的后端放在 Google App Engine 上,它可以存放你的 python 代码,当你在前端触发它时就运行它,但是你也可以很好地使用 AWS 或其他服务。这里没有特别的偏好。

前端是我们用 HTML、CSS 和 JavaScript(JS)编写的地方。后端是你可以存储数据,利用云计算,甚至运行代码,而不需要使用你的用户(客户端)资源(想象一下他们的手机,电脑)。

后端

出于这个例子的目的,我们需要设置我们的后端,以便它能够响应一些 URL 请求。换句话说,当您在浏览器中输入一个 URL 或者通过一些 JS 代码(比如 fetch()、XMLHttpRequest()等)发出请求时,每个函数都会运行。(稍后您将看到一个示例)。因为我们正在编写后端来执行一些 python 代码(所以我们可以在以后享受做一些数据科学的酷东西——嘿,这里没有偏见:p)我们利用 Flask——python 的一个简单的 web 开发框架。

Flask 是基于 Werkzeug、Jinja 2 和 good intentions 为 Python 开发的微框架。在你问之前:它是 BSD 许可的!

您需要编写您的 python 脚本并将其托管在服务器上的某个地方,这样每次请求 URL 时,就会触发一个或多个 python 函数。您可以将一些数据传递给该函数,并最终获得一些数据,在本演示中,这些数据将是优化的路线和车辆信息。附带说明一下,这个简单的演示利用了 Google 或工具来解决一些教科书式的旅行推销员问题,这里的约束条件被定义为时间和卡车负载。

如果你之前没有用过 app engine,最简单的入门方法就是注册后按照 App Engine 中的教程进行操作。选择 Python 作为您的语言,并遵循 Hello World 教程的结尾。然后回到这里。

在浏览了关于 App Engine 的 hello world 教程后,你应该能够创建一个应用程序,并使用命令行或浏览器中的嵌入式 shell 和编辑器(我个人喜欢后者)将其部署到 Google App Engine,你真正需要创建的只是一个简单的 Flask 应用程序,如下所示。请记住,首先安装您将在后端代码中使用的包,如 Flask、或-tools 等。这意味着您需要将它们添加到 requirements.txt 文件中,然后进行安装(见下文)。

Simple Flask app for the back-end to trigger our functions via some URL requests

现在,如果我们向上面的“baseURL-of-project/vrp”发出请求,我们只是触发了与之相关的函数。简单吧?!这很棒,因为你可以在后端做任何你想做的事情,甚至添加复杂的建模和使用所有你需要的机器学习库,等等,然后将结果传递给你的客户端,以呈现一个漂亮的图形或图表。

前端

听到“前端开发”可能会吓到你,但我向你保证,你不需要知道一切来开始。你可以试着通过 python 来完成,但是我个人更喜欢 HTML、CSS 和 JS。以下是几个概念,每个概念都有很好的学习来源,应该是你需要开始学习的全部内容;

  1. 基础 Javascript
  2. 承诺
  3. 获取()或 XMLHttpRequest ()以在客户端(前端)发出我们的 URL 请求

我不会告诉你什么是最好的,因为有大量的前端库、包和框架。对你有用的就应该是好的。如果你没有任何线索,那么我建议你从浏览( PWA 初学者工具包)开始,你应该很快就能开始编写非常棒的尖端 web 应用程序。

我们需要一个简单的 HTML 页面来包含我们的演示 UI 元素,如按钮,输入字段,也许谷歌地图,因为它太简单了。记住,要使用谷歌的服务,比如地图,你需要在谷歌的相关网页上创建一个免费的 API 密匙。为了渲染地图,你可以简单地从这里开始和这里的。

一旦你有了一个动作按钮设置&你想把它连接到后端,你只需要在一些用户交互时向我们的触发 URL 发出请求,例如,在我们的例子中,当用户点击“优化路线”时。我们通过我们附加到按钮上的点击监听器(下面将详细介绍)捕捉到这个信息,并运行下面的函数。

JavaScript function where we make a POST request to our back-end URL

为了让你知道我说的点击监听器是什么意思,下面是一个功能演示的例子在这里。

<!DOCTYPE html>
<html></html><h2>JavaScript addEventListener()</h2><p>This example uses the addEventListener() method to attach a click event to a button.</p><button id="myBtn">Try it</button><p id="demo"></p><script>
document.getElementById("myBtn").addEventListener("click", displayDate);function displayDate() {
  document.getElementById("demo").innerHTML = Date();
}
</script></body>
</html>

请注意我是如何在 _optimize ()方法的请求体中以字符串形式传递数据的。我还利用了 fetch 函数,该函数返回一个承诺,允许我在结果返回时检索它。完成了。一旦你有了结果,你可以简单地通过 console.log(response.json())把它打印到控制台上,进入谷歌浏览器的开发者工具,确认你收到了结果。另外,您需要在 App Engine 中将******替换为您的项目名称。除此之外,所有这些都是 JS 以您喜欢的方式处理和呈现您的数据。有很多 JS 图形库。 D3.js 是我的最爱之一。

托管您的前端

所以,你已经写好了项目。现在你需要通过一个可以和懒人分享的 URL 来访问它(lol)。你需要的只是一个托管服务。周围有很多托管服务。我一直在使用相对较新的谷歌 Firebase 服务,因为它的学习曲线非常短。你可以选择任何你喜欢的服务。要在 Firebase 上托管您的项目,您需要通过 Firebase 控制台创建一个项目(需要几分钟)。然后转到机器中的本地项目文件夹,初始化 Firebase 并连接到新创建的 Firebase 项目。不要担心所有这些都是一步一步的概述这里。然后从本地项目目录中输入下面的命令来部署您的项目。

firebase deploy

然后,该 URL 会显示在 Firebase 控制台的主机下。这就是了。

结论

如果您开始一个基本的 UI,您可以轻松地将您的数据科学项目包装到一个更高级的交互式外壳中,这将使任何人都可以自由地玩和不喜欢玩!!我个人已经看到了以这种方式展示你的解决方案的优势。虽然您确实可以通过 Jupyter 笔记本或其他工具为简单的项目创建一些交互式菜单,但构建更复杂的仪表板通常是前端开发人员的任务。我认为,作为一名努力变得更好的数据科学家,你不必依赖他人的时间表或技能。所以,帮你自己一个忙,花一个周末在这上面,掌握它&享受你将因此获得的自由。

如果你按照我提供的教程和链接,你应该可以在一两天内开始构建。后端应该非常简单,因为它主要是 python 而不是 Flask shell。对于以前没有做过前端开发的人来说,前端可能需要更多的时间。我希望我已经提供了一步一步的指导,让你去,但我可能会添加更多的细节取决于我得到的评论。请让我知道我如何才能改善这个职位,我会这样做。

参考文献

[## 用 Jupyter 构建交互式仪表盘

欢迎来到“高级 Jupyter 笔记本技巧”的第二部分在第一部分,我描述了魔术,以及如何计算笔记本…

blog.dominodatalab.com](https://blog.dominodatalab.com/interactive-dashboards-in-jupyter/) [## Jupyter 笔记本上一个非常简单的交互控件演示

当使用交互式小工具时,笔记本变得生动起来。用户可以可视化和控制数据的变化。学习…

towardsdatascience.com](/a-very-simple-demo-of-interactive-controls-on-jupyter-notebook-4429cf46aabd)

全栈编程:失败的前奏

原文:https://towardsdatascience.com/fullstack-programming-a-prelude-to-failure-2bc93cf19e71?source=collection_archive---------12-----------------------

神话,现实,荒谬

简介:

如果你是这种认为自己是“全栈程序员”的新老时尚“称谓”的一部分,或者拥有无数让你负责技术的头衔(例如,首席技术官、副总裁 R&D、技术负责人等)。)为了你自己和你的公司,你应该花几分钟时间来阅读这篇文章。如果你个人认为这篇文章质疑了你的能力,我首先向你道歉。 然而,在你勃然大怒、口吐白沫、发疯并根据标题和你对“全栈”思想的坚持来否定整篇文章之前,让我们首先尝试定义和理解围绕全栈编程愿景的实际困境。

我无法确定“全栈”这个术语是从什么时候开始被广泛用于描述一个编程职位的。它就像其他许多术语一样,随着时间的推移而时隐时现。例如,已经变得非常流行的术语“DevOps”以其最基本的形式代表了永恒的开发、准备和生产周期。如果小心应用,应该可以缩短从编程到实现的时间。最*,你也会注意到“CI/CD”这个术语。当我第一次看到它的时候,我觉得自己像个傻瓜,对自己说“这到底是什么意思?”,就去查了一下。当我意识到它代表“持续集成/持续开发”时,我简直笑破了肚皮。开发运维的 YAT(另一个术语)(基于敏捷、Scrum 或看板等方法。等等。)!因此,对于技术领域的任何人来说,“Fullstack”越来越受欢迎,越来越受关注,这并不奇怪。突然间,我面试或交谈过的一半程序员都一本正经地直视着我,说:“我是一名全栈程序员”。

然后我问,就像我问 CI/CD 一样,“那到底是什么意思?”。当我听到有人吹嘘他们的全栈能力时,问题来得又快又激烈(是的,我承认有点讽刺。)

1.你指的是哪一堆?贵公司正在使用或打算使用的技术是什么?

2.你自称懂 Angular,Vue,HTML & React?完全了解他们吗?

3.可以用 NodeJS,Java/Scala,C++,PHP,Python,Golang?你知道所有那些语言,并且很了解它们?

4.你了解 JSON,以及在深度嵌套的情况下如何真正使用它?

5.你知道 AWS,Azure 等。所有的部件呢?从 EC2 到 NAT 网关,再到 AWS 提供的所有 1001+模块?

6.您是 Redis 和 Memcached 方面的专家,知道如何设置和正确使用 Redis 系统,以及使用它做什么?

7.你知道 IOS 原生和 Android 原生以及使用 React 不使用原生代码吗?

8.你知道 SQL 和 NoSQL 吗?它们之间的区别以及如何操作?你懂 MySQL,Postgre/Postgres SQL,MongoDB,Hadoop,Cassandra,Apache Spark?

9.或许最重要的是,您知道如何保护您所有的数据,包括静态数据和传输中的数据吗?

我只是让问题飞,没有等待答案。因为人们可以很容易地把上面的问题变成 25 个或更多。任何胆敢告诉我他们知道以上所有的事情,并且非常了解它们的人,不是傻瓜就是骗子。那么,我们所说的“全栈”是什么呢?首先也是最重要的,定义你的全栈。我不知道你说的“全栈”是什么意思!

为了理解什么是真正的堆栈,让我们举两个简单的堆栈为例,它们都是词汇和缩写词,在技术领域很常见。技术专家知道“灯”堆栈和更新的“*均”堆栈。LAMP 代表“Linux、Apache、MySQL 和 PHP”。MEAN 代表“MongoDB,Express,Angular,NodeJS”。*均堆栈中包含一个前端,即 Angular。灯堆没有。

毫无疑问,可能有数百个“堆栈”。所有这些都是为了确定和阐明特定项目所需的技术。他们定义技术。他们从来没有打算也不应该被用来定义一个特定工作 的程序员的实际资格。事实上,这篇文章的全部论点是,如果成功是你的目标,那么“全栈”应用于程序员是一个神话和可怕的错误。

神话

我认为没有人能把一个具体的原因归结于“全栈”编程的出现。我有我的理论和假设,虽然它们的混合,然后延续了全栈神话可能是最好的猜测。我相当肯定 fullstack 的想法是出于好意。在一个程序员身上结合一种专长和另一种专长。这是合乎逻辑的,因为许多优秀的程序员确实有能力以胜任的方式处理两种技术。然而,和所有事情一样,“fullstack”不受约束,已经成为一个包罗万象的术语,需要大量的专业知识,涉及广泛的技术。这是一个神话——尽管是当今公认的编程方式。

1.资金有限 —现实一点,有预算。无论是在初创公司还是在大公司,这都是理所当然的。创建预算是为了确保燃烧率不会造成失控的列车,并且公司能够吸收成本。这是经济学 101 和那些选择忽略通过销售保证筹集或赚到的钱的人的灾难。因此,这似乎很有意义,与其拥有一个每个人(或团队)都是一两件事的专家的编程团队,为什么不拥有能够做所有事情的人呢?“全栈”获得了它自己的地位。毕竟,许多公司要求他们的 CTO“亲力亲为”(HO),这样他们就可以做两份工作——一份是编程,一份是管理其他程序员。那么为什么不把各种“专长”结合到一个岗位上呢?这确实节省了资金,并且有运行小而紧密的团队的额外优势。

2.编程团队的后援 —另一个突出的点,我相信这一点,就是如果一个程序员生病或离开,在真正的“全栈”环境中,另一个程序员可以接管,直到找到替代者。毕竟,如果每个人都是“全栈”,他们应该都知道其他人知道什么。不需要某个特定领域的专家,因为假设每个人都是某方面的专家。

3.不知道需要多少知识——在最*一次与新任命的研发副总裁的公开谈话中,他问我对“全栈”程序员团队有什么想法。我用一个问题来回答。“栈是什么?”他说,就是 MongoDB,React,NodeJS 栈,包括微服务,lambda 等使用 AWS 的技术。我想了一会儿,很清楚地知道过于诚实会让我失去面试的机会。对我来说,“残酷的诚实”永远是赢家。我问副总裁,他是否明白他在要求他的程序员了解什么。

a.他们必须理解和了解 NodeJS,尽管普遍认为 NodeJS 不仅仅是 JavaScript 的扩展。它是一种有如此多可能性和中间件的语言,需要对同步和异步编程有深刻的理解。将微服务的正确实现添加到组合中是对 NodeJS 如何工作以及在编程结构中应该做什么(更重要的是不应该做什么)的另一个层次的真正理解。

b.MongoDB 是一个 NoSQL 数据存储库。许多人没有意识到的是,仅它就包含了一种超过 200 种可能调用的语言。它还要求对数据有深刻的理解,因为这不是你的关系、线性表。(即使在 SQL 系统中,也需要一个严肃的数据人员(DBA))。MongoDB 和所有 NoSQL 系统也需要无模式数据的知识。(见我在 Medium 的文章:“使用 Mongoose 处理你的大数据的重大错误”。)这本身就是一门科学。复制和分片呢?索引使用?了解何时使用 map reduce 和所有其他要点。

c.然后就是 AWS。AWS 中有大量的技术。Lambda 就是其中之一。它变得非常受欢迎,但如果没有正确实施,可能会变成一场噩梦(特别是在公司成本方面)。那么对 AWS 的其他要求呢?简单的 AWS 堆栈包括实例、NAT 网关、S3 的使用以及 AWS 提供的无数技术。这本身就是一项巨大的任务,很容易失控。

d.我在回答中补充了一些其他花絮。redis——何时何地使用?怎么用?如何熟练地操作 it 和数据。

e.谁来负责数据安全?这本身就是一份全职工作,而且在开发周期中经常被忽视,这很可怕。(如果不深入这个主题,请参见我在 Medium 上的文章:“设计网络安全技术系统的 10 个初始步骤”)。

f.如果这还不足以说明,仅仅通过描述期望一个程序员能够做以上所有的事情并且做得很好是多么疯狂,我接着去了前端。你是在告诉我,一个人将知道上面列表中的所有内容,并且还能够准备一个具有规范 UI 和 UX 的体面前端?即使它没有反应过来,(也许是最难的),但角或 Vue,它仍然是一个巨大的想象力。我不在乎那个程序员有多“忍者”。

应该清楚的是,任何“堆栈”都可以被分解成最相关的部分。一旦这一堆知识被仔细剖析,什么是需要的,什么是不需要的就变得很清楚了。期望一两个“全栈”程序员对所有这些活动部分有一个完整和全面的理解是在给你的系统招致灾难。

4.朴素&简单狂妄 —是的,有一些栈(例如 WordPress,Wix 等。)可以一个人跑。然而,任何声称拥有全栈知识的程序员或 CTO,有时我听到过对许多编程语言、前端和数据库结构(混合了 SQL 和 NoSQL)的这种说法,都是极端的狂妄自大。

现实

现实很简单。俗话说,“鱼和熊掌不可兼得”。很少有人能把一个“完整的堆栈”管理到一个*庸的程度,更不用说优秀的程度了。我和这些杰出人士中的一些人很友好。相信我,这些人赚的钱比你的公司愿意支付的要多得多。

事实是你首先必须定义你的堆栈包含什么。如果我们坚持上面的例子,您的 NodeJS 程序员也可以处理 MongoDB 设置。但是他们会理解对安全的需求吗?我已经数不清有多少次在本地或者在 Atlas 上看到过 MongoDB 的设置,它完全不安全,需要一个马裤。这些程序员会知道当数据在传输时,他们必须对其应用安全措施吗?他们会理解 bCrypt 和 crypto 的区别吗?我可以继续下去,但让我们假设所有以上可以在一个人身上找到。前端呢?他们还将开发一个完整的前端(移动和网络),同时做好以上工作?

现实是,成功的团队有特定的工作。在所有堆栈中,您可以将其分为三个主要功能:

1.前端

2.后端

3.数据库

现实是专业知识的交叉。需要定义某些参数,尤其是关于 JSON 的参数,以及需要发送什么,哪一方将进行计算。

事实是随着你的公司对编程端的要求越来越高,你对程序员的期望也必须更加明确。贴一个广告,列出一系列语言、技术和需求,并称之为“需要全栈程序员”,并不能很好地说明这家公司。事实上,对于许多人来说,它应该敲响警钟,亮起红灯,说明该公司的确切专业知识以及它将如何取得成功。

现实情况是你和你的公司需要准确定义什么是需要的,需要什么样的程序员支持,并在现实的预算内工作。雇佣一个首席技术官和两个“全栈”程序员是不够的。

现实是——理智地面对现实和局限

荒谬

你会雇佣一个懂 Python 的程序员做数据科学家吗?我非常希望答案是“不”。为什么?因为数据科学家需要一套技能,而 Python 或 Java/Scala 只是其中的一部分。那么,为什么你会考虑雇佣一个懂一点 NodeJS 的 Python 程序员来构建一个完整的前端、后端和数据库系统呢?这显然是荒谬的。

但是..但是..但是..你测试了他们!是的,你做到了。他们通过了 Python 测试、NodeJS 测试、DB 测试,甚至一些小型前端系统。这里一个表单,那里一个问题,一个响应站点——当然你会发现一个优秀的全栈程序员。它们是如此之好,以至于即使你改用 Golang 或者将 JAVA 引入其中,它们也会无缝地完成过渡。

那个 IOS 原生程序员?如果他们能做 IOS,他们也能做 Android,对吗?当然啦!他们将能够处理两个系统中的所有细微差别,包括从后端来回传输的数据。为什么不呢?

当你思考这个问题的时候,处于飞速发展的后端的人应该能够处理整个数据和安全系统。我的意思是这只是他们正在做的事情的一小部分。

简单的数学告诉你两个程序员可以做五个人的工作。你可以简单地保护你的预算,在公司眼里看起来像一个不可思议的英雄。你发现了“全栈”的诱惑。你也逐渐发现了通往荒谬期望和不可能任务的道路。如今有了令人难以置信的 IDE 和工具,程序员应该能够处理任何事情。对吗?不对!哦,这么错

这就像期望首席技术官成为首席执行官,首席运营官和首席财务官合二为一。没有一个理智的人会建议做这样的事。为什么你会期望一个程序员去做呢?总之,你不应该期望一个“全栈”程序员什么都懂,什么都是专家。这太荒谬了。

失败的前奏

对于所有“全栈程序员”来说:

在你决定令我和这篇文章,尖叫和忽略整篇文章或投票否决它之前,请只阅读这一部分。那就做你想做的。

不是你。是这个系统把你扔进了不可能得到一份体面工作的境地,而没有声明你是一个“全栈程序员”。需要“全栈”的工作数量飞速增长。你需要工作。你别无选择,只能宣布你的“全面”能力,并在你知识的薄弱点上磨练。

然而,这种期望会迫使你陷入一种没有胜算的境地。你需要成为某些方面的专家,而不是所有方面。被迫钻研你知识薄弱的领域,会迫使你加强这方面的知识,但代价是你的其他知识。技术系统每三个月就会发生变化。任何一种语言提供给你的数量,对于一个人来说几乎是不可能跟上的。乘以一个“满栈”,你会发现自己溺水了。

然而你坚持对我说:“我是一个全栈程序员。我都知道。我能处理好一切。现实点吧。Fullstack 会留在这里,然后离开。”

所以,我会非常诚实地回答。全栈编程是个骗局。你将成为万事通,但什么都不会。当您的数据库无法响应,或者您的后端没有进行正确的计算,或者您的前端没有正确呈现数据,或者当您的系统遭到黑客攻击和破坏时,猜猜谁会受到指责?毕竟你是一个全栈程序员!

值得一提的是,成功的公司是那些认识到他们的每一部分都需要专业知识的公司。那些很快陷入困境或陷入巨大麻烦的公司是那些要求他们的程序员知道所有事情并能处理整个堆栈中所有事情的公司。

前端程序员不应该弄乱数据库结构和信息。后端程序员永远不要和前端打交道。在我们这个时代,安全问题必须由了解幕后情况的专家来解决。

有些技术可以而且可能应该结合到一项工作中。这并不意味着你已经成为一名全栈程序员。这仅仅意味着你扩展了你的专业知识,允许你在未来要求一份更大更好的工作。

远离“全栈”的诱惑。离远点。知道自己知道的,承认自己不知道的。这些是我最喜欢的英语单词。“我不知道”。不要试图欺骗系统。最终的结果是你,程序员,将会受到责备。


可以通过电子邮件联系到泰德:tedwgross@gmail.com;推特(@ tedwgross);LinkedIn;中等

分析@BillGates tweets Twitter API 的乐趣——从提取、数据可视化到情感分析的逐步分析

原文:https://towardsdatascience.com/fun-with-analyzing-billgates-tweets-twitter-apis-step-by-step-analysis-11d9c0448110?source=collection_archive---------6-----------------------

这是网络抓取和 API 系列的第二篇文章。第一封邮件来了。 请查看 。在这篇文章中,我们可以看到如何使用 twitter API 提取 Twitter 数据,然后使用 word cloud、饼状图进行一些基本的可视化,然后使用 Textblob 和 Vader 进行情感分析。

如果你没有 Jupyter,那么请继续安装 和 anaconda

让我们做以下事情

  1. 创建一个 twitter 帐户或使用您现有的 Twitter 帐户。
  2. twitter 开发者访问密钥请求
  3. 使用 Twitter 流 API 提取实时推文
  4. 使用 Tweepy 使用 Twitter 搜索/Rest API 提取历史推文
  5. 将数据加载到熊猫数据框中
  6. Wordcloud
  7. 分散文本
  8. 做一些统计分析和可视化。
  9. 使用文本块进行情感分析。
  10. 使用 VADER 进行情感分析
  11. 使用 Syuzhet(R) 进行情感分析

在使用 Twitter API 之前,我们需要一个 Twitter 帐户,然后请求一个开发者密钥。首先,如果你没有 twitter 账户,就创建一个。获取必要的开发人员密钥的步骤如下

观看这段创建 twitter 账户的 youtube 视频

  1. 转到https://developer.twitter.com/en/apps
  2. 使用您的 twitter 帐户登录。如果你没有,那就创建一个。

3.登录后,创建一个应用程序。

4.填写所有必填字段。

5.您将获得以下凭据

  1. API 键
  2. API 密钥
  3. 访问令牌
  4. 访问令牌秘密

看看这段 youtube 视频,关于创建 twitter

查看他的文档以获得 Twitter 开发密钥

Twitter 提供了 2 个 API

  • 串流 API
  • 搜索 API 或者休息 API

在 twitter 开发人员网站上,可用的 python 相关包装器有

  • 每秒 6000 条推文
  • 每分钟 473,500 条推文。
  • 每天有 5 亿条推文被发送
  • 每年 2000 亿条推文。
  • 每月有 3.26 亿人使用 Twitter
  • 每天产生 2.5 万亿字节的数据。
  • 地球人口的 50% 在社交媒体上,总共有27.89 亿人。
  • 2025 年,据估计全球每天将产生 463 艾字节的数据——这相当于每天 212,765,957 张 DVD!
  • 社交媒体占在线总时间的 33% 。

资料来源:Domo.com

来源:视觉资本家

来源:视觉资本家

1.流式 API

Twitter 搜索 APITwitter 流媒体 API 非常适合那些只想访问 Twitter 数据进行轻量级分析或统计分析的个人。

Twitter 的流媒体 API 是推数据,因为推文几乎是实时发生的。流媒体 API 的主要缺点是 Twitter 的流媒体 API 只提供了正在发生的推文的样本。根据用户要求的标准和当前的流量,用户通过 Twitter 的流媒体 API 收到的推文占总推文的实际百分比变化很大。研究估计,使用 Twitter 的流媒体 API 用户可以预期以*乎实时的方式收到 1%的推文。(** 参考网站)**

开始安装所有必需的库之前—使用 pip 命令提示符

请查看更多关于 PIP

**pip install vaderSentiment
pip install nltk
pip install Textblob
pip install numby
pip install pandas**

之后,导入所有需要的库

首先,输入您的所有凭证。登录 twitter 账户,进入应用程序,然后填写上述所有信息。

请务必打印并检查您的凭证

您可以通过以下方式进行筛选

  1. 用户标识
  2. 用户名
  3. 按关键字查询
  4. 地理位置

按位置过滤,选择我按位置过滤的推文=旧金山

仅仅一条微博就包含了如此多的信息

检查所有可用的 tweet 对象

JSON 对象看起来像

您也可以将其保存到 CSV 文件中

包含选定信息的 1 条 tweet 的输出

了解更多关于流式 API 的信息

Twitter API 的输出是 JSON 格式的。那么 JSON 是什么呢

请看这段 youtube 视频。

有关 JSON 文件和 python 的更多信息,请查看 data camp 文章

现在我们可以下载 JSON 格式的文件了

将 JSON 文件上传到列表。

检查按键和推文本身

输出如下所示

该字典包含许多信息,如创建时间、用户 ID、转发时间、时间戳等。只需从字典中读取您需要的信息,然后继续进行文本挖掘和可视化。

2.搜索 API 或 REST API

Twitter 的搜索 API 让你可以从已经发生的推文中访问已经存在的数据集。对于个人用户,无论查询条件如何,您可以接收的最大推文数量是最后3200 条推文。对于一个特定的关键词,你通常只能对每个关键词的最后 5000 条推文进行投票。在某个时间段内,您还会受到请求数量的限制。Twitter 请求限制在过去几年中有所改变,但目前限制为 15 分钟内 180 次请求。

让我们将 tweepy 用于搜索 API。

  1. 在命令提示符下安装 tweepy

因为我已经安装了它,所以说这个要求已经满足了。

2.导入所需的库。

3.提供您之前获得的所有凭证

4.现在我们将提取推文,主要功能如下。我正在提取比尔·盖茨的微博。 最多允许 3200 条 。如果用户的推文超过 3200 条,我无法提取用户的整个推文历史。

下载的文件如下所示

5.现在,将数据上传到熊猫数据框中,以便进行数据可视化和情感分析

数据如下图所示

大约 80%的时间用于准备数据,只有 20%的时间用于分析。

6.对推文做一些基本的清理

来源:福布斯

7.现在我们可以进行基本的数据分析和可视化

我们来做一个词云。查看文档了解更多信息。

唯一必需的参数是文本,其他参数都是可选的。

输出是

你也可以做面膜

原图是

还有单词云

代码是

**There are 292731 words in the combination of all tweets.**

分散文本

一种工具,用于在中小型语料库中查找有区别的术语,并以性感、交互式散点图的形式呈现这些术语,这些散点图带有不重叠的术语标签。探索性数据分析变得更有趣了。

查看 GitHub 链接

视觉是惊人的。我试着用推文做一个分散的文本。请参考 GitHub 的示例代码和场景。我认为我的散文肯定可以改进。

代码是

我喜欢 HTML 显示中的图表。我已经附上了截图。

推文中最常见的 20 个词

现在做一些基本的分析。找到最受欢迎和转发最多的推文。

代码是

输出

The tweet with more likes is: 
Congratulations to the Indian government on the first 100 days of @AyushmanNHA. It’s great to see how many people h… [https://t.co/mGXaz16H7W](https://t.co/mGXaz16H7W)
**Number of likes: 56774**
The tweet with more retweets is: 
RT @WarrenBuffett: Warren is in the house.
**Number of retweets: 39904**

最喜欢的推文是

推文来源——显然没有 iPhone 和 Android😃

**Twitter Web Client           1115
Hootsuite                     907
Sprinklr                      733
Twitter Media Studio          100
Twitter for Windows            89
Twitter for Windows Phone      56
Twitter for Websites           11
Twitpic                        10
Twitter Ads                     8
Spredfast                       6
Twitter for Android             6
Panoramic moTweets              5
Mobile Web                      3
Seesmic Look                    3
Yfrog                           1
Vine for windows phone          1
Facebook                        1
Twitter Web App                 1
Mobile Web (M2)                 1
Name: Source, dtype: int64**

按年份分类的推文

2013 年是盖茨发 445 条推文的一年,2015 年是 409 条。最低的是 2011 年,有 125 条推文。

**2013    445
2015    409
2018    370
2014    357
2016    338
2012    329
2017    319
2010    230
2019    135
2011    125**

按月推文

4 月是他发微博最多的月份,有 329 条,最少的是 11 月,有 196 条

**Apr    329
Mar    305
May    292
Feb    283
Jan    282
Jun    254
Oct    236
Sep    234
Dec    227
Aug    212
Jul    207
Nov    196**

每日推文

周三是他发了将* 609 条推文的一天,接下来是周四,有 586 条。周末是最低的😄

**Wednesday    609
Thursday     586
Tuesday      549
Friday       521
Monday       389
Saturday     239
Sunday       164**

每小时的推文:

大多数推文是在下午。最大值在下午 5.00 左右有 297。甚至他在午夜或凌晨 1 点发微博😀。AM 推文很少。

**17    297
14    250
21    230
16    219
20    212
18    202
15    199
22    193
13    188
23    163
19    154
0     147
12    137
1      90
6      54
4      53
2      53
3      52
5      48
8      39
7      30
11     27
9      11
10      9**

多年来的收藏计数和转发

收藏和转发直方图

Fav 计数— Seaborn

情感分析

图片来源:媒体文章

什么是情感分析?

情感分析也被称为观点挖掘是自然语言处理 (NLP)中的一个领域,它建立了试图识别和提取文本中观点的系统。通常,除了识别意见,这些系统还提取表达的属性,例如:

  • 极性:如果说话人表达的是正面负面的意见,
  • 主语:正在谈论的事情,
  • 意见持有人:表达意见的个人或实体。

在情感分析系统的帮助下,这种非结构化信息可以自动转换为公众对产品、服务、品牌、政治或人们可以表达意见的任何主题的意见的结构化数据。这些数据对于市场分析、公共关系、产品评论、净推广者评分、产品反馈和客户服务等商业应用非常有用。

一些 Python 情感分析 API 和库

  • Scikit-learn
  • NLTK
  • 空间
  • 张量流
  • Keras
  • PyTorch
  • Gensim
  • 波尔格洛
  • 文本块
  • 图案
  • 词汇
  • 斯坦福 CoreNLP Python
  • 蒙托林瓜

通过 TextBlob 进行情绪分析:

TextBlob 是一个用于处理文本数据的 Python (2 和 3)库。它提供了一个简单的 API,用于处理常见的自然语言处理(NLP)任务,如词性标注、名词短语提取、情感分析、分类、翻译等。

代码是

**Percentage of positive tweets: 63.23192672554792% 
Percentage of neutral tweets: 26.66012430487406%
Percentage of negative tweets: 10.107948969578018%**

产量在 90%以上

饼图是

维达的情绪分析:

VADER (Valence Aware 字典和情感推理器)是一个基于词典和规则的情感分析工具,专门针对社交媒体中表达的情感。它在【麻省理工学院许可】下是完全开源的

更多信息请查看此 GitHub 链接

计算情感得分的代码与上面类似。只有图书馆不一样。我们只考虑复合分数。

**Percentage of positive tweets: 66.47039581288846%
Percentage of neutral tweets: 20.870134118416747%
Percentage of negative tweets: 12.659470068694798%**

SA —来自文本 blob 的情感分析得分

VSA —来自维德的情绪分析评分

Syuzhet 的情感分析

这个软件包附带了四个情感词典,并提供了一种方法来访问斯坦福大学 NLP 小组开发的健壮但计算昂贵的情感提取工具。

更多信息请查看链接。

这个包有 R 版本,代码如下。我参考了示例代码并做到了这一点。如果你想要更多的细节,请检查我提供的链接,也检查 Rcran 项目。

结论

希望你喜欢阅读这篇文章。现在你知道使用 Twitter API 提取数据有多简单了——流媒体和搜索。只需几行代码,您就可以从 Twitter 获取数据,并使用熊猫进行所有分析。在下一篇文章中,我会写一些关于 scrapy 和 selenium 的内容。我也会很快更新我的 GitHub 并提供链接。同时,如果你想提供反馈或建议,或者有任何问题,请发送电子邮件给 epmanalytics100@gmail.com。再次感谢你阅读我的帖子👍

我发现这张图表很有帮助。(来源:FT)

Jupyter 备忘单(来源:Datacamp)

熊猫小抄 1(来源:数据营)

Matplotlib 备忘单(来源:Datacamp)

再次感谢你阅读我的帖子😃

HTML 画布的乐趣:让我们制作熔岩灯等离子体

原文:https://towardsdatascience.com/fun-with-html-canvas-lets-make-lava-lamp-plasma-e4b0d89fe778?source=collection_archive---------11-----------------------

Real time lava-lamp style plasma

在这篇文章中,你将学习如何创建上面嵌入的熔岩灯等离子体效果。该效果是实时计算的,并使用 HTML 画布进行渲染。

如果你在手机上,看不到嵌入,你可以直接打开嵌入页面。

不需要高等数学。我会解释所有我们需要的数学概念。我们将使用sincos函数,这就是这个效果所需的所有数学复杂性。

如果您想查看完成的代码,请在另一个窗口中打开源代码。

HTML

我们的 HTML 结构是基本的。我们创建一个主体,在其中放置一个画布,并对我们的标记进行样式化,使我们的画布总是填充整个窗口。

<!DOCTYPE html>
<body
  style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; overflow: hidden; margin: 0; padding: 0;"> <canvas 
    id="canvas"
    style="width: 100%; height: 100%; padding: 0;margin: 0;"
  ></canvas></body>

设置

我们将画布设置为固定大小的512 x 512像素。画布的像素被设计为拉伸填充整个窗口,但是内部像素缓冲区的大小是固定的512 x 512

const canvas = document.getElementById("canvas");
const c = canvas.getContext("2d");*// size of canvas* const imgSize = 512;canvas.width = imgSize;
canvas.height = imgSize;

我们不打算在画布上使用任何绘图功能,我们将把它当作一个像素缓冲区。我们不能直接操作画布上的像素值,但我们可以创建一个与画布大小相同的图像缓冲区,根据需要操作图像缓冲区,然后将其内容绘制到画布上。

对 createImageData 的调用为我们提供了一个与画布大小相同的图像缓冲区。

*// init image data with black pixels*const image = c.createImageData(imgSize, imgSize);for (let i = 0; i < image.data.length; i += 4) {
  image.data[i] = 0; *// R* image.data[i + 1] = 0; *// G* image.data[i + 2] = 0; *// B* image.data[i + 3] = 255; *// A* }

返回的图像数据是像素数据的一维数组。每个像素由四个连续的值表示。这四个值是 0-255 范围内的整数强度。它们依次保存像素的红色、绿色、蓝色和 alpha 分量的值。

该阵列按行存储所有图像像素。第一行的像素先出现,然后是第二行,依此类推,行与行之间没有间隙。

我们将所有的图像像素初始化为不透明的黑色。

效果总结

该效果依赖于构造两个高度图,在相对运动时组合它们,并根据高度值的总和对输出进行着色。

1 号高度图

我们想填充第一个1024 x 1024高度图,*滑值范围从 0..128.

我们希望值的分布*滑,没有噪声。我们将在第二个高度图中添加噪声。第一个高度图的工作是给我们一些各个方向的*滑的波浪作为可预测的基础层。

我们希望生成一个高度图,当在透视图中渲染时,看起来像这样:

height map 1

我在用正弦函数生成高度图。还记得窦的功能吗?以下是相关事实:

  • 它产生连续的波浪
  • 它是周期性的,频率为 2π
  • 它生成-1 和 1 之间的值

我们来看看。

plain sin(x)

我们想要产生一个大约有 1.5 个完整振荡的波。这就是我们从 sin 函数中得到的,当我们给它 0 到 3π的值时。

如果我们适当的缩放比例,我们可以得到任何我们需要的频率。例如,如果我们想要在 x = 0 和 x = 512 之间产生 1.5 次振荡,我们不会将x传递给 sin,但是x × 3π/512``x越接* 512,我们的转换输入值就越接* 3π。

graph of sin(x × 3π/512)

接下来我们需要关注的是输出范围。sin 函数给出了介于-1 和 1 之间的值。我们想要 0..128.

我们可以转换-1..1 到我们想要的范围,首先归一化到 0..1.为此,我们加 1,然后除以 2。值在 0 之间..1 我们可以到达 0..乘以 128 得到 128。

因此,我们完成的发电机公式是:

该图具有我们需要的所有属性:

we have a wave in range (sin(x×3π/512)+1)/2*128

我们有一个很好的函数来生成我们的高度图。但是我们如何用合适的值填充 2D 高度图呢?

我们确定每个像素到高度图中心的距离,并使用距离作为高度生成函数的输入。相同的距离像素产生相同的高度值,所以我们得到一个从中心出现的径向波值。

Same distance pixels generate the same height value

为了计算像素到中心的距离,我们首先将像素坐标偏移地图宽度和高度的一半。这有效地将坐标移动到以原点为中心的坐标系。

像素坐标允许我们构建一个直角三角形,所以我们可以使用勾股定理告诉我们distance² = cx² + cy²

the distance from origin is given by sqrt(cx²+cy²)

第一张高度图就这样了。对应的代码是:

二号高度图

我们想用 0 范围内的值填充第二个1024 x 1024高度图..127.这一次我们想要不规则。它们需要在空间上连贯一致,从山丘到山谷*滑过渡。

由于我们已经熟悉了 sin 函数,我将继续使用 trig 函数来生成第二个高度图。在透视图中,它看起来像这样:

Height map 2

这张地图不是随机的。事实上,这是非常有规律的。它甚至关于 x 轴和 y 轴都是对称的。它只是混杂在一起,足以有一个有机的感觉,这就是我们所要寻找的。

它由正弦和余弦函数之和构成,这些函数在偏离中心的轴伪距离上运算。像以前一样,输入被缩小以产生适合我们的地图大小的波浪量,输出被缩放为 0..127.

构建高度函数

主要思想是使用正弦和余弦之和来产生波状不规则性。出于我们的目的——这里纯粹是审美目的——我们将 cos 函数理解为 sin 函数的相移版本。

cos is just a phase shifted version of sin

这次我们不想要径向对称,所以我们不打算用距离作为这些函数的输入。相反,我们将使用轴倾斜版本的距离。

对于 sin 部分,我们将拉伸 y 坐标,收缩 x 坐标。然后,我们缩小输入,以达到一个适合我们地图大小的好看的频率。

对于 cos 部分,我们遵循同样的思路,但是沿 x 轴拉伸,沿 y 轴收缩。

这两个部分为我们产生了规则的椭圆波形。当我们把它们加起来,它们就形成了我们想要的不规则的山丘景观

sin, cos, and combined waves

我们仍然需要将输出标准化到 0..127.当我们将 sin 和 cos 的输出相加时,我们得到-2 范围内的值..2,所以我们加 2,除以 4,得到值 0..1,然后缩放 127 以得到我们想要的范围。

第二张高度图到此为止。下面是相应的代码:

渲染高度贴图

我们将我们的高度图构造为1024 x 1024,与我们的可见图像尺寸512 x 512相比,它在每个方向上的尺寸都是两倍

为了使高度图可见,我们可以迭代任何512 x 512部分,从高度值中导出每个像素的显示颜色,并将颜色放入我们的图像缓冲区。

因为高度图包含 0..128 和 0..127,我们可以将它们相加,得出范围为 0..255.最简单的开始是渲染相应的灰度值,其中红色、绿色和蓝色分量是相同的。

如果我们对高度图 1、高度图 2 以及它们的值的总和(都从左上角开始)执行此操作,我们将得到以下图像:

height map 1, height map 2, and the sum of their values

下面是更新图像像素缓冲区的相应代码:

高度场动画

我们应该开始制作我们的高度图来获得初步的视觉效果。我们应得的。

这个想法是动画的高度地图的位置相对于彼此。请记住,我们有1024 x 1024高度图,但只有一个512 x 512图像视图,因此在每个高度图上,对图像有贡献的第一个——左上角——像素可以是范围[0..512]x[0..512]内的任何像素

different offsets of height maps create different values in the view port

我们将使用requestAnimationFrameAPI 来启动我们的动画。当需要渲染下一帧时,它会调用我们的tick函数。浏览器会尽力给我们一点时间来绘制下一帧,通常目标是每秒 60 帧。我们需要请求在我们完成后再次被呼叫。

在我们的 tick 函数中,我们将高度图偏移更新到新的位置,重新计算新的图像数据,并将图像呈现到画布上。

随时间插值高度图偏移

当我们的回调函数被调用时,浏览器会传入一个以毫秒为单位表示时间的高分辨率数值。每次调用我们的时候,这个参数都会比上次调用的毫秒数高。我们可以将这一事实用于基于时间的动画,从而独立于帧速率。

我们将使用时钟值来驱动高度贴图偏移的动画。我们需要在两个高度图上的两个轴上插入 0 到 512 之间的值。我们将为四个偏移值中的每一个单独做这件事,因为我们不希望运动开始看起来太有规律或重复。

我们的目标是移动高度贴图的中点,使其在视口中漫游,如下所示:

desired middle point movement of our height maps within the viewport

是的,既然我们已经对 sin 和 cos 有了充分的了解,我们就用它们来插值时间偏移。

给定一个进行中的时间值t,我们的插值必须给我们一个范围为 0 的值..512.

我们在构建高度图时使用的相同原则在这里也适用。我们将缩小t来延长一个完整振荡发生的时间。然后,我们通过加 1,除以 2,然后乘以 512 来缩放到所需的范围。

我们还想增加一些变化,因为我们想对四个偏移量进行稍微不同的插值。为此,我们可以改变时间比例因子,并给t增加一个常数,以在输出中产生相移。

这是我们的基本公式:

对于四个偏移中的每一个,我们将对timeScalephaseShift使用稍微不同的值,以避免锁步重复动画。下面是相应的代码:

随着偏移动画的到位,我们已经得到了等离子体效果的灰度版本。

我们迄今为止的进展

这是我们迄今为止取得的进展:动画灰度等离子体

screenshot of grey-scale plasma sandbox

添加颜色

我们将通过添加颜色来改善我们的等离子效果。首先,我们将添加静态颜色,然后我们将提出一个随着时间改变颜色的策略。

使用单一调色板

主要思想是使用一组固定的 256 种颜色来对应范围 0..255.

如果我们认为低值是谷,高值是山,我们可以决定将山设为蓝色rgb 0,0,255而将谷设为红色rgb 255,0,0,并在颜色之间进行线性插值。我们可以预先计算所有 256 种颜色,并将它们放入一个数组中,这样高度值为 0..255 索引成与高度相对应的颜色。

如果我们用r, g, and b键将颜色表示为对象,我们可以使用辅助函数在两种颜色之间进行插值:

// c1 and c2 are colors
// f is a fraction between 0..1
//
// returns an interpolated color between 
//   c1 (for f=0) and
//   c2 (for f=1)
//
// pass f=0.5 to get the color half-way between c1 and c2const interpolate = (c1, c2, f) => {

  return {
    r: Math.floor(c1.r + (c2.r - c1.r) * f),
    g: Math.floor(c1.g + (c2.g - c1.g) * f),
    b: Math.floor(c1.b + (c2.b - c1.b) * f)
  };
};

使用双色渐变

我们可以生成 256 种颜色的渐变,如下所示:

// generates an array of 256 colors 
// forming a linear gradient of the form
// [c1, ..., c2]const linearGradient = (c1, c2) => {
  const g = [];
  *// interpolate between the colors in the gradient* for (let i = 0; i < 256; i++) {
    const f = i / 255;
    g[i] = interpolate(c1, c2, f);
  }
  return g;
};

有了这些助手,我们可以像这样定义一个调色板:

let palette = linearGradient(
   { r: 255, g: 255, b: 0 },  // c1 yellow
   { r: 0, g: 54, b: 128 }    // c2 dark blue
);

updateImageData中,我们可以使用调色板中对应于高度值的颜色:

*// height value of 0..255* let h = heightMap1[i] + heightMap2[k];*// get color value from current palette* let c = palette[h];

以下是使用两种颜色之间的线性渐变的一些结果:

Using a linear gradient between two colors

整体视觉效果还是和灰度着色差不多。我们可以通过在渐变中添加额外的不同颜色来创造更多样的外观。

五色渐变

让我们创建一个渐变函数,它接受五种不同的颜色,并在它们之间进行插值。

创建五种颜色的调色板极大地增强了我们输出的多样性。

通过在中等高度的部分选择任意的颜色,我们将我们对深度的感知与潜在的高度值分离。

我们可以自由地为调色板的中间选择浅色,为相邻的颜色选择深色,以获得更高和更低的值。在我们的感知中,这使得高度图的中间色调看起来像脊线。这种效果是我们只有用两种以上颜色的渐变才能达到的。

multi-color palettes can effectively accentuate or blur areas in our height map

使用两种调色板

现在我们可以轻松地创建调色板,我们可以创建两个调色板,并随着时间的推移在它们之间进行插值。

我们想开始创造性地使用颜色,所以在我们继续之前,让我们快速添加一个助手来创建一个随机的 5 色渐变调色板。

*// returns a random color* const randomColor = () => {
  const r = Math.floor(Math.random() * 255);
  const g = Math.floor(Math.random() * 255);
  const b = Math.floor(Math.random() * 255);

  return { r, g, b };
};// returns a random 5-color gradient palette
const makeRandomPalette = () => {
  const c1 = randomColor();
  const c2 = randomColor();
  const c3 = randomColor();
  const c4 = randomColor();
  const c5 = randomColor();

  return makeFiveColorGradient(c1, c2, c3, c4, c5);
};

每一帧我们计算一个范围为 0 的值..1,并将当前帧的调色板创建为源调色板的相应颜色之间的插值。

我们将使用 cos 函数进行插值。应用与之前相同的规则:我们拉伸t值来控制振荡时间,然后归一化为 0..通过加 1 除以 2 得到 1。

*// two palettes we interpolate between* const palettes = [makeRandomPalette(), makeRandomPalette()];*// current palette is edstablished durting animation* let palette = [];const updatePalette = t => {
  const timeScale = 0.0005;
  const x = t * timeScale;

  *// normalized value 0..1 used to interpolate palette colors* const inter = (Math.cos(x) + 1) / 2; *// create interpolated palette for current frame* for (let i = 0; i < 256; i++) {
    palette[i] = interpolate(palettes[0][i], palettes[1][i], inter);
  }
};

现在,我们可以使用两个调色板来实现我们的效果不同的艺术意境。

Given two color palettes we can interpolate between the two each frame

转向时生成新调色板

两个调色板之间的混合很好,但仍然有些静态。最后,随着时间的推移,我们将生成新的调色板。

当在两个调色板之间来回切换时,最好能知道我们何时到达插值的远端,也就是说inter何时分别到达01,并且即将开始向相反的方向移动。

一旦我们检测到这个事实,我们可以在另一端生成一个新的调色板,并*滑地插入一组新的颜色。

仅仅检查inter的具体值是不够的。首先,我们不能指望准确地击中01

假设我们在inter = 0.01,直到下一帧足够长的时间过去,使得 cos 函数经过0并再次移动到0.01。这种情况也说明了我们的下一个问题:仅仅看插值并不能告诉我们前进的方向。我们应该重新生成两个调色板中的哪一个?

检测转向点

我们需要插值函数cos的导数。我们需要看看-sin

cos的导数给出了cos任意给定点处切线的斜率。实际上:当一个函数在点x向下时,导数函数在点x为负。当函数在点x向上时,导数在点x为正。

因此,我们可以寻找导数符号的变化。如果前一帧的导数是负的,而当前帧的导数是正的,我们已经改变了方向,正在向第二个调色板插值。

同样的想法适用于相反的情况。如果前一帧的导数是正的,而当前帧的导数是负的,我们已经改变了方向,正在向第一个调色板插值。

cos的导数是-sin。通过查看图表,说服自己上述陈述是正确的。

cos(x) and its derivative -sin(x)

cos向下时,-sin为负。当cos抬头时,-sin为正。在cos改变方向的点-sin0

我们将使用这些事实,并扩展我们的调色板插值,以在检测到导数符号变化时生成新的调色板。

根据新的导数是正的还是负的,我们知道我们正在向哪个调色板插值,所以我们可以替换正确的那个。

对新生成的调色板插值结束了我们的工作。等离子效果完成了。

恭喜你走到这一步!

结论

哇,那真是一段旅程。在这里找到完整的工作源码。坐下来享受你创造的一切吧!

random screenshot of lava lamp plasma

PS: 看看这篇用 HTML 创建星球大战标题抓取的文章。这比血浆更容易做到,但也相当值得。它看起来非常接*真实的交易。

[## 创建一个 HTML 格式的星球大战标题抓取

很久很久以前,在一个遥远的浏览器里

medium.com](https://medium.com/better-programming/create-a-star-wars-title-crawl-in-html-c25a76fea401)

StyleGAN 的乐趣:让我们预测特斯拉 CyberTruck 的设计!

原文:https://towardsdatascience.com/fun-with-stylegan-lets-predict-the-tesla-cybertruck-design-3f2123ab4d0d?source=collection_archive---------35-----------------------

当你从一辆旧的皮卡和一辆特斯拉 Model X 的潜在组合中生成一辆带有 StyleGAN 的汽车时,会发生什么?

11 月 21 日,埃隆·马斯克将推出一款新的特斯拉皮卡,他说

所以自然地,作为一名数据科学家和特斯拉粉丝,我必须探索人工智能是否可以预测这辆卡车的设计!

经过数周的尝试和失败,我终于找到了一个名为 StyleGAN 的生成式人工智能模型,它可以产生想象中的汽车设计,我用这个模型结合了一辆皮卡和一辆特斯拉 Model X 的设计,给了我们一个特斯拉卡车的估算设计。

StyleGAN output for Old Pickup Truck + Tesla Model X

在进一步将假想的特斯拉卡车的设计与一辆装甲运兵车的设计相结合后,我们根据埃隆的描述得到了赛博卡车设计的最佳估计。

Is this what the Tesla CyberTruck will look like? StyleGAN seems to think so.

理解风格 g

今年早些时候,NVIDIA 的研究人员推出了 StyleGAN 。它最出名的是能够生成看起来非常真实的随机人脸。他们还提供生成汽车的预训练模型,这是我在这个项目中使用的。

These people are not real. These are random faces generated by StyleGAN. [source]

任何 GAN 方法的典型发生器网络使用从高斯分布提取的随机噪声像素的图像作为起点。然后,它学习将这个有噪声的图像转换为目标分布,在我们的例子中是一辆汽车的图像。

生成器使用几个卷积层来学习这个目标分布,使用数千个图像样本用于其训练过程。然而,StyleGAN 的工作方式略有不同。它在输入噪声层和卷积层之间引入了一个额外的映射网络。映射网络仅由完全连接的层组成,这些层接收噪声图像并将其转换为一些有意义的潜在空间表示。

Mapping Network in StyleGAN

这个中间的潜在空间包含多个层,其中每一层都表示一个特定的造型元素,生成器在试图生成汽车图像时需要使用该元素。因此,一层可能包含关于汽车颜色的信息,另一层可能包含关于位置和角度的信息,如前视图或后视图。一层可以包含前灯设计的信息等等。

The Generator/Synthesis Network of StyleGAN.

现在是斯蒂根模型的生成器。该模型使用小尺度的恒定图像作为在训练过程中学习的起点。几个上采样和卷积层处理这个输入。来自映射网络的中间潜在表示在这里被用于不同的级别,以控制输出汽车图像的设计。这就是 StyleGAN 能够生成随机汽车图像的方式。

然而,这里有一个问题。

虽然我们可以使用 StyleGAN 来转换随机噪声输入,使其看起来像汽车,但我们无法控制汽车的设计元素。换句话说,对于任何给定的输入,我们无法控制映射网络的输出。因此,如果我们想为特斯拉 CyberTruck 生成具有特定风格特征的汽车,我们将需要以某种方式修改这种潜在的风格,以符合 CyberTruck 的描述。只有这样,我们才能使用合成网络来可视化汽车的最终输出图像。

编码器拯救世界。

谢天谢地,有人为这个问题找到了一个巧妙的解决办法。名为 StyleGAN-Encoder 的 github repo 将在这里帮助我们。

使用这个编码器,我们可以训练另一个神经网络,它充当一个“反向生成器”。它可以将任何汽车的图像(如特斯拉 Model X)作为其输入,并产生相应的潜在空间作为其输出。一旦潜在空间可用,我们可以对其进行修改,并根据我们的意愿改变输入车的设计。很聪明,对吧?

所以,这里是这个反向发电机的工作原理。首先,我们使用一个预训练的 ResNet 模型来转换我们想要改变其设计的汽车的图像,并将其转换为潜在的风格作为其输出。为此生成训练数据非常容易,我们可以简单地使用 StyleGAN 生成器来生成几乎无限的输入-输出样本对。使用这个,我们可以得到一个由 StyleGAN 的映射网络产生的潜在空间的相当不错的估计。

但是,仍然有一些更多的优化需要做。一旦我们从 ResNet 获得了对潜在风格的粗略估计,我们就可以用它来生成汽车的相应图像。损失函数现在可以由 VGG 感知损失 度量来定义,该度量测量两个输出图像在视觉上看起来有多不同。对于比较图像之间的视觉相似性来说,这是一个比诸如均方误差之类的更健壮的度量。

现在,为了优化潜在的风格,我们需要做的就是通过这个组合网络反向传播,同时保持所有网络权重固定。这里唯一允许训练的参数是输入风格潜伏。因此,经过几次反复训练后,你可以很快收敛到潜在风格的最佳估计值。

玩潜伏空间!

我们现在准备通过组合不同汽车的潜在风格,挑选我们想从哪辆汽车中选择的设计元素,来玩转这种潜在风格。然后,我们可以简单地使用 StyleGAN 生成器来产生混合多种汽车设计的结果。

我必须承认,和甘斯一起工作时,玩这个潜在空间是你能得到的最大乐趣!

结果:赛博卡车预测!

我摆弄了一下这个人工智能,得到了一些关于即将推出的特斯拉 CyberTruck 设计的有趣预测。我将不同的设计风格混合到一辆旧学校皮卡的潜在空间中,得到了 StyleGAN 输出,如下图。

  1. 第一个简单地将卡车转换成 Model X 克隆,如果不是因为埃隆·马斯克对网络卡车的疯狂设计想法,这将是一个安全的选择。
  2. 这就是为什么我认为第二种选择看起来最接*网络卡车的实际样子。它结合了
  3. 第三种选择也可能是真的,如果埃隆决定让它看起来像一辆复古的银翼杀手汽车,但不幸的是,它看起来不再像特斯拉汽车。

我投票给最接*真实情况的选项 2。但是,你们觉得呢?你认为赛博卡车看起来会像这些预言中的任何一个吗?或者你认为它会看起来完全不同,一些我们从未见过的东西?请在下面的评论中告诉我!

参考

  1. 学习如何用一个生成性对抗网络来变形人脸!由 Arxiv 洞察
  2. 用 nVidia StyleGAN 和 Python (7.3)生成人脸作者杰夫·希顿
  3. StyleGAN 作者亨利·艾实验室

感谢您的阅读。如果你喜欢这篇文章,你可以在媒体、 GitHub 上关注我的更多作品,或者订阅我的 YouTube 频道。

有趣的二项式分布

原文:https://towardsdatascience.com/fun-with-the-binomial-distribution-96a5ecabf65b?source=collection_archive---------4-----------------------

理解不太为人所知的正态分布,以及如何应用它

每个人都知道并喜欢正态分布。它被用于各种各样的应用,如投资建模、A/B 测试和制造过程改进(六西格玛)。

但是人们对二项分布不太熟悉。这很遗憾,因为二项分布真的很有用。有人问过你类似这样的问题吗:

"给定一枚硬币,掷 10 次,得到 6 个头的概率是多少?"

概率(尤其是餐巾纸后面的概率计算)不是我最喜欢的东西。所以当我第一次学习二项分布的时候,我想,“是的,我再也不用担心抛硬币的概率问题了!”

那是因为抛硬币的结果遵循二项分布。我应该强调一下,大数定律在这里适用。为了技术上的正确,我应该说,如果我们一遍又一遍地重复进行同一套实验(投掷硬币 10 次),我们在所有这些实验中观察到的人头数将遵循二项式分布。

不要担心,我很快会详细说明这一点。

什么是二项分布

首先让我们从稍微更技术性的定义开始— 二项式分布是一系列实验的概率分布,其中每个实验产生一个二元结果,并且每个结果都独立于所有其他结果。

一次抛硬币是二进制结果实验的一个例子。抛硬币也符合另一个二项式分布要求——每一次抛硬币的结果都是独立的。需要明确的是,实验的结果不需要像掷硬币一样具有相同的可能性,以下内容也符合二项分布的前提条件:

  • 不公*的硬币(例如有 80%的概率正面朝上)。
  • 在街上随机挑选一些人来回答是或否的问题。
  • 试图说服网站访问者购买产品——是或否的结果取决于他们是否购买。

概率和统计的新手可能会遇到的一个问题是概率分布的概念。我们倾向于确定性地思考,比如“我将一枚硬币抛 10 次,产生了 6 个头”。所以结果是 6,那么分布在哪里呢?

概率分布来源于方差。如果你和我都掷 10 枚硬币,很可能我们会得到不同的结果(你可能得到 5 个正面,而我得到 7 个)。这种方差,也就是围绕结果的不确定性,产生了一种概率分布,它基本上告诉我们哪些结果相对更有可能(比如 5 个头),哪些结果相对不太可能(比如 10 个头)。

我们可以通过模拟产生这样的概率分布,如下图所示:

Illustration of a Sequence of Trials that Would Produce a Binomial Distribution

在我们进入运行这个模拟并产生二项式分布的 Python 代码之前,让我们先了解一些定义。当你看到教科书中描述的二项式分布及其背后的实验时,这些描述总是包括以下关键参数:

  1. n: 我们做实验的次数。在我们的硬币例子中,n 等于 10(每个实验是硬币的 1 次翻转)。
  2. p: 成功概率。公*地说,应该是 50%。
  3. k: 成功的目标次数。之前我们提到过我们希望获得 6 项成功。

用 Python 实现二项式分布

让我们来看一些运行上述模拟的 python 代码。下面的代码 ( 也可以在我的 Github 这里得到 ) 做了如下的事情:

  1. 生成一个介于 0 和 1 之间的随机数。如果这个数字是 0.5 或者更多,那么把它算作正面,否则就是反面。使用 Python list comprehension 做 n 次。这在函数 run_binom 中通过变量 tosses 实现。
  2. 重复指定次数(试验次数由输入变量试验指定)。我们将进行 1000 次试验。
# Import libraries
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns# Input variables# Number of trials
trials = 1000# Number of independent experiments in each trial
n = 10# Probability of success for each experiment
p = 0.5# Function that runs our coin toss trials
# heads is a list of the number of successes from each trial of n experiments
def run_binom(trials, n, p):
    heads = []
    for i in range(trials):
        tosses = [np.random.random() for i in range(n)]
        heads.append(len([i for i in tosses if i>=0.50]))
    return heads# Run the function
heads = run_binom(trials, n, p)# Plot the results as a histogram
fig, ax = plt.subplots(figsize=(14,7))
ax = sns.distplot(heads, bins=11, label='simulation results')ax.set_xlabel("Number of Heads",fontsize=16)
ax.set_ylabel("Frequency",fontsize=16)

这就是代码。那么,当我们重复 10 次掷硬币试验 1000 次时,会发生什么呢?我们得到下面绘制的直方图:

Our Simulation Results

让我们修改前面代码的绘图部分,以便我们的绘图也显示实际的二项式分布(使用 scipy 库中的 stats.binom 函数):

# Plot the actual binomial distribution as a sanity check
from scipy.stats import binom
x = range(0,11)
ax.plot(x, binom.pmf(x, n, p), 'ro', label='actual binomial distribution')
ax.vlines(x, 0, binom.pmf(x, n, p), colors='r', lw=5, alpha=0.5)
plt.legend()
plt.show()

下图用蓝色显示了我们最初的模拟分布,用红色显示了实际的二项式分布。要点是,如果我们实际上重复 10 次抛硬币 1000 次,二项式分布是我们观察到的非常好的*似值——因此,我们可以直接使用二项式分布,而不是浪费大量时间来抛硬币和记录结果!

Actual Binomial Distribution (Red) vs. Our Simulation Results (Blue)

如果我们想模拟一系列 n 次实验的结果(回想一下,在我们的例子中 n=10,但实际上它可以是任何正整数),我们可以使用二项分布的随机变量来生成结果,如下所示:

np.random.binomial(n, p)

最后,让我们通过对 10 次抛硬币进行 10,000 次模拟来回答我们最初的问题(10 次抛硬币得到 6 个正面的概率):

# Probability of getting 6 headsruns = 10000
prob_6 = sum([1 for i in np.random.binomial(n, p, size=runs) if i==6])/runs
print('The probability of 6 heads is: ' + str(prob_6))

我们发现概率约为 20%(我们也可以通过 x 轴上红色垂直线高于 6 的高度在之前的直方图中看到这一点)。

二项分布在现实世界中的应用

酷,但是如果我们想分析抛硬币以外的事情呢?让我们来看一下二项分布的一个程式化的真实世界用例。假设我们是数据科学家,负责提高我们公司呼叫中心的 ROI(投资回报),在这里,员工试图给潜在客户打电话,让他们购买我们的产品。

您查看了一些历史数据,发现了以下情况:

  • 典型的呼叫中心员工*均每天打 50 个电话。
  • 每次通话的转换(购买)概率为 4%。
  • 你公司每次转换的*均收入是 20 美元。
  • 您正在分析的呼叫中心有 100 名员工。
  • 每个雇员每天的工资是 200 美元。

我们可以将每个员工视为具有以下参数的二项分布随机变量:

n = 50

p = 4%

以下代码模拟了我们的呼叫中心:

# Call Center Simulation# Number of employees to simulate
employees = 100# Cost per employee
wage = 200# Number of independent calls per employee
n = 50# Probability of success for each call
p = 0.04# Revenue per call
revenue = 100# Binomial random variables of call center employees
conversions = np.random.binomial(n, p, size=employees)# Print some key metrics of our call center
print('Average Conversions per Employee: ' + str(round(np.mean(conversions), 2)))
print('Standard Deviation of Conversions per Employee: ' + str(round(np.std(conversions), 2)))
print('Total Conversions: ' + str(np.sum(conversions)))
print('Total Revenues: ' + str(np.sum(conversions)*revenue))
print('Total Expense: ' + str(employees*wage))
print('Total Profits: ' + str(np.sum(conversions)*revenue - employees*wage))

如果您运行该代码,您会得到如下输出(每次运行都会发生变化,因为转换是一个二项分布的随机变量数组)呼叫中心的关键指标:

  • 每位员工的*均转换率: 2.13
  • 每个员工转换率的标准偏差: 1.48
  • 总转换数: 213
  • 总收入:21300 美元
  • 总费用:20,000 美元
  • 总利润:【1,300 美元

与费用相比,利润相当微薄。但这些只是随机产生的一天的结果。让我们看看我们的呼叫中心在 1,000 次模拟中的利润,看看每天的利润是如何变化的:

Profit Distribution of Our Call Center

哇,鉴于我们呼叫中心目前的运营指标,亏损的可能性非常高(*一半的模拟利润为负)。那我们该怎么办?

回想每位员工的业绩都遵循二项分布,我们意识到我们可以采取以下一项或多项措施来改善情况:

  • 多打冷门电话(增加 n )。
  • 以更高的百分比转换(增加 p )。
  • 少给员工发工资(我们不会这么做,因为我们人好)。

最终,我们开发了一个潜在客户生成工具,使我们的呼叫中心员工能够识别更有可能购买我们产品的人。这导致电话通话时间更短(需要的甜言蜜语更少),我们的转换概率上升,最终对我们的参数进行了如下修改:

  • n = 55
  • p = 5%

让我们运行下面几行代码,模拟我们新改进的呼叫中心的 1000 个潜在工作日,看看这些变化如何影响我们未来每日利润的统计分布。

# Call Center Simulation (Higher Conversion Rate)# Number of employees to simulate
employees = 100# Cost per employee
wage = 200# Number of independent calls per employee
n = 55# Probability of success for each call
p = 0.05# Revenue per call
revenue = 100# Binomial random variables of call center employees
conversions_up = np.random.binomial(n, p, size=employees)# Simulate 1,000 days for our call center# Number of days to simulate
sims = 1000sim_conversions_up = [np.sum(np.random.binomial(n, p, size=employees)) for i in range(sims)]
sim_profits_up = np.array(sim_conversions_up)*revenue - employees*wage# Plot and save the results as a histogram
fig, ax = plt.subplots(figsize=(14,7))
ax = sns.distplot(sim_profits, bins=20, label='original call center simulation results')
ax = sns.distplot(sim_profits_up, bins=20, label='improved call center simulation results', color='red')ax.set_xlabel("Profits",fontsize=16)
ax.set_ylabel("Frequency",fontsize=16)
plt.legend()

上面的代码还绘制了我们的改进结果(红色)相对于旧结果(蓝色)的分布。我们不需要进行 A/B 测试(尽管我们真的应该)就能看到我们的销售线索挖掘工具已经显著改善了我们呼叫中心的运营和盈利能力。

我们成功认识到每个员工产生的利润遵循二项式分布,因此如果我们能够增加 n (每天拨打的陌生电话数量)和 p (每次电话的转换概率)参数,我们可以产生更高的利润。

Improved Call Center Simulation

结论

最后,我想提出以下几点:

  • 概率分布是接*现实的模型。如果我们能够找到一个与我们所关心的结果非常接*的分布,那么这个分布就非常强大——就像我们上面看到的那样,只需要几个参数(n 和 p ),我们就可以对数百人产生的利润进行建模。
  • 然而,同样重要的是认识到模型在哪里以及如何与我们的现实情况不匹配 —这样我们就知道在什么情况下我们的模型可能表现不佳。

干杯!

更多数据科学与分析相关帖子由我:

了解 PCA

了解随机森林

理解神经网络

了解 A/B 测试

用 Tableau 可视化股票

维度的诅咒

强化学习中的函数逼*

原文:https://towardsdatascience.com/function-approximation-in-reinforcement-learning-85a4864d566?source=collection_archive---------0-----------------------

当状态和动作空间爆炸时该怎么办…字面意思?

Photo by Maksym Kaharlytskyi on Unsplash

更新:学习和练习强化学习的最好方式是去 http://rl-lab.com

概观

在像 DP 和蒙特卡罗这样的表格方法中,我们已经看到状态的表示实际上是每个状态的记忆。
现在让我们回忆一下到底什么是状态。
状态是可观察特征或变量的组合。这意味着每当一个特性或变量有了一个新值,就会产生一个新的状态。

我们来举一个具体的例子。假设一个代理在 4x4 网格中,那么代理在砂砾上的位置就是一个特征。这给出了 16 个不同的位置,意味着 16 个不同的州。

Grid World

但这还不是全部,假设方位(北、南、东、西)也是一个特征。这为每个位置提供了 4 种可能性,这使得状态的数量为 16*4 = 64。此外,如果代理有可能使用 5 种不同的工具(包括“无工具”的情况),这将使状态数增加到 64 * 5 = 320。
你明白了……

表示这些状态的一种方法是创建一个多维数组,比如 V[row,column,direction,tool]。然后我们或者查询或者计算一个状态。
例如 V[1,2,north,torch]表示代理在第 1 行第 2 列,面向北方,手持火炬的状态。这个数组单元格中的值表明了这个状态的价值。
另一个例子是 V[4,1,west,nothing],它是第 4 行第 1 列的一个代理,向西行驶,但什么也没有。

让我们也考虑一下国际象棋。
每一步棋后棋盘的情况是一种状态。估计大约有 10^120 个州!
国际象棋中一种状态的一种表示可以是:

黑卒,黑车,…,无,无,…。,白皇后,白主教]

其中每个维度代表棋盘上的一个正方形,其值是黑色或白色棋子之一,也可以是零。

所以一旦我们有了状态集,我们就可以为每个状态分配一个值状态函数。

不用说,容纳多个状态所需的存储量是巨大的,并且计算每个状态的值所需的时间也是令人望而却步的。

从逻辑上讲,这促使我们寻找更好、更合适的解决方案。

解决方法

记住我们正在努力做的事情总是有用的,因为我们可能会忽略所有的细节。
我们的想法是,我们希望找到环境中每个状态/动作的值,以便代理遵循收集最大回报的最佳路径。

在上一节中,我们已经表明,当状态空间变得太大时,表格方法就变得不充分和不合适了。为了解决这个缺点,我们可以根据每个状态的特征采用新的方法。目的是使用这些特征集合来概括具有相似特征的状态的值的估计

我们使用单词估计来表示这种方法永远不会找到一个状态的真实值,而是它的*似值。尽管这个结果看起来很不方便,但是这将实现更快的计算和更多的推广。

计算这些*似值的方法被称为函数*似值

有许多函数逼*器:

  • 特征的线性组合
  • 神经网络
  • 决策图表
  • 最*邻

由于我们将使用梯度下降以找到最佳结果,函数逼*器必须是可微分的,这导致我们对特征和神经网络的线性组合。

特征的线性组合

现在让我们深入研究这种线性函数逼*方法的细节。
但首先让我们记住这个公式,它来自数学背后的强化学习文章:

这是一个递归公式,它根据下一个状态【s’等等的值来计算一个状态 s 的值…
这个公式的问题是,每次我们需要计算 V(s)时,我们都需要计算所有未来的状态。更糟糕的是,如果我们在某个时候遇到一个与我们过去已经见过的状态相似的状态,我们没有办法识别它。

还记得在时间差异文章中提到的,利用 Q 学习公式,我们有一种估计未来状态的方法:

我们将利用这些公式推导出一些有趣的解。
让我们重新定义 V(s ),比如它反映了它所包含的特征。状态值函数可以用其特征的加权和来表示:
V(s) = W1。F1(s) + W2。F2(s) + … +Wn。Fn(s)或简称:

𝝫(s)是在状态 s 下的特征向量,而𝜽ᵀ是应用于特征的权重的转置矩阵,以这种方式,一些特征在任何状态 s 下比其他特征更受重视。

现在让我们定义𝜹,也称为 TD 误差,如下所示:

通过用新的定义代替𝜹中的 V(s ),我们得到:

请记住,根据定义 V(St) = R(t₊₁) + 𝛾V(St₊₁),这意味着𝜹应该是零。然而,我们不是在一个确定的环境中,这意味着我们不能确定相同的行为总是导致相同的结果,并且学习过程不是 100%准确的,这意味着我们对 V(s)的学习不一定等同于 R(t₊₁) + 𝛾V(St₊₁).所有这些导致𝜹具有非零值。所以现在我们的目标是计算𝜽,以便最小化𝜹.通过最小化 J(𝜽).来实现这一点的便利方法

J(𝜽)与任何回归一样,计算实际结果与真实结果之间的差异。然而我们的问题是我们不知道什么是真正的结果!相反,我们将计算实际结果和估计结果之间的差异。每次迭代后,我们都有一个新的真实结果估计,这使得我们看起来好像是在瞄准一个移动的目标。
想法仍然是不断改进估计,直到两者之间的差异变得足够小。
已经证明这种方法有足够的收敛性保证。

成本函数的最小化可以使用梯度下降法来完成,该方法在梯度下降文章中有详细描述。
梯度下降将逐步向最小化 J(𝜽的值更新𝜽,更新公式为:

其中𝜹 𝝫(s)大致是 J(𝜽)相对于𝜽的导数,⍺是学习率]0,1]。

重要提示:实际上 J(𝜽相对于𝜽的推导是𝜹【𝝫(st)-𝝫(st+1】,但实际上这个算法的结果更差。

我们已经建立了状态值函数的函数*似,现在让我们把这个概念扩展到动作值函数。

设𝝫(s,a)为状态 s 的特征,动作 a ,我们要做的是根据一个策略 π来估计 Q(s,a)的值。

与状态值类似,动作值函数为:

𝜽权重的更新是:

神经网络

与非线性函数*似(如神经网络)相比,线性函数*似的主要缺点是需要良好的精选特征,这可能需要领域知识。

在非线性函数逼*器中,我们将再次重新定义状态和动作值函数 V 和 Q,例如:

所以现在 v 和 q 是非线性函数即以𝝫(s) / 𝝫(s,a)和𝜽为参数。
在这个公式中我们要注意的是,特征的数量和𝜽向量的大小不一定相同(就想象一个神经网络)。

从上面我们现在可以计算 TD 误差𝜹和权重𝜽的更新

请注意,𝜹是使用先前已知的𝜽值(此处称为𝜽⁻)和新计算的值来计算的。
神经网络计算的细节可以在反向传播文章第一部分、第二部分和第三部分中找到。

结论

总之,当类似情况发生时,函数*似有助于找到状态或动作的值,而在计算 V 和 Q 的真实值时,需要完整的计算,并且不从过去的经验中学习。此外,函数逼*节省了计算时间和存储空间。

相关文章

  • 政策梯度循序渐进
  • 基于策略的强化学习
  • 强化学习中的演员评论家介绍

Scala 中的函数式编程特性

原文:https://towardsdatascience.com/functional-programming-features-in-scala-e770c7f31a6c?source=collection_archive---------21-----------------------

数据工程

Scala 语言的特性和模式

在过去的几个月里,我一直在探索使用 Scala 及其 eco 系统进行函数式编程。

在这篇文章中,我将重点介绍该语言的一些特性,这些特性支持为分布式系统和数据操作直观地创建功能代码。

Photo by apoorv mittal on Unsplash

高阶函数

根据官方文档,函数是 Scala 中的第一类对象,这意味着它们可以-

  • 把另一个函数作为参数,或者…
  • 返回一个函数

一个函数将另一个函数作为参数的例子是 Scala 的标准集合库中的map()函数。

val examplelist: List[Int] = List(2,9,8,14)examplelist.map(x=> x * 2) // anonymous function as argument

当使用标准的 Scala 集合时,链操作符也非常直观,尤其是使用中缀符号时。在下面的小代码示例中,我定义了一个从 1 到 20 的数字列表,过滤偶数,然后对它们求和。

(1 to 20).toList filter (_%2 == 0) reduce (_ + _)

_是通配符——在地图和过滤器的情况下,它指的是集合中的值。

递归

对集合中的所有项目进行操作的推荐方式是使用操作符mapflatMapreduce

如果这些操作符不能满足用例的需求,那么写一个尾递归函数来操作集合中的所有条目是非常有用的。

下面的代码示例显示了计算一个数的阶乘的尾递归函数定义。

import scala.annotation.tailrec@tailrec
// Factorial Function Implementation that uses Tail Recursion
def factorial(in_x: Double, prodsofar: Double = 1.0): Double = {
    if (in_x==0) prodsofar
    else factorial(in_x-1, prodsofar*in_x)
}factorial(5)

在 Scala 中,一个尾部递归函数,如上所述,可以被编译器优化(使用上面的@tailrec注释),只占用一个堆栈帧——所以即使是多层递归也不会出现 stackoverflow 错误。这是可能的开箱即用,不需要任何框架或插件。

如上所述,推荐的方式是使用集合运算符(如reduce等)。).作为集合 API 简单性的演示,上面的阶乘函数也可以由下面的 1-liner 实现

(1 to 5).toList reduce (_*_)

为了从概念上理解reduce,看看这个伟大的链接!

(还要做查看foldLeftfoldRightmapflatMap的解释,了解一些常用的数据操作!)

Photo by Patrick Baum on Unsplash

案例类别

Case 类可以非常容易地实例化,不需要 boiler plate 代码,如下例所示。

case class BusinessTransaction(sourceaccountid: Long, targetaccountid: Long, amount: Long)// create some transactions now to demo case classes// I lend my friend
val 1_xaction = BusinessTransaction(112333L, 998882L, 20L)
// My friend pays me back 
val 2_xaction = BusinessTransaction(998882L, 112333L, 20L)

仅仅上面的 1 case class ..行做了以下有用的事情——

  • 定义了 3 个不可变的值sourceaccountidtargetaccountidamount
  • 定义 get 方法来访问构造函数参数(例如:1_xaction.amount)

虽然易用性很好,但 case 类是在 Scala 中存储不可变数据实例的推荐方式。例如,在大数据应用程序中,大数据文件的每一行都可以通过 case 类建模并存储。

使用 case 类存储数据的一个例子是这里的。

在链接的示例中,函数rawPostings将数据文件的每一行建模为 case 类Posting的一个实例。最终,它返回一个类型为RDD[Posting]的数据集。

模式匹配

在 Scala 中,case 类、常规类和集合等对象可以通过模式匹配进行分解。

您可以使用模式匹配来-

  • 分解对象的类型(如下例)
  • 获取集合的头(例如一个List或一个Seq)

下面的代码示例展示了如何使用模式匹配来分解一个Seq

val seq1: Seq[Int] = Seq(1,3,4,5,5)seq1 match {
    case x::y => println(s"The first element in the sequence is ${x}")
    case Nil => println("The sequence is empty")
}

cons 操作符(::)创建一个由头部(x)和列表其余部分(称为尾部,y)组成的列表。

伴随物体

在 OOP 中,一个静态变量有时被用在一个类中来存储多个实例化对象的状态或属性。

但是 Scala 中没有static关键字。相反,我们使用的是伴随对象,也称为单例对象。伴随对象是使用object关键字定义的,并且与伴随对象的类具有完全相同的名称。

伴随对象可以定义不可变的值,这些值可以被类中的方法引用。

在 Scala 中有两种使用伴随对象的常见模式

  • 作为工厂方法
  • 提供类共有的功能(即 Java 中的静态函数)
// The 'val specie' straightaway defines an immmutable parameter abstract class Animal(val specie: String) {
    import Animal._ // Common Behaviour to be mixed-in to Canine/Feline classes
    def getConnectionParameters: String = Animal.connectionParameter }object Animal { // .apply() is the factory method
    def apply(specie: String): Animal = specie match {
        case "dog" => new Canine(specie)
        case "cat" => new Feline(specie)
    } val connectionParameter:String = System.getProperty("user.dir") }class Canine(override val specie: String) extends Animal(specie) {   
    override def toString: String = s"Canine of specie ${specie}"
}class Feline(override val specie: String) extends Animal(specie) {
    override def toString: String = s"Feline of specie ${specie}"
} // syntactic sugar, where we don't have to say new Animal
val doggy = Animal("dog")
val kitty = Animal("cat")doggy.getConnectionParameters

选择

大多数应用程序代码检查 Null/None 类型。Scala 对空类型的处理略有不同——使用的构造称为Option。最好用一个例子来说明这一点。

val customermap: Map[Int, String] = Map(
    11-> "CustomerA", 22->"CustomerB", 33->"CustomerC"
)customermap.get(11)         // Map's get() returns an Option[String]
customermap.get(11).get     // Option's get returns the String
customermap.get(999).get    // Will throw a NoSuchElementException
customermap.get(999).getOrElse(0) // Will return a 0 instead of throwing an exception

在 Python 这样的语言中,if None:检查在整个代码库中很常见。在 Java 中,会有 try-catch 块来处理抛出的异常。Option s 允许关注逻辑流程,对类型或异常检查进行最小的转移。

在 Scala 中使用Option s 的一个标准方式是让你的自定义函数返回Option[String](或者IntLong等等。).让我们看看Map结构的get()函数签名-

def get(key: A): Option[B]

使用它的一个(直观的)方法是用如下所示的getOrElse()函数链接它

// Map of IDs vs Namesval customermap: Map[Int, String] = Map(
    11-> "CustomerA", 22->"CustomerB", 33->"CustomerC"
)customermap.get(11).getOrElse("No customer found for the provided ID")

使用Option s 的一个非常有用的方法是使用像flatMap这样的集合操作符,它直接透明地为你处理类型。

// Map of IDs vs Namesval customermap: Map[Int, String] = Map(
    11-> "CustomerA", 22->"CustomerB", 33->"CustomerC"
)val listofids: List[Int] = List(11,22,33,99)listofids flatMap (id=> customermap.get(id)) //flatMap magic

这就是我这篇文章的全部内容!我正在研究 Akka 和 Actor 模型的并发系统。在以后的文章中,我将分享我在这个主题上的心得(以及它与 Scala 函数式编程方法的关系)。

原载于http://github.com

函数式编程太棒了

原文:https://towardsdatascience.com/functional-programming-is-awesome-c94bcd150ae6?source=collection_archive---------5-----------------------

为什么函数式编程正在兴起

编程范例是一个用来描述编写命令的方法的术语。一门语言的理念是建立在它的编程范式之上的。最著名的三个范例是面向对象编程、命令式编程和函数式编程。没有一种意识形态比另一种更好,因为通常它更多的是关于使用正确的工具来完成工作。

函数式编程是一个大多数软件工程师至少模糊地熟悉的概念。有史以来第二种为计算机编程而编写的编程语言 Lisp 实际上很好地包含在函数范式中。根据简化的定义,函数式编程优先考虑数据的不变性和数学计算,而不是传统地修改存储在类构造函数中的部分对象。对于现代函数式编程,这种想法有点牵强,但这不一定是件坏事。函数式语言的可变性带来了更多的用途,我敢说:

功能

到函数式编程。记住这一点,函数式编程并不局限于函数式语言。例如,Python 具有功能特性。尽管传统上,函数式编程有着难以置信的不同,但函数式和面向对象的范式似乎与用于数据科学的大多数语言有点接*。

对我们的工作很有帮助

大多数函数式语言的标题中都有“统计”。这很方便,因为数据科学家很像统计学家,只是添加了编程和机器学习技能。对于数据科学家来说,函数式语言通常更快,最重要的是更容易。

相信我,你不会想浏览 C 代码,因为你的准确性有点低。大多数函数式语言都是完全可读的,并且很容易输入和掌握。一些人可能会惊讶地发现,函数式编程是许多互联网最古老的大数据管道的基础。随着机器学习和统计计算的兴起,函数式编程最*变得越来越流行。

酷语言

有很多很酷的统计语言,其中很多都有自己的特色和其他更传统的特色交织在一起。在函数式编程语言下,有很多我非常喜欢的很酷的语言。

朱莉娅

朱莉娅是我一直以来最喜欢的语言。尽管 Julia 确实是函数式的,但它确实包含了一些可变的、类似面向对象的属性,这使得它在编程上更加方便。作为一门高级语言,Julia 的速度快得令人难以置信。它很容易键入,如果键入得好,它可以和 C 一样快,同时比 R 和 Scala 更容易阅读。通常,在 Julia 中建立和训练一个模型并不需要很长时间,这增加了使用 Julia 的好处,因为语言很容易,ML 很快。在某些情况下,比如在我的 ML 包中,车床,机器学习可以用更少的行来完成,构造函数的属性可以用参数多态性更容易地变异。

咬舌

尽管 Lisp 不一定因其数据科学领域而出名,但它仍然是一种非常酷的语言。Lisp 和 Julia 一样,让编程变得非常简单和方便。一个真正值得注意的特性是 Lisp 的宏和 Julia 的宏。宏本身是一个主要的功能特性,如果使用正确,可以使笔记本编码变得非常容易。应该注意的是,Lisp 已经将自己分割成不同的语言集,包括 Scheme、Clojure 和(Common) Lisp。很难理解或估计第二高级语言及其功能的影响,但范围肯定是相当大的。

稀有

现在我们问候我们的老朋友,R. R 传统上是一种函数式语言,但像大多数其他语言一样是(或已经成为)多范式的,这意味着它从每个特定的编程范式中挑选自己喜欢的。这很好,因为它给了 R 可变性的优势。r 起源于 S 语言,并且一直专注于统计计算。

哈斯克尔

Haskell 与我上面谈到的多范式语言完全不同,Haskell 以其纯粹的函数性而自豪。我不能代表 Haskell,因为与列表中的其他语言不同,我从未使用过它。但是据我所知,Haskell 确实是一种很酷的语言。我对学习 Haskell 的担心纯粹是局限。正如我所讨论的,大多数现代语言都是多范式的,这使得它们可以有效地消除任何需要消除的错误,而无需创建新的代码库。

最后的想法

我大部分时间都在函数式语言中度过,主要是 Julia,如 Github 上的笔记本库所示,其中主要包含 Julia 笔记本。我喜欢函数式编程,因为它非常适合我所做的事情。当然,有些时候 Python 构造函数(类)可能更适合某项特定的工作,但总的来说,Julia 完成了这项工作,它的输入方式对我来说非常流畅和高效。对于其他人来说,函数式语言可能无法实现他们的目标,对于一生都在使用面向对象语言的人来说,学习函数式语言可能很困难。归根结底,语言是一种选择,大多数语言都有开发者,大多数语言都有优缺点。

什么是增强现实

原文:https://towardsdatascience.com/fundamentals-of-augmented-reality-ar-89ce986f70f8?source=collection_archive---------8-----------------------

Image by Dina Dee fromPixabay

什么是增强现实,它是如何工作的

增强现实(AR)是我们用数字数据增强的现实。

数字数据可以是文本、图片、视频、3d 资产或以上所有形式的组合。

AR 系统将需要理解现实并重建它,以创建它的数字双胞胎。

它还需要使用户能够与数字孪生和数字数据进行交互。

照相机没有固有的方向感。你不能命令它给你前面或后面的东西拍照。你只能把它指向你想要的方向。

这是一个传感器阵列,当光线穿过一个洞射向它时,它就会燃烧起来。

赋予相机方向感和对世界的理解是一个复杂的过程。处理分析和理解像素的研究领域被称为计算机视觉(CV)。

像我们一样看世界,像我们一样分类物体,像我们一样学习适应世界的变化,这就是机器学习(ML)。

我们不断学习,变得更加聪明。当机器学习并产生比以前好一点的结果时,它的人工智能(AI)。

ML、AI 和 CV,以及组成 IMU(惯性测量单元)的一些硬件传感器,使 AR 成为可能。

AR 的层次

增强现实应用的核心是摄像头。一切都来源于摄像机带入系统的数据。

通过检测形状和运动来形成增强世界。这构成了物理层。

除了有形的层面,还有赋予我们所见事物意义的语义层。

语义层包括训练神经网络,以便机器能够像我们一样理解世界。

自动驾驶汽车在很大程度上解决了这个问题。这些汽车上的硬件比手机上的更先进。在移动领域,我们仍在努力构建理解物理世界的基础层。

这篇文章是关于物理层的。

物理层

物理层的主要组件是-

  1. 惯性测量组合
  2. 用户交互
  3. 点云和空间制图/ SLAM
  4. 模式匹配
  5. 锚,跟踪和坚持。

1.惯性测量组合

IMU(惯性测量单元)是测量线性加速度的加速度计、测量旋转的陀螺仪和测量航向的磁力计。

汽车上的传统里程表通过检测车轮的转动来测量行驶的距离。

手机上的视觉里程表从一系列图像中测量行驶的距离和方向。

视觉里程计与 IMU 的组件相结合,形成视觉惯性里程计(VIO)系统。

我们不能使用传统的里程表传感器,因为它们是为车轮设计的,而我们的是腿部运动。

2.用户

我们不需要智能眼镜来看世界,就像我们不戴眼镜时一样。

AR 的用处来自于使用关于世界的信息,然后给它增加价值。

博物馆里的灭绝动物可以活过来,或者将我们的相机对准建筑物可以向我们展示更多信息。如果你去伦敦,你现在看不到大本钟,因为伊丽莎白塔还需要几年才能完工。但是,如果你下载大本钟 AR 应用程序,并将其指向脚手架负载的结构,你就可以再次看到和听到大本钟。

3.点云和空间制图/ SLAM

来自相机的数据由计算机视觉算法进行分类,这些算法试图识别数据流中的现实世界物体,并返回一堆点,也就是点云。

拿一个放大镜仔细看一张图片,你会开始看到像素。或者,如果你在 Photoshop 中不断放大图片,你会开始看到像素。这张照片只不过是一个点云。在图片的情况下,这些点被称为像素。

图片中的像素以某种方式组织和排列在一起,使得从远处看,图片是完整的。手机上的点云数据还没有整合起来,因为它仍在试图理解现实世界中的图片。

连接云中的点会产生一个网格。看起来像蜘蛛侠用蜘蛛网覆盖你的家具。随着新的信息通过摄像机进入,网格不断变化并一直扩展,直到系统可以开始锁定对象。这也称为空间映射。

在绘制环境地图的同时,该程序还试图定位自己,以找出设备相对于周围环境的位置以及它面对的方向。这被称为 SLAM(同步定位和绘图)

然后程序试图在这个网格中找到熟悉的模式。这就把我们带到了下一个话题——模式匹配。

在下面的参考部分有一个来自微软的视频,展示了空间映射如何在 Hololens 上工作。

4.模式匹配

苹果的 ARKit 和谷歌的 ARCore 的第一次发布,移动上的两个原生 AR 框架只识别水*面。这两个框架花了几个月才识别出垂直面。

水*面为我们提供了放置数字对象的地面和桌面。

很多 AR 游戏非常有创意的使用了水*面。现在很有趣,因为它是新的。除了游戏,要让 AR 在现实生活中有用,我们需要的不仅仅是飞机。

除了程序检测形状,我们可以告诉程序寻找一个复杂的模式。该图案以图像的形式提供给系统。

图像识别

我们可以用图像识别做很多事情——比如当你把手机对准广告牌上的数字动画人物时,你就可以把这个人物放在手机屏幕上。让博物馆里的图片活起来,或者提供关于艺术家的信息,等等。

物体、房间和场景识别

我们还能够扫描 3D 对象,并为程序生成一个模式,然后识别现实世界中的 3D 对象。这叫做物体识别。

如果您将对象识别扩展到一个房间中的多个对象,它将成为房间识别。

在户外更大范围内进一步扩展,就成了场景识别。

Wikitude 支持物体、房间和场景识别。ARKit 在其最新版本中支持对象识别 it,并且用例有些受限。扫描 3D 对象以将其提供给系统的必要步骤需要时间来在消费硬件上正确完成。

虽然能够检测比*面更复杂的图案是件好事,但是这种方法有一个严重的缺点。

喂食模式限制了程序真正了解世界。如果我们要从每一个可能的角度给我们当今世界的每一张照片提供信息,这将需要很多年和数十亿美元,而且一旦我们告诉程序一张照片,这张照片可能已经过时了。

我们这个世界的事情一直在变。

一天中的时间变化,季节变化,灯光变化,使事物看起来不同。山在冬天会下雪,看起来和夏天不一样。同一棵树也会落叶。事情会随着时间而褪色。新的拆迁。新的结构,我们可以用几年的时间来写这段文字,写下所有发生变化的东西。

5.锚定、跟踪和持久性

很多人用持续这个词,其实是指跟踪一个主播。然后他们问了一个关于堆栈溢出的问题,并以错误的理由否决了一个响应。

让我们先弄清楚一些定义。

锚定是将数字对象放置在增强世界中。

跟踪是在相机四处移动时保持增强世界的一致定义,以便增强世界中的数字对象停留在它们锚定的位置。

但是它在追踪什么呢?

它从图像序列中跟踪特征点,通常是高对比度的点,以形成光流。ARKit 结合使用这种基于特征的方法和另一种称为直接方法的方法来完成工作。

关于特征点和从图像中提取特征的更多信息可以在参考文献部分找到。

持久性是指当应用程序关闭并再次打开时,能够记住数字对象在现实世界中的位置。

持久性的工作原理是保存(序列化)我们从世界点云中获得的地图。当您打开应用程序时,您可以选择重新加载保存的地图。这样,您就不需要在该空间中再次执行空间映射。

人类视觉系统中的术语“持续性”与大脑在图像被取走后保持图像几分之一秒的能力有关。这就是电影的工作原理。对于我们来说,每秒 24 帧是一个很好的帧速率,可以保留上一帧并将其融合到下一帧中,以获得流畅的运动感。但是,那不是 AR 中的坚持。那是追踪。

模式匹配的局限性

当我们 2 岁的时候,我们看着一个图案,然后指着它。一个声音轻轻地告诉我们,这是一张桌子!表!然后我们看了其他 100 张桌子,被告知是桌子!

稍微不同的形式但共同的特征可以用共同的标签来标记。在某种程度上,我们开始对桌子充满信心。

手机上的 AR 很难整理出飞机在现实世界中可能出现的所有不同方式。

一个水*面可以处于许多不同的高度,在不同的光照条件下,它们看起来可能不同。

垂直面可以有多种不同的角度。

可以有任意数量的既不水*也不垂直的倾斜*面。

墙从地面升起。45 度的墙。如果我们沿着边走,现在我们是沿着一个多边形而不是一个矩形。并且墙壁彼此相交。他们总是这样。

随着摄像机花费更多时间收集数据,程序的置信度可能会上升或下降。

随着新数据的到来,也许那架飞机现在看起来更大或更小,或者位于大厅更远处。来自位于第一架飞机后面 50 英尺的另一架飞机的数据进入,现在从摄像机的角度看,这两架飞机看起来像一个巨大的垂直*面。

随着时间的推移,也许程序将能够解决飞机是分开的。但是我们没有更多的时间了。我们希望程序能非常快地完成所有这些计算。要让 AR 在手机上有用,它必须实时工作。

跟踪的局限性

随着对相机周围世界的理解发生变化,世界的定义也发生变化,程序越来越难准确地记住数字世界中特定对象的位置,尤其是当它不看着它时。

在现实世界中,这个问题可能是这样的

我看到一台自动点唱机,就走过去在酒吧找了个座位坐下。现在我知道点唱机在我身后。也许我会点一杯啤酒,放在我正前方几英寸的地方。如果这是菲利普·K·蒂克的小说,也许这就是当我眨眼的时候世界改变的时候。世界绕着它的轴旋转,也许我忘了和它一起旋转。我伸手去拿啤酒,它已经不在我刚才放的地方了。点唱机也不是真的在我身后。它现在在我的左边!

想象一下你周围的一切都有可能像这样每秒钟移动 30 次!(默认情况下,手机上的摄像头以每秒 30 帧的速度录制视频)。

我们需要在这些芯片上有大量的能量,以便能够实时处理这个世界并把它保持在一起。

结论

我们的大脑是我们的硬件,我们的智力是我们的软件,已经进化了一百万年。相机已经有 100 多年的历史了,机器学习比它还新。

要做好这件事有很多挑战。云计算是真实存在的,随着 5G 网络速度的到来,我们应该能够使用云的力量,并将结果实时传输回手机。

AR 在教育、旅游、时尚、零售、公用事业、娱乐、出版、MRO、远程指导、游戏等领域有着巨大的潜力……这个清单很大,而且还在不断增长。

数十亿美元正涌入这项技术。一些人认为这是继互联网之后的下一个最大的革命。

Magic Leap 是一家制造 AR 耳机的公司,它成为了科技史上获得资金最多的初创公司——据报道,风投资金达 23 亿美元,而且还是在没有产品的情况下。当它结束融资时,它所拥有的只是展示潜在产品的视频。现在他们有了一个产品。这是好的,但远远达不到他们在那些视频中显示的。后来他们声称这些视频是在视觉特效软件中被篡改的。不知道他们是怎么逃脱的。

但是,这是当今 AR 创业世界存在的狂热。没有投资者想错过。

无论财务预测是什么,最终,我相信它会改善我们联系的方式。

半个世纪以来开发的复杂计算机视觉算法可以实时检测面部特征。Snap 使用该算法覆盖数字图像,用户以有趣的方式使用它来建立关系和人际联系。

令人愉快的体验来自看似互不关联的技术层面。

在实验室深处智能开发的扫描像素技术(CSAIL)可以通过帮助人们以新的方式交流来获得其意义,并在将他们与世界联系起来的事物中找到新的意义。

对我来说,这是一个完整的循环,这也是我所期待的。

参考

从图像中提取特征;

[## 特征提取-维基百科

在机器学习、模式识别和图像处理中,特征提取是从一个初始集合开始的

en.wikipedia.org](https://en.wikipedia.org/wiki/Feature_extraction)

微软 Hololens 空间制图:

机器学习基础(三)

原文:https://towardsdatascience.com/fundamentals-of-machine-learning-part-3-b305933f00cd?source=collection_archive---------16-----------------------

信息论

介绍

这是我认为机器学习的基础主题系列的第 3 部分。这些主题是加深对该领域理解的基础。到目前为止,我们已经介绍了:

  1. 概率论
  2. 最大似然估计

这篇文章的目的是涵盖信息论中的重要概念,并描述它们如何用于机器学习。这里的许多主题将建立在我们在概率论的文章中讨论的概念上,比如独立性和期望。

我将利用机器学习和统计学的思想来激发和构建这些概念。如果你有物理学背景,你可能已经看到这些概念的不同动机(即通过热力学)。

信息

让我们假设我们的目标是通过使用的单词来检测给定文本的作者,以此来激发我们的讨论。哪些词对检测作者身份有用?直觉上,像“the”、“or”和“it”这样的词不会很有用,因为无论作者是谁,这些词都很有可能出现在任何文本中。看起来普通单词包含的信息比罕见单词少,而且信息内容在某种程度上与概率直接相关。

让我们通过让 x 是代表所有可能单词的随机变量, p ( x )是观察一个特定单词的概率 x 来使这个更正式。我们想要为通过观察一个特定的单词所获得的信息创造一些可量化的概念。

我们将使用 h ( x )来表示从观察单词 x 中获得的信息。同样,对于两个单词 xy ,我们可以将通过观察它们获得的信息写成 h ( x,y )。我们的目标是找到一个合适的 h。

首先,我们来考虑两个词 xy 的独立性。像“足球”和“比分”这样的词不是独立的,因为看到一个会使另一个更有可能。所以在“足球”之后看“比分”获得的信息应该不大。回想一下第一部,独立在形式上是指 p ( x,y)= p(x)p(y)。如果两个词 xy 不相关,我们要 h ( x,y)=h(x)+h(y)。换句话说,同时看到两个不相关的单词所获得的信息应该是单独看到它们所获得的信息的总和。

我们希望我们的 h 公式与 p,相关,但是我们有这样一个问题,即独立观察的联合概率是一个乘积,而联合信息是一个和。为了解决这个问题,我们使用对数的乘积规则将乘积转换为总和:

log[ p ( x,y)]= log[p(x)p(y)= logp(x)+logp(y)。

将信息与概率的对数联系起来似乎是我们需要的技巧。我们把与 x 相关的信息写成:

Information gained from observing x.

这个公式满足我们的要求,即更可能的观察产生更少的信息,对于两个独立的观察 xy ,我们有 h ( x,y ) = -log p ( x, y)=-log[p(x)p(y)]=[-logp(x)]+[-logp(y)]=h()

对数的底是一个任意的选择。信息理论家通常使用基数 2,并将信息单位称为“比特”,而在机器学习中,通常使用基数 e 并将信息单位称为“NAT”。这个信息量的另一种观点是,给定某种编码,hh(x)给出了发送一条消息 x 所需的位数。

我们刚刚把信息写成了一个随机变量的函数。在第 1 部分中,我们了解到随机变量 x 上的函数 g 的期望值,给出了 g 的期望值(或*均值):

Expectation of g(x) with respect to x.

我们的信息函数的期望 h 是信息论中最基本的概念之一。这种期望被称为随机变量 x 的熵,通常用大写字母 H 表示:

Entropy of random variable x.

熵是信息函数的期望值,或者换句话说,它是通过观察从 p ( x )随机抽取获得的*均信息量。这是一个需要知道的有用值!

信息论者可能会使用熵来计算传输给定长度的消息所需的预期比特数。更好的是,为了降低传输成本,找到使熵最小化的消息编码将是有益的。这将允许发射机压缩消息,并且每条消息发送更少的比特。

寻找有效的编码类似于为机器学习问题寻找特征的有效表示。我们希望用尽可能少的特征来表示我们的数据(以避免过度拟合和维数灾难),同时仍然保持足够的信息来做出准确的决策。

我们将会看到,熵的概念对于思考其他几个重要的概念是有用的。

交叉熵

让我们回到我们的作者分类问题。让我们通过只考虑两个类来简化问题:{文本来自作者 A,文本不来自作者 A}。我们将把我们试图分类的每个文档视为一个“单词包”,这意味着我们不关心单词的顺序,只关心哪些单词存在。我们将每个文档表示为向量 x ,其中如果单词 j 出现在文档中,则条目 j 为 1,否则为 0。

我们假设存在某种基本事实分布 p ( x ),这给出了文档 x 是由作者 a 编写的概率。如果我们可以了解这种分布,那么对于任何一个其中 p ( x ) >为 0.5 的文档,我们都可以猜测该文档是由 a 编写的

但是我们不知道 p ,所以我们写下一个模型 q 并尝试拟合 q 的参数,使其接*p。然后我们将使用 q 来决定 A 是否是任何给定文本的作者。

由于我们使用的是 q ,因此对一个文档 x 进行分类所需的信息量为h(x)=-logq(x)。但是如果 x 实际上是由 p 分配的,那么对于xt所需信息的期望值是:

Cross Entropy

这是 q 相对于真实分布 p 的交叉熵。如果我们以此为代价函数,找到使交叉熵最小化的 q 的参数,那么当 qp 相同时,将出现最佳解。

最小化交叉熵通常是逻辑回归和用于分类的神经网络的目标。可以看出,最小化交叉熵相当于最大化我们的模型 q. 的似然性。因此,这种解决分类的方法找到了最大似然估计量,如第 2 部分中所讨论的。

相对熵(KL-散度)

假设我们使用的是 q 而不是 p ,交叉熵给了我们分类文档所需的*均信息量。显然,如果我们使用 p,,那么*均起来,我们只需要 H (x)比特数(真实分布的熵)。但是由于我们使用的是 q ,*均需要 H ( p,q )位(交叉熵)。

使用 q 差多少?用 q 代替 p 需要 H ( p,q )- H (x)额外的位。我们称这个值为相对熵或 Kullback-Leibler (KL)散度。如果我们代入交叉熵和熵的方程,然后收集各项,我们得到 KL 散度为:

KL-Divergence

同样,这给了我们所需的额外位数(或 NAT ),因为我们使用了 q 来代替 p 。KL-散度总是大于 0,除非 q 等于 p 。因此,最小化也是一个常见的目标函数。最小化 KL-散度也最小化交叉熵,我们已经说过交叉熵是最大似然估计量。

交互信息

我们之前讨论过,有些单词并不是相互独立的,当我们同时观察它们时,这种依赖性会导致我们获得多余的信息(例如“足球”和“得分”)。我们想知道两个变量共享多少信息。

回想一下,如果 x 和y 为自变量,那么它们的联合分布为 p (x,y) = p (x) p (y)。如果它们不是独立的,那么我们就不能这样分解联合分布。当变量独立时,我们没有任何冗余,随着变量越来越依赖,冗余信息量增加。为了对此进行量化,我们使用 x 和 y 的互信息:

Mutual Information.

如果我们用独立因子分解来表示真实的联合分布,那么互信息就是所需的额外信息量。如果变量是独立的,那么 KL 散度将为 0,否则它将随着变量冗余度的增加而增加。

互信息经常被用于在机器学习中执行特征选择。对于给定的特征,我们可以用类别标签来度量特征的互信息。如果互信息高,则该特征是该类的强指示符。例如,如果作者 A 总是在他们的文档中包含他们的名字,那么他们的名字和类之间的互信息将会非常高。

类似地,如果我们有太多的特征需要考虑,我们可以使用特征之间的互信息来删除那些冗余的特征。如果作者 A 总是包括他们的名字和他们的家乡,那么我们可以安全地从我们的词汇中删除他们的家乡,并且仍然可以很好地完成任务。

结论

在这篇文章中,我们已经涵盖了信息论中直接适用于机器学习的主要概念。从任何意义上来说,这都不是一个详尽的处理方法,但是这些是我个人在实践中一次又一次看到的概念。

更多阅读,我建议看看克里斯托弗·毕晓普的书模式识别和机器学习。整本书是知识的金矿,但是我讨论的概念都可以在第一章的信息论部分找到。

大卫·麦凯的书信息论、推理和学习算法也很受欢迎。

下次见!

数据库:SQL 基础

原文:https://towardsdatascience.com/fundamentals-of-sql-d0182bc1346b?source=collection_archive---------25-----------------------

带有客户交易实例的简单易懂的解释。

这篇文章不可能完全涵盖 SQL 功能的每个方面,但是,我试图创建一个快速参考指南,提供 SQL 的实用方面,并以简洁的方式展示重要的功能。如果你发现任何错误,请毫不犹豫地评论出来。

第 1 级

选择、从、在、分组依据、拥有、排序依据

当我们编写 SQL 语句时,它们的顺序应该和上面写的一样。我们还可以看到下面的代码:

从< 中选择
条件>*
其中< 条件> 分组按 <条件><条件>
顺序按< 条件>

然而,在执行方面,流程是不同的。这意味着,当 SQL 语句在服务器端运行时,其读取顺序与下面写的顺序相同:

FROM(它选择所需的表)
WHERE(它根据条件过滤行)
GROUP BY(它聚合过滤的结果)
HAVING(聚合值的附加过滤级别)
SELECT(从结果中选择适当的列)
ORDER BY(按升序或降序排列值)

示例:

SELECT OrderQty, Count(*) AS countsFROM Sales.SalesOrderDetailWHERE UnitPrice > 1000GROUP BY OrderQtyHAVING count(*) < 500ORDER BY counts desc;

结果:

结果显示,对于单价大于 1000 的所有订单,我们有 481 个数量为 6 的订单实例(意味着 6 个项目)和 266 个数量为 7 的订单实例,依此类推。因此,数量越高,计数越低。

第二级

子查询,别名

我们从子查询中得到的结果被传递给主查询,以便生成复杂且更精确的结果。此外,别名用于为列或表提供临时名称。让我们看看使用这两种方法生成结果的例子。

SELECT OrderQty, LineTotalFROM Sales.SalesOrderDetail AS s1WHERE UnitPrice = (SELECT MIN(UnitPrice) FROM Sales.SalesOrderDetail AS s2WHERE s1.SalesOrderDetailID = s2.SalesOrderDetailID )

这里的子查询返回每个特定 ID 的最小单价。因此,如果 1 的 SalesOrderDetailID 有 5 件商品,它将返回所有这 5 件商品中的最低价格,ID 2 也是如此。

然后,主查询将返回单价与子查询输出的单价匹配的订单数量和行合计。s1 和 s2 称为别名,对于连接表非常有帮助。

结果

这意味着,我们有一个实例,其中数量为 1,行总计为 2024.99400,属于一个 ID 的最小单价。然后是另一个数量为 1 的实例,具有基于最低价格的特定行合计。

三级

在,存在,之间

IN 子句可用于子查询,如下所示:

SELECT FirstName, LastNameFROM Person.PersonWHERE BusinessEntityID IN (SELECT BusinessEntityID FROM Sales.SalesPerson WHERE SalesLastYear > 2000000)

在此语句中,我们仅从 person 表中获取那些 BusinessEntityID 也存在于子查询中的人员的姓名,并且子查询从 Sales 表中返回销售额高于 2000000 的 business 的 BusinessEntityID。

EXISTS 子句可用于子查询,如下所示:

 SELECT AccountNumber FROM Sales.Customer AS c1 WHERE EXISTS (SELECT * FROM Sales.SalesOrderHeader AS SOH WHERE SOH.CustomerID = c1.CustomerID AND OnlineOrderFlag=1)

子查询只返回布尔值,而不是可以与其他列匹配的某些值。因此,只要在线订单被标记为 1,它就返回 TRUE,否则返回 FALSE。换句话说,外部查询仅基于子查询提供的 TRUE 和 FALSE 条件工作。

介于两者之间的例子

SELECT SalesOrderDetailID, UnitPrice FROM Sales.SalesOrderDetail WHERE OrderQty BETWEEN 4 AND 6

它只是检查订单数量在 4 和 6 之间的行。

四级

窗口功能&案例报表

案例陈述真的很酷。

这仅仅是一个 if-then-else 语句。它检查一个条件,如果它是真的,那么它返回一个特定的值,如果不是,它移动到 else 部分。我们可以定义许多 if-then 语句和一个 else 语句。只要遵循 SQL 的规则,就可以在整个脚本的任何地方使用它

SELECT  SalesOrderID,CASE OrderQty WHEN 1 THEN 'Order quantity is 1' WHEN 2 THEN 'Order quantity is 2' WHEN 3 THEN 'Order quantity is 3' ELSE 'Greater Than 3'END AS Order_QuantityFROM Sales.SalesOrderDetail

上面的代码只是说,选择 OrderQty 列,如果它是 1,则打印“order quantity is 1 ”,并对其他列进行类似的操作,直到您点击 else,其余的值将被打印为“大于 3”

窗口函数对于销售、利润和其他指标的比较非常有用。

这是我们将对其应用窗口函数的真实表的快照。

 SELECT OrderQty,AVG(UnitPrice) OVER(PARTITION BY OrderQty) AS average,MAX(UnitPrice) OVER(PARTITION BY OrderQty) AS maximum,MIN(UnitPrice) OVER(PARTITION BY OrderQty) AS minimum FROMSales.SalesOrderDetail;

这是结果的快照。

第 5 级

存储过程和 IF-ELSE (T-SQL)

当我们不得不反复编写一段代码时,存储过程是很有用的。相反,我们可以创建一个存储过程,定义一个参数,然后使用 execute 命令执行该过程。我们定义的变量写在@之后,然后用在 WHERE 子句中。

CREATE PROCEDURE attempt @cost_limit int AS SELECT * FROM Production.ProductCostHistory WHERE StandardCost > @cost_limit and endDate is null GOEXECUTE attempt @COST_LIMIT = 10

结果给出了标准成本大于执行期间传递给 cost_limit 变量的值的所有值(在本例中为 10)。

下一个例子

首先,我们声明变量,然后,我们启动 IF 语句并检查事务类型的计数是否大于 1。如果条件为真,将执行 BEGIN 部分。SET 关键字用于将 select 语句的值存储到变量中。一旦设置了变量,我就使用 print 语句通过 SQL 的串联功能打印变量值。请注意,CAST 函数在转换变量的数据类型时非常有用。

DECLARE @TYPE1 intDECLARE @TYPE2 intDECLARE @TYPE3 intIF(SELECT COUNT(*) TransactionType FROM Production.TransactionHistory) > 1BEGINSET @TYPE1 =(SELECT COUNT(*) FROM Production.TransactionHistory WHERE TransactionType = 'W');SET @TYPE2 =(SELECT COUNT(*) FROM Production.TransactionHistory WHERE TransactionType = 'S');SET @TYPE3 =(SELECT COUNT(*) FROM Production.TransactionHistory WHERE TransactionType = 'P');PRINT 'Total count of W type transactions ' + CAST(@type1 as varchar(10)) + '.' ;PRINT 'Total count of s type transactions ' + CAST(@type2 as varchar(10)) + '.' ;PRINT 'Total count of p type transactions ' + CAST(@type3 as varchar(10)) + '.' ;END

使用存储过程和 IF-ELSE 函数输出结果的附加查询。

CREATE PROCEDURE Learning@quantity int,@cost INTASBEGINDECLARE @COUNT INTSET @COUNT =(SELECT count(*) from Production.TransactionHistory where Quantity > @quantity and actualcost > @cost)PRINT @COUNTIF @count > 1000BEGINPRINT 'There are more than 1000 instances with quantity =' + cast(@quantity as varchar)+ ' and cost =' + + cast(@cost as varchar)ENDELSEBEGINPRINT 'THERE ARE LESS THAN 1000 such INSTANCES'ENDENDGOEXECUTE Learning @COST=10 , @QUANTITY = 10

请注意一些要点

  • 取决于子查询输出的布尔值。
  • IN 取决于子查询输出的匹配值。
  • 在 SQL 中,子句的顺序很重要,它根据执行的顺序而不同。
  • 为存储过程定义的变量不同于声明的变量。
  • 任何内容都可以放在开始和结束之间,并作为单个批处理运行。

支持竞争的神经网络

原文:https://towardsdatascience.com/funderstanding-competitive-neural-networks-f855bd7882e1?source=collection_archive---------17-----------------------

几年前,我想出了一个小术语来表示理解复杂概念的有趣方式。典型的大学教学方式是打好理论基础(无聊的几个小时),重复你需要知道的基本科目(无聊的几个小时),然后最终对正在发生的事情做出解释(又无聊了几个小时),之后你离开时不会比开始时有更多的理解。与此相反,当你试图资助某事、 时,你先从一个有趣的激励性例子开始,然后再深入探究这一切的原因和方式。

这是三个系列中的第一个帖子,旨在为一个特别有趣的主题提供“有趣的介绍”:竞争神经网络及其在向量量化中的应用(请,停止运行,我知道这听起来像是沉重的数学负担,但我保证我会尽量减少!).在第 2 部分中,我们将讨论所谓的自组织特征映射(SOFMs ),之后,我们将在第 3 部分中研究不断增长的神经气体。

矢量量化:总体思路

想象你有一张黑白图像。实际上,您可以将这样的图像看作是一个点坐标列表 (x,y) ,其中包含了您想要涂成黑色的每个点。然后你会接*一个网格,就像在一个正方形的数学练习本上一样,然后给列表上的每一点涂上颜色。显而易见,你的点数越多,你的清单就越长。对于这个例子,我将我的工作牌头像数字化,并为它创建了这样一个列表,密度相对较低——它给了我大约 15,000(!)积分:

My work badge photo, digitized, converted to black and white and thresholded for optimum performance.

问题是,我们能减少点数,仍然得到可识别的、语义上忠实的图像吗?一种解决方案是找到能够很好地代表其附*一系列点的点,并使用它们作为这些点的“代理”。我们不使用 15,000 个点,而是指定几百个新点,并将它们放置在适当的位置,使它们各自相对代表周围的点。这将允许我们用最*的新点替换所有这些点,有效地将 15,000 个点减少到几百个点。此外,我们可以创建一个新点列表,这通常被称为“代码簿”,而不是每次都必须记下坐标,我们只需用最*的代码簿条目的索引替换每个点的 (x,y) 坐标对。如果我们已经很好地设置了点数,那么我们将得到一个相当不错的*似值。

The underlying idea of vector quantization: represent a large number of vectors by a smaller number of entries in a codebook, each of which is a relatively good proxy for the points it represents.

只剩下一个问题:我们到底该如何做?我的意思是,好主意,但我们需要找到这些点的方法,对吗?当然,最简单的方法是定义一个误差函数,并不断优化,直到我们达到目标。

The Growing Neural Gas algorithm converges to the point set relatively quickly: in 20 iterations, it created a semantically comprehensible representation, still with only 2,500 points — 16% of the original 15,564 points.

一种方法是简单地丢弃随机点,计算它们代表多少新点,以及它们的邻域中有多少点已经被代表,而它们的邻域中有多少点根本不应该被代表。然后,我们不断增加新的分数,剔除表现不佳的分数。这通常类似于两种较老的机器学习方法,称为简单竞争赫比学习。问题是这些需要很长时间才能融合。我指的是年龄——大多数时候,结果并不令人印象深刻。

The idea of Delaunay triangulation: to divided the set of points into triangles so that no point is within the circumcircle of another triangle (gray). By definition, this also means a Delaunay triangulation does not have intersections between the triangulating lines. Illustration courtesy of Wikipedia/Gjacquenot.

相反,我们可以做得更好。我们有一些数学技巧可以帮助我们做到这一点,叫做三角测量。三角剖分基本上是以一种特殊的方式将一个空间分成三角形。对于点,最简单的三角剖分当然是开始连接点,直到你得到很多三角形。事实证明,有更聪明的方法可以做到这一点。 Delaunay 三角测量在多个点之间创建三角形,这样没有其他点在任何三角形的外接圆(包含三角形所有三个点的圆)内。这给了我们一个不相交的三角形网格。一个奇妙的小副作用是,如果我们连接外接圆的中心,我们会得到由这些点围成的空间的所谓的 Voronoi 分割。将画出每个 Voronoi 分割的边界,使得点 P 周围的 Voronoi 分割将包括比初始点集内任何其他点更靠* P 的每个点。这有助于我们在点之间很好地划分空间:我们可以通过简单地测量代码簿点网格内 Voronoi 分区内的点的百分比以及空的百分比来测量我们模型的有效性。这使得误差函数相对容易优化。一件好事是,Delaunay 三角剖分和 Voronoi 分割都可以很好地推广到高维空间,所以在二维空间中工作的东西也可以在高维空间中使用。

变得有竞争力

A Growing Neural Gas model learning the topology of the Starschema logo, 100 iterations with a high drop-out rate.

好吧,那么“竞争性”神经网络呢?你可能遇到的大多数神经网络都遵循一定的模式:具有激活功能的神经元获得输入并产生输出。从这个意义上说,“竞争性”神经网络非常不同。相反,在竞争性神经网络中,神经元“竞争”被激活,其中激活通常是离所选数据点的距离的函数。最靠*数据点的神经元——也就是说,具有最高激活度的神经元——“获胜”,并向数据点移动,吸引其一些邻居。从这个意义上来说,竞争力允许学习拓扑,这是一个有用的副作用,当用于从低维表示重建高维形状时。事实上,Martinetz 和 Schulten 创建了第一个简单的神经气体模型,称之为拓扑表示网络 (TRN)。这篇由 Marco Piastra 撰写的论文展示了竞争性神经网络在重建甚至非常复杂的形状方面令人印象深刻的潜力,例如 22 类七面体或斯坦福兔子。

Neural gas models can learn fairly complex topologies, such as the human face, as seen before. In this example, a high-dropout slow-converging Growing Neural Gas starting with two vertices and adding a new one every ten iterations creates an approximation of my photo. This graph contains only 752 nodes, a compression of 95.17% of the original 15,564 points.

竞争学习有一个相当接*的神经生理类比。它是 Hebbian 学习的一种形式。这种机器学习的方法源于对“一起放电的神经元连接在一起”的观察:也就是说,当独立的神经元同时对刺激做出反应时,突触强度(神经元“接*度”的一种衡量标准)就会增加。正是神经元的这一特性被不断增长的神经气体用来连接各个顶点,使我们不必像自组织特征图那样指定图的大小和形状:最佳匹配和第二最佳匹配被连接为“共同响应者”,连接的强度取决于两点之间的相对响应强度。如果两个点都强烈响应,则表明它们与数据点的距离几乎相等,因此可以被视为紧密相连——“一起触发”会导致算法将相关点“连接在一起”。

虽然听起来可能很抽象,这些算法可以很容易地适应我们日常机器学习工作量的一部分。在无监督学习的许多应用中,增长的神经气体和自组织特征图是有用的,其中第一个也是最重要的当然是聚类。但与许多聚类算法不同,例如,生长神经气体不需要预先提供聚类数。这在不相交的簇的数量是问题的开始时是有用的。例如,考虑计算页面字数的问题:增长的神经气体,如果配置良好,可以将单词加入到单独的子图中,不相连的子图的数量给出了字数。类似地,难以可视化和解释的多个高维集群可以使用基于增长神经气体的算法轻松计数。

我们将在本系列的后续部分中讨论的两个实现——生长神经气体自组织特征映射 (Kohonen 映射)——具有广泛的用途。正如我们将看到的,它们不仅可以用于复制形状,还可以用于聚类和嵌入高维数据集。因为这些技术属于拓扑数据分析的更广泛的领域,这可能变得非常数学密集,并且因为它们不同于我们通常理解的神经网络的方式,神经网络由前馈神经元层和它们之间的连接组成,例如使用反向传播来训练。这些算法自 20 世纪 90 年代被发现以来,尽管具有迷人的特性,却一直被过度忽视。借助 Numpy、Theano 和 Tensorflow 等现代张量代数工具,这是深入竞争神经网络并实现其巨大潜力的最佳时机。在本系列的下一期中,我们将首先讨论自组织特征地图,以及如何将它们用于更多的日常数据科学应用。

本系列的下一部分,第二部分:自组织特征地图,将于 2019 年 1 月 20 日发布。看好这个空间!

星巴克数据集上的 Funk SVD 实践体验

原文:https://towardsdatascience.com/funk-svd-hands-on-experience-on-starbucks-data-set-f3e0946da014?source=collection_archive---------20-----------------------

Photo by Austin Distel on Unsplash

尝试使用协同过滤来个性化移动应用提供分发。

目录:

  1. 简介。
  2. 数据概述、清理和转换。
  3. 优惠在公司收入中的作用。
  4. 什么样的优惠真的让人兴奋?
  5. 使用 Funk SVD 的协同过滤。
  6. 模型微调。
  7. 结论。

介绍

如今,互联网资源、移动应用程序被设计为个性化促销优惠,以增加忠诚度,一方面超出预期,另一方面增加收入。作为 Udacity 数据科学家 Nanodegree 的一部分,我已经获得了几个可能的数据集,其中星巴克项目最让我兴奋,因为它包含模拟数据,模拟真实星巴克奖励移动应用程序中的客户行为。我很好奇以下几点是否能引起我的兴趣:

1.要约真的在公司的现金流入中扮演重要角色吗?
2。什么样的优惠真正让人兴奋,带来更多的收益?
3。如何通过使用协同过滤技术(Funk SVD)的个性化优惠分发来改善促销优惠方面的客户体验(关于 Funk SVD 的更多信息可在此处和此处找到)。

数据概述、清理和转换

数据包含在三个文件中:

  • portfolio.json —包含每个报价的报价 id 和元数据。
  • profile.json —每个客户的人口统计数据。
  • transcript.json 记录交易、收到的报价、查看的报价和完成的报价。

Porftolio 仅包含 10 行描述可能的优惠和细节,如优惠持续时间、难度(完成优惠所需花费的金额)、渠道、优惠 id、优惠类型(折扣、BOGO—‘买一送一’,信息性)以及优惠完成后将获得的奖励:

portfolio data transformed into pandas

配置文件包含大约 17 000 名客户的数据,该数据缺少 2175 人的性别和收入值。

profile data transformed into pandas (first 10 rows)

只要对于收入,没有人报告收入为零,那么让我们用零填充 NaN 值,并检查这如何影响图表。此外,性别中缺失的值要用“S”填充,以便调查。

Income before (on the left side), missing values filled with zeroes on the right side

从下面的散点图中我们可以看到,缺少性别值的 2175 个消费者与缺少收入值的消费者是相同的。他们在 118 岁时形成了一个特殊的群体。因此,我们可以用“S”来填充性别中缺失的值,用零来填充收入中缺失的值,因为这不会干扰其他客户群。

抄本包含交易、收到的报价、查看的报价和完成的报价的记录。它还包括时间(小时)、人员 id。可以从值列中提取优惠 id、奖励和金额。

抄本数据集的主要挑战在于,它不包含交易和影响这些交易的报价之间的直接关联标签。为了实现这种理解,我准备了一个功能,用于验证每个客户是否收到、查看了特定的报价,交易是否发生,以及报价是否在报价有效时间内完成。

然而,一个人可能同时收到不同的报价,两个报价都可以被客户查看,如果交易发生在两个报价都被查看的时间内,那么我们应该决定哪个报价实际上导致了交易。

Example of the above mentioned case

由于数据集没有给出明确的方向,也没有给出背景信息,我假设在最接*交易时间查看的报价将被视为影响交易的报价。如果其中一个报价是信息性的,而第二个报价是奖励性的,那么奖励性报价应该占优势,因为我认为奖励会比不提供任何额外好处的信息性报价更吸引客户。

转换函数的代码。

在应用 trans_affected_func 函数后,我们对顾客对收到的报价的反应行为模式有了清晰的认识。

返回到开始时找到的特殊组。

Number of offer types received by all customers (on the left) and by special group (on the right)

比例看起来差不多。这意味着星巴克应用程序在发送优惠时没有区分这个群体。

Number of affected transactions within offer types for all customers (on the left) and for special group (on the right)

当谈到交易数量时,与总体人口相比,特殊群体似乎更受信息提供的影响,而不是 BOGO。对他们俩来说都是第一次打折。

Overall amount spent by all customers (on the left) and for special group (on the right)

特殊群体的消费金额比例不同,这可以用 BOGO 在“S”群体中不太受欢迎、交易次数较少和消费金额较少的事实来解释。有趣的是,虽然受 BOGO 影响的交易数量明显低于折扣,但对于一般客户群体来说,BOGO 和折扣的总和非常接*。

研究发现,特殊群体在行为上不同于普通消费者群体,可能需要特殊对待。

要约在公司收入中的作用

不受要约影响的交易产生的收入的大部分:与任何要约无关的交易产生的购买流入的 65.53% 。折现率和 BOGO 给出了彼此相对相似的数字:分别为 14.06%和 13.33%。信息性的最多 7.08%。

这 34.47%的收入如何在客户中分配?

受优惠影响的现金流入是由至少收到过一次优惠的* 72%的消费者产生的。在给定的客户群体中,大约 28%的人根本没有受到影响,尽管在实验过程中至少收到了一个报价。

主外卖

要约在公司收入中的作用并不重要,尽管被认为是值得注意的。

什么样的优惠真的让人兴奋?

我们可以说,如果有大量评论、完成(如果适用)和交易,宣传片真的会让人兴奋。

Distribution of offers and the number of affected transactions

Overall sum of amount spent within each offer

从上面的图表中我们可以看到,所有的报价几乎是*均分配的,同时其中一些报价的审核和完成比其他报价更频繁。10 个优惠中有 6 个具有最高的观看率,其中 2 个奖励优惠位于顶部——discount _ 10 _ 10(有效期 10 天,难度 10)和 discount_7_7(有效期 7 天,难度 7)。他们还获得了最高数量的受影响交易。

从信息报价来看,有效期为 3 天的报价是最令人兴奋的,因为它影响了大量交易(6223) —非常接* discount_7_7 (6335)。

这三项优惠在客户消费总额方面也是冠军。

主要外卖:

发现难度分别为 7、10、持续时间分别为 7、10 的折扣优惠才是真正让人们兴奋的优惠。从信息性报价来看,持续时间为 3 天的报价对消费者的影响率也很高。这三项优惠也是在顾客总消费金额方面领先。因此,他们对消费者和星巴克都有利。

使用 Funk SVD 的协同过滤

第一步是准备用户项目矩阵,用户在索引中,报价在列中。在应用一组变换后,准备以下矩阵:

报价和用户被编码成整数值。单元格(I,j)中的“1”表示作为信息要约影响的结果,第 I 个用户完成了第 j 个要约或执行了交易。我们可以说第 I 个用户对第 j 个提议做出了积极的反应。零意味着第 I 个用户至少收到第 j 个报价一次,但是从未进行过被认为受报价影响的交易。行中缺少值意味着用户从未收到反映在列中的报价。

missing values in user item matrix

该矩阵非常稀疏,因为每列中有 63%的数据丢失。这就是我期望使用 Funk SVD 的好处,因为它可以用 1 和 0 填充所有缺失的值。

下一步是定义没有正则化的 Funk SVD 的基本形式。

然后我们可以对用户项目矩阵应用 Funk SVD。

Applying Funk SVD

查看矩阵分解的结果和原始用户项目矩阵。

Predictions and the original matrix

因此,我们有一个矩阵,其中的建议反映了对报价可能的正面(“1”)和负面/忽略反应(“0”)。

但是我们做得怎么样呢?预测够好吗?
为了验证结果,我们应该将用户项目矩阵分为训练集和测试集。在训练集上训练模型,并验证它在测试集上的表现,与简单的预测器进行比较。我们可以天真地假设所有的优惠都会被所有的客户完成/使用。请记住,我们只能验证在两个数据集中出现的客户和报价的预测。

指标和评估者

Funk SVD 函数的估计量是均方误差(MSE)。MSE 测量误差*方的*均值,即估计值和估计值之间的*均*方差。它显示了随着梯度下降迭代的增加,所有预测的*方差是如何减小的。准确性被选为绩效评估的衡量标准,因为对报价的积极和消极反应对我们来说同样重要:如果我们向客户发出报价,或者如果我们不这样做,都不会有大的伤害。这些阶层并没有失衡。考虑到所有这些,准确性度量被认为是可接受选择。

将用户项目矩阵拆分成训练和测试数据集。

Splitting user item matrix into train and test sets

我们可以对 5456 个普通用户进行预测,而对于 10 个用户,由于冷启动问题,我们不能进行预测,它们不会同时出现在两个集合中。

将模型拟合到训练集。

我已经在训练集上应用了该模型,并在训练集和测试集上验证了结果。此外,准确性,均方误差和 RMSE 比较了天真的预测数字。

MSE, RMSE, Accuracy on the train, test sets (on the left) and Naive model metrics and performance (on the right)

嗯,我的 FunkSVD 模型做得不是很好,因为该模型和朴素预测器之间的测试集的准确性差异只有 3%。

模型微调

上面的结果可以改进吗?我已经准备并应用了定制的 gridsearch_funkSVD 函数,该函数验证了模型在所有可能的参数下的表现。取得的成果反映如下。

注意:每当预测给出除 0 和 1 之外的值时,“过拟合”栏都填充“是”。该模型在列车上的表现证明了同样的事实。

观察:我们可以看到,潜在特征的数量越多,迭代次数越多,我们使用的学习越大,那么相应地,模型在训练集上过度拟合的机会就越多,相反,迭代次数、潜在特征和学习率越低,模型在测试集上的性能就越差。因此,应该在参数和性能之间进行权衡。

从上表可以看出,最佳参数是:潜在特征数=5,学习率=0.005,迭代次数=100。
这些参数给出了优化的模型。

结论

我分析过星巴克给定的数据,应用过数据清洗、转换和可视化。

65.53% 与要约无关的交易产生的购买流入。折扣和 bogo 给出了相对相似的数字:分别为 14.06%和 13.33%。信息性的最多 7.08%。不受报价影响的交易产生的大部分收入。

这些受优惠影响的 35% 的现金流入是由至少收到过一次优惠的 72% 的客户产生的。在给定的消费者群体中,约有 28% 根本没有受到影响,尽管在实验过程中至少收到了一份报价。

发现难度分别为 7、10、持续时间分别为 7、10 的折扣优惠才是真正让人们兴奋的优惠。从信息性报价来看,持续时间为 3 天的报价对消费者的影响率也很高。这三项优惠在客户消费总额方面领先。

基于转换后的交易信息,我形成了用户-项目-矩阵,反映了客户对收到的报价的积极或消极(忽略)反应。

由于不是所有的顾客都收到了所有可能的报价,所以选择了没有正则化的 Funk SVD 的基本形式来满足用户-项目-矩阵中缺失的值(比率)。为了评估模型的表现,我将数据分成了训练集和测试集。正如预期的那样,在测试集上,优化后的模型比天真的预测(向所有客户发送报价,好像所有客户都乐于接收和使用报价)做得更好。我们应该记住的是,对于 45 名客户,由于冷启动问题,我们无法做出预测,因为他们没有同时出现在两组中。

我无法达到超过 0.7093 的精度,因为模型在训练集上训练得越多,它就越是过度拟合。因此,在训练集上的训练模型和测试集上的预测能力之间存在权衡。尽管 0.7093 看起来并不太糟糕,但也不太有希望,我们应该考虑可能的进一步措施。

还能做什么?可能的进一步分析和改进

  1. 性能可以与监督学习算法进行比较,监督学习算法将接收客户数据作为输入,并预测消费者是否对报价做出积极响应。
  2. 可以从数据集中排除特殊人群,并且可以将模型性能与先前实现的性能进行比较。可能这个特殊的群体正在增加数据的方差,因此模型不能更好地概括。
  3. 作为我们在这里使用的离线方法的替代方法,我们可以进行在线方法,在该方法中,我们运行一个实验来确定在我们的用户群中实施一个或多个推荐系统的影响(例如,一个可以基于 Funk SVD,第二个基于监督学习算法)。对于这种情况,一个简单的实验可能是将用户随机分配到一个控制组,该组接收他们从未见过的额外优惠。然后,我们捕捉对它们的反应,并将其与所选算法的预测进行比较,并测量性能。

感谢您阅读本文。这篇博文只反映了所做分析的一小部分,更多你可以在 Github 上找到。

人工智能的未来是生物的

原文:https://towardsdatascience.com/future-of-ai-is-biological-b512d6c40fe6?source=collection_archive---------15-----------------------

自然智能是有机的/生物的。今天,我们认为人工智能(AI)是机器、机器人和软件代码。会保持不变还是发生变化成为生物神器?

迄今为止,尽管受到人脑的启发,但人工智能的旅程正在偏离它,而且越来越看起来不可持续。不可持续的能源和数据消耗,与大脑皮层和学习瓶颈相比的表现差异,为基于干细胞的神经网络提供了一个有前途的案例。

消耗太多能量:基于人工智能的机器可以计算得更快,但是消耗太多能量。马萨诸塞大学阿姆赫斯特分校的研究人员最*建立了人工智能训练的基准(如下图)。虽然这些型号需要 1000 瓦,但大脑需要 20W。对,就是这样。AI-1000 瓦;镍— 20W。再加上云计算的成本,云计算运行在由可再生能源和不可再生能源驱动的大型服务器群中。

Source: https://arxiv.org/pdf/1906.02243.pdf

不可持续的气候变化:如你所见,训练一个大型人工智能模型比一辆普通美国汽车排放的 5X 二氧化碳还要多。这不可持续。

这是一个最小值:专业人士不会调优一个模型,而是做 100 个或 1000 个模型,以达到最佳的人工智能模型。同样的研究人员分析了一个典型的 R & D 调优模型,发现它需要运行 1000 次。所以上面提供的数字是最小值。它乘以运行次数。

Source: https://arxiv.org/pdf/1906.02243.pdf

不像大脑:燃烧了所有的能量,我们得到了什么?狭隘的单任务问题解决者。多种人工智能模型需要通过管道连续进行复杂的对话。这与 NI 非常不同,NI 可以是串行的,也可以是大规模并行的。下次你看电影的时候,记得你是在同时听、看和想象。下面是来自脑成像研究的图像,显示了 50 个独立的过程为一项视觉运动任务并行运行。

fMRI… brain parallel processing Source: MIT Technology Review

构造不同:这是因为越来越多的大脑研究指出,大脑的构造不同于我们的深度学习架构。首先,深度学习中的数据以密集的形式表示,而大脑似乎具有稀疏的表示。这是什么意思?对于你见过的每个人,你都有一套大脑人工制品来维持他们的面孔。当你再次看到它们时,那组神经元被触发。它与基于一系列特征、轮廓等网络来识别面部的面部识别系统非常不同。AI 没有一个地方…所有的脸都混在同一个网络里。具有更稀疏表示的大脑因此可以更好地处理噪声。通过遮住你的半张脸,你不能欺骗大脑,但即使引入几个像素,人工智能也可以被欺骗,因为网络的不同部分被触发。

不像人类一样学习:这对于学习是如何发生的有着巨大的影响。今天的人工智能系统需要 1000 张猫的图像来识别一只猫。NI/ brain 没有。我们根据自己的知识进行推断。这意味着显著降低计算和能源。

在你童年时,父母什么时候教过你如何利用重力工作?从来没有。当你还是个婴儿的时候,你就在和它一起工作,并且在生命的早期就知道当你释放它们的时候,东西就会掉下来。NI 拥有像重力和其他物理知识的多层编码,我们可以无缝地并行连接稀疏矩阵的其他部分,从而在未知的场景中扩展我们的知识。

边缘案例弄巧成拙:这击中了边缘案例今天 AI 问题的核心。为了制造一辆坚固的自动驾驶汽车,它应该被训练成不会掉下悬崖。倪似乎与生俱来…我们看到重力神经元触发的悬崖,我们知道我们将会坠落。AI 需要训练。你不能把一辆车推下悬崖去训练。你永远不会有足够的数据点来训练。在这种情况下,人工智能在模拟中学习。边缘案例永远没有足够的数据,这就是为什么它们被称为边缘。这是人工智能中一个基本的自相矛盾的问题,而 NI 结构克服了这个问题。

新大脑皮层是一个复杂但可复制的结构:大脑中的 NI 结构很复杂,仍在研究中。但是在某些方面我们有着一致的看法。新皮层是大脑中与高级功能相关的部分。我们开始相信大脑的不同部分处理不同的感觉。但是越来越多的证据表明,这些不同区域的底层结构(柱子、连接等)是相似的。区别它们的是输入,而不是内在结构。用音频改变视觉区域的输入,它仍然会学习和工作。甚至每*方毫米皮层表面的神经元数量看起来也与相似。同样的组织是重复的。和 AI 很不一样。这能造出来吗?

大脑器官看起来很有希望:在实验室里,这已经在使用干细胞了。见下图的迷你大脑/ 类脑器官。

Pea-size brain organoids at 10 months old. Credit: Muotri Lab/UCTV Source: phys.org/

它们正在培养皿中生长。该组织类似于大脑,是一个低能耗的神经网络。它们自我组织成神经组织。科学家们已经取得了长足的进步,通过提供血管系统/血管的生长来反复创造它们并稳定它们以保持更长时间。它们还被培养成具有多种功能,如视网膜细胞(原始的眼睛)引领我们进入一个传感成为可能的时代。这些类器官像人脑一样产生脑电波。最*,一个人工智能系统未能区分 9 个月大的大脑器官和早产儿大脑的电模式。

生物计算即将到来:这些类器官组织将在数月内自我组织和发展。可以指导他们做特定的活动吗?一系列*行的活动表明答案是肯定的。最*加州大学戴维斯分校&哈佛大学的一个团队展示了一台运行 21 种不同程序的 DNA 计算机(例如:复制、排序、识别回文和 3 的倍数等)。

可持续的低能耗、自组织、类脑学习系统越来越有可能实现。

在分子编程/生物计算、干细胞和类器官、用于特定开发的基因编辑(CRISPR)以及从这些结构中推导神经计算模型方面的进步将需要人工智能生物。

激动人心。

创新的未来将由社区自下而上推动,而不是由政府或企业自上而下推动

原文:https://towardsdatascience.com/future-of-innovation-will-be-driven-bottom-up-by-communities-not-top-down-by-governments-or-273d3650f1ec?source=collection_archive---------23-----------------------

一群从未谋面、位于世界不同地区(不同大陆、不同时区)的爱好者能否走到一起,合作解决社会中的大问题?

这是一个引起我兴趣的问题,我想启动 Omdena 来看看这种自下而上的模式是否可行。

这半年发生的事情很神奇。来自 63 个国家的 400 多名爱好者不仅合作应对重大的社会挑战,如战胜尼泊尔的饥饿,索马里的冲突,巴西的森林火灾,印度的性骚扰,而且他们还能够建立非常复杂的人工智能模型,同时相互帮助。更有经验的开发人员开始分享他们的工作,并帮助不太有经验的开发人员,而新的开发人员开始生成数据。

尽管面临各种挑战,但所有发烧友都有一个共同点。他们都被极大地激励着,渴望构建一个现实世界的产品来解决现实世界的问题。

合作而不是竞争

这是一种新的创新模式。一种模式,在这种模式下,社区可以聚集在一起解决他们的问题,共享他们的数据,并构建解决方案。

在大数据和机器学习的世界里,数据是关键。这不是复杂的算法或更好的团队,而是拥有更好(和更多)数据的团队获胜。此外,由于在线课程的泛滥,教育,特别是人工智能和人工智能等新兴技术的教育变得容易获得。现在,对于世界上任何地方的任何人来说,从像 Udemy,Coursera 这样的网站开始学习是非常容易的。通过访问数据和开源代码,人们拥有了构建自己解决方案的所有工具。

对社区驱动的方法感兴趣的人如何开始构建他们的解决方案?以下是步骤:

  1. 建立一个由拥有共同愿景、动机和使命的高度积极的人组成的社区。社区应该拥有多样化的经验和技能。
  2. 把他们带到一个*台下,可以懈怠。
  3. 遵循协作工作的最佳实践、流程和工具。
  4. 定期举办活动,让社区成员展示他们的工作并分享知识。
  5. 写下他们正在做的工作,以保持动力。每个人都喜欢被认可。

管理社区

社区很难管理和维护。最好的策略是用一种有共同价值观和动机的语言说话。这是建立“部落”[1]的唯一方法:一群拥有共同意义和联系的人。

另一件重要的事情是有人能把社区粘在一起。Scott Adams 在他的书《如何在几乎所有事情上都失败的情况下仍然赢得巨大成功》中谈到了建立多样化的技能,这样整体就大于部分之和。

社区外的价值

由社区构建的解决方案几乎肯定会被采用。他们知道要解决什么问题,如何获取数据,甚至知道如何构建这些解决方案。他们需要的是支持、指导和鼓励。

一个社区创造授权,建立信任,提供数据访问,产生不同的意见,并刺激创新。

但是如果创造的模型产生了经济价值会怎么样呢?这是如何分配的,特别是当一个公司把它的项目外包给社区的时候?当公司正在使用经过训练的模型时,数据和代码保留在社区中。因此,如果有经济价值,从产出中获益对社区和公司都更有意义。

公司的利益是短期的。社区的利益是长远的。

这种利用社区的方式甚至可以更大。在观看一部关于一些暴虐政权的纪录片时,我意识到暴虐政权(或公司)的目标是控制人民。这是一种经典的自上而下的方法,一些精英告诉我们其余的人什么时候做什么。

社区驱动的方法正好相反。这不是关于控制,而是关于激发自由思想。这是推动真正创新的动力,也是我认为世界应该走向的地方,我想成为其中的一部分。

当我们接触到自己的感觉和需求时,我们人类就不再是好的奴隶和下属了——非暴力沟通:马歇尔·罗森博格的一种生活语言。

模糊逻辑及其如何治愈癌症

原文:https://towardsdatascience.com/fuzzy-logic-and-how-it-is-curing-cancer-dc6bcc961ded?source=collection_archive---------19-----------------------

简要介绍软计算、模糊逻辑以及这两者如何帮助我们治愈肿瘤!

什么是软计算?

它是一切不脆/不实的东西。一门不能给出 100%准确答案的科学,但更合适的是它不需要 100%明确的输入。一个简单的例子是一个根据照片预测一个人年龄的程序。它研究照片中的多种特征,如头发颜色、皮肤纹理、皱纹等。并估计他们的年龄。
输入:可能不是高分辨率的照片/侧面照片。
输出:一个大概接*这个人年龄的数字。
软计算基于模糊逻辑,后面会解释。

硬计算是传统的计算方法,你们大多数人可能已经很熟悉了。一个例子是将两个数相加的程序。明确的输入和绝对的答案。

Eva Volná写的《软计算简介》是一本很棒的免费书籍,可以让你在软计算和模糊逻辑方面有一个很好的开端。

以下是本书对软计算的定义 软计算是一组方法,旨在利用对不精确性、不确定性和部分真实性的容忍来实现易处理性、健壮性和低解决方案成本。它由三种计算范式组成,即模糊 计算、神经计算概率推理。软计算的角色模型是人脑。**

什么是模糊逻辑?

传统的方法是将一杯咖啡分成两类,冷的或热的。一个温暖的接*热的杯子会属于热的类别。在模糊世界中,这个暖杯对热杯的隶属度为 70%,对冷杯的隶属度为 30%。

sketch made using sketchboard

模糊逻辑是一种基于真实度而不是通常的真或假的计算方法。使得对于每个元素,它对于包含在问题中的每个集合都有一个隶属度

这种计算在我们的日常生活中非常有用。例如,一所学校正在为校队选拔篮球运动员,他们宣布需要身高 5 英尺 5 英寸以上的人。这会让一个 5 尺 4 的非常优秀的球员失去资格吗?还是他会被试镜因为其实差别不大?如果一个 5 英尺 3 英寸的人申请。他只比最后一个被录取的人矮一英寸。永远都是这样。这就是为什么更合适的应用程序会在身高字段中有分数,其中相对较矮的人会有较低的分数(属于高个子集的程度< 100%),而较高的人会得到满分(完全属于高个子集)。

seriousfacts.com

自然本身是不脆的,当你看到彩虹时,你会看到红色,然后是橙色。你盯着一个点,你可以发誓它是红色的,百分之百的红色。而且,你看到它变得越来越轻,直到它*稳地变成橙色。你说不出它到底是从哪一点停止变红,开始变成橙色的。它不是一个纯红色的笔画后面跟着一个纯橙色的笔画,相反,它是一个从 100%到 0%递减的红色百分比和从 0%到 100%递增的橙色百分比。

这和肿瘤有什么关系?

文献(以前/当前关于检测肿瘤的论文/研究)中有 3 个缺陷:

  • 没有考虑包含在肿瘤区域内的每个细胞中的癌症百分比。在大多数情况下,肿瘤由大量癌细胞组成,这些癌细胞在各个维度上逐渐消失,直到不再有癌细胞。
  • 假设肿瘤的形状是规则的几何形状(球形),其直径为 MRI 扫描中肿瘤的长度。因此,肿瘤体积的计算是错误的,因为肿瘤通常以不规则的形状存在。
  • 指定癌症级别以及治疗计划是基于依赖于肿瘤直径大小的清晰集合。意味着治疗中的剧烈改变可能基于阶段边界周围的轻微移动。

Photo by Damon Hall from Pexels

忽略癌变区域内癌症的不同强度(癌症分级)

在海滩上,你看不到海水以一条完美的直线结束。相反,海水的深度逐渐减少。从齐肩到齐膝,再到湿脚趾,然后是湿沙子,最后是完全干燥的沙子。对于肿瘤来说也是一样,当你检查核磁共振扫描时,你会看到一个癌块(水),癌细胞会逐渐消失,直到你到达完全健康的器官部分(沙子)。文学不能解释这一点。他们没有考虑到肿瘤固有的模糊性。一般来说,生物系统,尤其是癌性肿瘤,并不显示出清晰的边界。因此,为了精确描述肿瘤,必须考虑内在分级,以评估初始肿瘤结构和追踪治疗进展。一些细胞可能仅包含 40%癌组织的模糊部分将被认为是 100%的癌细胞。这高估了病人的情况,并可能导致不必要的沉重的愈合过程。

假设肿瘤是规则的球形,这种情况很少发生

癌症检测文献中的另一个大错误是,他们假设肿瘤是规则的球形,具有肿瘤本身中最长线的直径。这可能导致非常错误的尺寸,特别是在肿瘤形状不规则或者最长和最短尺寸之间的差异很大的情况下。通常基于最长直径的体积估计导致比实际情况大得多的体积大小。这种测量技术只能对完美或接*完美的球形病变精确。

主要基于肿瘤直径长度来定义癌症的明确阶段

source: wikimedia commons

癌症分期用于描述和排列癌症的严重程度。从阶段 0 到阶段 4。其中 IV 是最严重的。第四阶段意味着疾病已经扩散到其他器官。自从洛菲·扎德提出模糊集合论以来,人们就认识到了生物系统的模糊性,从那以后,生物现象的层次性得到了广泛的重视和应用。例如,如果一个阶段落在分别作为下限和上限的肿瘤直径 2 cm 和 4 cm 的值之间,那么值 1.99 和 4.01 呢?对于这样一个微小的偏离边界的情况,我们应该把整个治疗计划或药物设计从一个阶段转移到另一个阶段吗?如果我们不这样做,那么我们应该在什么指数值设置限制?这是一个典型的悖论的例子,模糊集合论就是为此而发明的。

我在这里写的很多东西,都是从这篇智能癌症分期的肿瘤体积模糊化论文中学到的。

尺度模糊匹配

原文:https://towardsdatascience.com/fuzzy-matching-at-scale-84f2bfd0c536?source=collection_archive---------2-----------------------

从 3.7 小时到 0.2 秒。如何以一种甚至可以扩展到最大数据集的方式执行智能字符串匹配。

Same but different. Fuzzy matching of data is an essential first-step for a huge range of data science workflows.

# # # 2020 年 12 月更新:一种更快、更简单的模糊匹配方法现已包含在本文末尾,并提供了在任何数据集上实现该方法的完整代码###

D 现实世界中的 ata 是杂乱无章的。处理乱七八糟的数据集是痛苦的,耗费了大量时间,而这些时间本可以用来分析数据本身。

本文重点关注“模糊”匹配,以及它如何通过以下方式帮助自动化大量数据科学工作流中的重大挑战:

  1. 重复数据删除。对齐数据集中相似的类别或实体(例如,我们可能需要将“D J Trump”、“D. Trump”和“Donald Trump”组合成同一个实体)。
  2. 记录联动。连接特定实体上的数据集(例如,将‘D . J . Trump’的记录连接到他的维基百科页面的 URL)。

通过使用从自然语言处理领域借用的新方法,我们可以在大型数据集上执行这两项任务。

大数据的模糊匹配问题

有许多算法可以提供模糊匹配(参见这里如何用 Python 实现),但是当用于超过几千条记录的适度数据集时,它们很快就失效了。

这样做的原因是,他们将每个记录与数据集中的所有其他记录进行比较。在计算机科学中,这被称为二次时间,在处理较大的数据集时会很快形成障碍:

Number of records on the left against the number of operations required for an algorithm that works in quadratic time. A relativity small data set of 10k records would require 100m operations.

更糟糕的是,大多数字符串匹配函数还依赖于被比较的两个字符串的长度,因此在比较长文本时速度会更慢。

众所周知的 NLP 算法如何帮助解决这个问题

这个问题的解决方案来自一个众所周知的 NLP 算法。词频,逆文档频率(或 tf-idf)从 1972 年开始用于语言问题。

这是一个简单的算法,它将文本分成“块”(或 ngrams),对给定样本的每个块的出现次数进行计数,然后根据该块在数据集的所有样本中的稀有程度对其进行加权。这意味着有用的单词从文本中出现的更常见单词的“噪音”中过滤出来。

虽然这些组块通常应用于整个单词,但是没有理由为什么相同的技术不能应用于单词中的字符集。例如,我们可以将每个单词分成 3 个字符的 ngrams,对于单词“Department ”,将输出:

' De', 'Dep', 'epa', 'par', 'art', 'rtm', 'tme', 'men', 'ent', 'nt '

然后,我们可以在代表我们的数据集的项目矩阵中比较这些块,以寻找接*的匹配。这种寻找接*匹配的方法应该非常有效,并且通过其对数据中不太常见的字符组给予更大重视的能力,还可以产生高质量的匹配。让我们来测试一下吧!

真实世界的例子

我们将用来测试该算法的例子是一组在 Contracts Finder 上发布合同的英国公共组织。这些组织的名称非常混乱,看起来好像是通过自由文本字段输入系统的。

A sample of the data set — there are 3,651 different buying organisations in total

智能重复数据删除

我们将首先探讨如何对相*的匹配项进行重复数据删除。使用 Python 的 Scikit-Learn 库可以使这个过程变得轻松:

  1. 创建一个函数将字符串分割成字符。
  2. 使用 Scikit-Learn 从这些字符创建一个 tf-idf 矩阵。
  3. 使用余弦相似度来显示总体中最接*的匹配。

ngram 功能

below 函数既用作文本数据的清理函数,也用作将文本拆分成 ngrams 的方法。代码中添加了注释以显示每一行的用途:

The function used to turn a string into a series of ngrams for matching on

应用函数并创建 tf-idf 矩阵

Scikit 中 tf-idf 实现的伟大之处在于它允许向其中添加自定义函数。因此,我们可以添加上面创建的函数,只用几行代码就可以构建矩阵:

from sklearn.feature_extraction.text import TfidfVectorizerorg_names = names['buyer'].unique()
vectorizer = TfidfVectorizer(min_df=1, analyzer=ngrams)
tf_idf_matrix = vectorizer.fit_transform(org_names)

通过余弦相似度找到接*的匹配

您可以在这里使用 Scikit 中的余弦相似性函数,但是这并不是查找接*匹配的最有效的方法,因为它会返回每个样本的数据集中每个项目的接*度分数。相反,我们将使用一个更快的实现,可以在这里找到:

import numpy as np
from scipy.sparse import csr_matrix
!pip install sparse_dot_topn 
import sparse_dot_topn.sparse_dot_topn as ctdef awesome_cossim_top(A, B, ntop, lower_bound=0):
    # force A and B as a CSR matrix.
    # If they have already been CSR, there is no overhead
    A = A.tocsr()
    B = B.tocsr()
    M, _ = A.shape
    _, N = B.shape

    idx_dtype = np.int32

    nnz_max = M*ntop

    indptr = np.zeros(M+1, dtype=idx_dtype)
    indices = np.zeros(nnz_max, dtype=idx_dtype)
    data = np.zeros(nnz_max, dtype=A.dtype)ct.sparse_dot_topn(
        M, N, np.asarray(A.indptr, dtype=idx_dtype),
        np.asarray(A.indices, dtype=idx_dtype),
        A.data,
        np.asarray(B.indptr, dtype=idx_dtype),
        np.asarray(B.indices, dtype=idx_dtype),
        B.data,
        ntop,
        lower_bound,
        indptr, indices, data)return csr_matrix((data,indices,indptr),shape=(M,N))

将所有这些放在一起,我们得到以下结果:

Witchcraft! The algorithm is eerily good at identifying duplicate records.

非常令人印象深刻,但它有多快?让我们比较一下使用“fuzzywuzzy”库计算*似匹配的更传统的方法:

!pip install fuzzywuzzy
from fuzzywuzzy import fuzz
from fuzzywuzzy import processt1 = time.time()
print(process.extractOne('Ministry of Justice', org_names)) #org names is our list of organisation names
t = time.time()-t1
print("SELFTIMED:", t)
print("Estimated hours to complete for full dataset:", (t*len(org_names))/60/60)**Outputs:**
SELFTIMED: 3.7s 
Estimated hrs to complete for full dataset: 3.78hrs

使用传统方法的基线时间大约是 3.7 小时。我们的算法用了多长时间来发挥它的魔力?

import time
t1 = time.time()
matches = awesome_cossim_top(tf_idf_matrix, tf_idf_matrix.transpose(), 10, 0.85)
t = time.time()-t1
print("SELFTIMED:", t)**Outputs:
**  SELFTIMED: 0.19s

哇——我们已经将预计时间从 3.7 小时减少到大约五分之一秒(大约 66,000 倍的速度提升!)

记录链接和不同的方法

如果我们想使用这种技术来匹配另一个数据源,那么我们可以回收大部分代码。在下面的部分,我们将看到这是如何实现的,并使用 K 最*邻算法作为一种替代的接*度测量。

我们想要加入的数据集是由英国国家统计局(ONS)创建的一组“干净”的组织名称:

The clean data set we would like to join against.

如下面的代码所示,这种方法的唯一区别是使用 tdif 矩阵来转换杂乱的数据集,该矩阵是在干净的数据集上学习的。

“getNearestN”然后使用 Scikit 的 K 最*邻实现来查找数据集中最接*的匹配:

from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import TfidfVectorizer
import reclean_org_names = pd.read_excel('Gov Orgs ONS.xlsx')
clean_org_names = clean_org_names.iloc[:, 0:6]org_name_clean = clean_org_names['Institutions'].unique()print('Vecorizing the data - this could take a few minutes for large datasets...')
vectorizer = TfidfVectorizer(min_df=1, analyzer=ngrams, lowercase=False)
tfidf = vectorizer.fit_transform(org_name_clean)
print('Vecorizing completed...')from sklearn.neighbors import NearestNeighbors
nbrs = NearestNeighbors(n_neighbors=1, n_jobs=-1).fit(tfidf)org_column = 'buyer' #column to match against in the messy data
unique_org = set(names[org_column].values) # set used for increased performance###matching query:
def getNearestN(query):
  queryTFIDF_ = vectorizer.transform(query)
  distances, indices = nbrs.kneighbors(queryTFIDF_)
  return distances, indicesimport time
t1 = time.time()
print('getting nearest n...')
distances, indices = getNearestN(unique_org)
t = time.time()-t1
print("COMPLETED IN:", t)unique_org = list(unique_org) #need to convert back to a list
print('finding matches...')
matches = []
for i,j in enumerate(indices):
  temp = [round(distances[i][0],2), clean_org_names.values[j][0][0],unique_org[i]]
  matches.append(temp)print('Building data frame...')  
matches = pd.DataFrame(matches, columns=['Match confidence (lower is better)','Matched name','Origional name'])
print('Done')

这会产生以下结果:

Not all items exist across the data sets. Thankfully the closeness score can be used to apply a threshold to what counts as a positive match.

从这个例子中可以看出,并不是所有的项目都出现在两个数据集中,但是 K 个最*邻仍然可以找到最接*的匹配。因此,我们需要对接*度分数应用一个阈值来确定什么算匹配。

使用这种方法,将 3,651 个实体与我们的干净数据集(包含 3,000 个实体)匹配不到一秒钟。

2020 年 12 月更新,这是一种使用 NMSLIB 的更快、更可扩展的新方法

虽然我们在本帖中构建了自己的函数来寻找向量间的*似匹配,但还有许多库存在,它们的唯一目的是加速这一过程。

不幸的是,大部分这些要求向量是密集的,并且不能处理我们在这篇文章中创建的大型稀疏(大部分是空的)矩阵。幸运的是,有一个库可以很好地处理稀疏矩阵;NMSLIB。我已经在这里更详细地写了这个库,但是本质上,NMSLIB 可以在一个矩阵上创建一个索引,并在给定的输入上执行极快的查询。在任何数据集上实现这一点的完整、有文档记录的代码可以在下面找到:

[## 模糊 _ 匹配 _ 更新. ipynb

合作笔记本

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

总之,在处理大量记录时,tf-idf 是一种高效、高性能的数据清理、重复数据删除和匹配方法。

代码,参考资料及进一步阅读:

请参见下面的 colab 文档,查看这篇文章的完整代码:

[## 快速匹配

快速模糊匹配

colab.research.google.com](https://colab.research.google.com/drive/1qhBwDRitrgapNhyaHGxCW8uKK5SWJblW)

这篇文章的灵感来自范登博客上的以下帖子:

[## Python 中的超快速字符串匹配

传统的字符串匹配方法,如 Jaro-Winkler 或 Levenshtein 距离度量,对于…

bergvca.github.io](https://bergvca.github.io/2017/10/14/super-fast-string-matching.html)

关于 tf-idf 的更多信息可以在下面的文章中找到

[## 如何在 Python 中使用 TF-IDF 处理文本数据

计算机擅长处理数字,但不太擅长处理文本数据。最广泛使用的处理技术之一…

medium.com](https://medium.com/free-code-camp/how-to-process-textual-data-using-tf-idf-in-python-cd2bbc0a94a3)

基于 Levenshtein 和 PostgreSQL 的模糊匹配

原文:https://towardsdatascience.com/fuzzy-matching-with-levenshtein-and-postgresql-ed66cad01c03?source=collection_archive---------8-----------------------

构建容错搜索引擎

用户体验是多种因素综合的结果:UI 设计、响应时间、对用户错误的容忍度等。这篇文章的范围属于第三类。更具体地说,我将解释如何使用 PostgreSQL 和 Levenshtein 的距离算法来处理搜索表单中的用户错误。例如,我们可能在我们的站点中查找一个名为“Markus”的用户,尽管我们可能以“Marcus”的名称搜索他(这两个名称都存在,并且在不同的语言中是等价的)。

让我们从熟悉 Levenshtein 的距离算法开始。

Levenshtein 距离算法

Levenshtein 的距离(为了简洁起见,我们从现在开始称之为 LD)旨在计算两个字符串之间的不相似性(因此,值越高,它们越不相似)。此度量表示需要应用于其中一个字符串以使其等于另一个字符串的操作数量。这些操作包括:插入字符、删除字符或替换字符。值得一提的是,每个操作都有一个相关的成本,尽管通常将所有操作的成本都设置为 1。

你很少需要实现 LD 算法,因为它已经存在于许多主流编程语言的库中。然而,理解它是如何工作的是值得的。我们将通过一个示例来确定“Marcus”和“Markus”之间的 LD,将所有操作的等价成本设置为 1:

  1. 我们创建一个 m×n 维的矩阵 D,其中 m 和 n 代表我们的两个字符串的长度(向前称为 A 和 B)。
  2. 我们从上到下从左到右迭代矩阵,计算相应子串之间的 LD。
  3. 我们计算增加的成本(ac),如果 A[i]等于 B[j]则为 0,否则为 1。
  4. 我们执行以下操作:

D[i,j] = min(D[i-1,j] + 1,D[i,j-1] + 1,D[i-1,j-1] + ac)

这意味着单元(I,j)具有由下式中的最小值确定的 LD:

  • 正上方的单元格加 1(由于插入操作)。
  • 左边的单元格加 1(由于插入操作)。
  • 左上方的单元格加上 ac(由于替换操作)。

以下矩阵代表了这一过程的最终结果:

LD matrix of “Marcus” VS “Markus”

上面的矩阵不仅提供了完整字符串之间的 LD,还提供了子字符串任意组合之间的 LD。完整字符串之间的 LD 可以在位置(m,n)找到。在这种情况下,我们可以看到“马库斯”和“马库斯”的 LD 为 1(红色),这是由“k”替换“c”造成的。

在 PostgreSQL 中使用 Levenshtein 距离

现在你已经了解了算法,是时候进入实用部分了。使用 PostgreSQL 应用 LD 算法非常简单,这都要归功于 fuzzystrmatch 扩展。这个扩展为模糊字符串匹配提供了不同的算法。可用的选项有 LD 算法和一组语音函数。请注意,这些语音函数(Soundex、Metaphone 和 Double Metaphone)对于非英语字符串可能无法发挥最佳性能。因此,我认为 LD 是国际申请中最可靠的选择。

不过,让我们继续将这个扩展添加到我们的 PostgreSQL 数据库中:

CREATE EXTENSION fuzzystrmatch;

此时,计算 LD 就像运行以下查询一样简单:

SELECT levenshtein(str1, str2);

例如:

SELECT levenshtein('Marcus', 'Markus');

因此,如果您有一个用户表,并且想要查找与用户输入具有相似名称的所有用户(例如,设置最大 LD 为 1),您的查询可能如下所示:

SELECT name FROM user WHERE levenshtein('Marcus', name) <= 1;

在这种情况下,“Marcus”代表用户输入。在这个查询中,我们将搜索名为 Marcus 或者名称的 LD 为 1 的用户(例如,“Markus”)。

请注意,fuzzystrmatch 提供了另一个有趣的函数,在这种情况下会更有效一些:levenshtein_less_equal。该函数允许您定义一个最大距离阈值,超过该阈值后 PostgreSQL 将停止计算。换句话说,如果我们将最大阈值设置为 1,并且我们的字符串对的 ld 为 6,则 fuzzystrmatch 将在达到 LD 为 2 后停止计算,因为无论如何,我们对这样的字符串对的 LD 不感兴趣,从而节省一些计算资源(并产生 LD 为 2)。最后,还值得注意的是,这两个函数都有一个版本,允许您定义每个操作(插入、删除和替换)的成本。

FuzzyWuzzy:如何在 Python 上测量字符串距离

原文:https://towardsdatascience.com/fuzzywuzzy-how-to-measure-string-distance-on-python-4e8852d7c18f?source=collection_archive---------14-----------------------

Some fuzzy plant leaves. Source: Pixabay.

Python 的 FuzzyWuzzy 库用于测量两个字符串之间的相似性。以下是你也可以开始使用它的方法。

有时候,我们需要看两个字符串是否相同。当将输入的密码与你的登录数据库中存储的密码进行比较时,“相似性”是不够的。

然而,其他时候,事情会变得有点… 模糊

如果我的顾客的名字是艾伯特·汤普森,但是他用一张名为艾伯特·g·汤普森的信用卡付款,我应该报警举报欺诈吗?《魔戒 2:双塔》和《魔戒 2:双塔》是否应该被一个网站当做两部完全独立的书?奥地利和澳大利亚真的是两个不同的国家吗?

好吧,我可能被最后一个问题冲昏了头脑,但是你明白了。

字符串距离度量

我们想要的是一个测量两个字符串有多相似的函数,但是对小的变化是健壮的。这个问题听起来很普通:科学家们已经想出了很长时间的解决方案。

雅克卡距离:第一种方法

最直观的一个就是 Jaccard 距离。它可以推广到任意两个集合的距离度量。它通过以下公式进行测量:

也就是说,有多少个元素在任一集合上,但不被两者共享,除以不同元素的总数。

例如,给定字符串“Albert”和“Alberto”,它将报告 85.7%的相似性,因为它们共享总共 7 个字母中的 6 个。

然而,这不是一个专门为字符串定制的措施。

它将在许多用例中失败,因为它没有真正考虑排序。例如,两个变位词,如“铁路安全”和“童话”,总是 100%匹配,即使这些字符串完全不同。

莱文斯坦距离

俄罗斯科学家 Vladimir Levenshtein 在 60 年代发明了这种方法,这种方法更加直观:它计算需要多少次替换,给定一个字符串 u ,将其转换为 v

对于这种方法,替代被定义为:

  • 擦除字符。
  • 添加一个。
  • 用一个字符替换另一个字符。

需要对 u 进行的这些操作的最小数量,以便将其转换为 v,对应于这两个串之间的 Levenshtein 距离。

它可以通过以下公式递归获得:

其中 ij 是我们将要比较的子串的最后一个字符的索引。如果这些字符不同,最后一个表达式中的第二项等于 1,如果相同,则等于 0。

这是 Python 的 FuzzyWuzzy 库使用的度量。

在 Python 中使用 FuzzyWuzzy

要获得两个字符串之间的相似率,我们要做的就是:

from fuzzywuzzy import fuzzsimilarity = fuzz.ratio("hello","world")

你可能注意到了我说的比率。ratio 方法将总是返回一个介于 0 和 100 之间的数字(是的,我更希望它介于 0 和 1 之间,或者称之为百分比,但是各有各的)。

可以证明,Levenshtein 距离至多是最长字符串的长度:用较长字符串的第一部分替换较短字符串中的所有字符,然后添加其余的字符。

这就是我们如何将距离归一化以返回一个比率,以便在给定不同大小的输入的情况下,该数字不会大幅波动。

这解决了前面提到的一些问题:

fuzz.ratio("Albert Thompson", "Albert G. Thompson") #91%fuzz.ratio("The Lord of the Rings II: The Two Towers",
           "The Lord of the Rings 2: the 2 Towers") #88%

即使这可能会带来一些新的问题:

#88% for two different countries
fuzz.ratio("Austria","Australia")#57% but it's the same country
fuzz.ratio("Czechia","Czech Republic")

其他模糊不清的方法

Python 的 FuzzyWuzzy 库不仅为我们提供了普通的 Levenshtein 距离,还提供了一些我们可以利用的其他方法。

部分比率

partial_ratio 方法用较短字符串的长度计算较长字符串的所有子字符串的 FuzzyWuzzy 比率,然后返回最高匹配。

举个例子,

fuzz.partial_ratio("abc","a") == 
      min([fuzz.ratio( char, "a") for char in "abc"])

这有一些有趣的影响:

fuzz.partial_ratio("Thomas and His Friends", "Thomas") #100%fuzz.partial_ratio("Batman vs Superman", "Batman") #100%

实际上,partial_ratio 方法可以是对【T2 包含】字符串方法的模糊替换,就像常规比率可以替换【T4 等于】方法一样。

但是,对于相似但单词出现顺序不同的字符串,它将失败。即使是轻微的顺序变化也会破坏它。

#72% with basically the same idea
fuzz.partial_ratio("Peanut Butter and Jelly", 
                   "Jelly and Peanut Butter")

#86% with a random (carefully selected) string
fuzz.partial_ratio("Peanut Butter and Jelly", "Otter and Hell")

令牌 _ 排序 _ 比率

Token Sort Ratio 将两个字符串分成单词,然后在对它们调用常规 Ratio 之前,再次按字母数字顺序将它们连接起来。

这意味着:

fuzz.partial_ratio("Batman vs Superman", "Superman vs Batman") #100%fuzz.partial_ratio("a b c", "c b a") #100%

令牌 _ 集合 _ 比率

记号集比率将每个字符串分成单词,将两个列表都变成集合(丢弃重复的单词),然后在进行比率之前对它们进行排序。

这样,我们不仅排除了共享单词,还考虑到了重复。

fuzz.token_set_ratio("fun","fun fun fun") #100%fuzz.token_set_ratio("Lord the Rings of", "Lord of the Rings") #100%

结论

Python 的 FuzzyWuzzy 库是一个非常有用的工具。无论是对于客户的姓名匹配,还是充当穷人的单词嵌入,都可以省去你很多麻烦,或者对你的机器学习模型的特征工程有帮助。

然而,由于它需要预处理(比如将两个字符串都转换成小写),并且不考虑同义词,所以对于可能需要实际 NLP 或聚类方法的情况,它可能不是最佳解决方案。

我希望这篇文章对你有所帮助,如果你在工作中发现 FuzzyWuzzy 的其他用途,请告诉我!

关注我的TwitterMedium了解更多 Python 教程、技巧和窍门。

你可以在我的 个人网站 中看到我正在做的事情以及我最*的文章和笔记。

哥德尔不完全性定理及其对构建强人工智能的启示

原文:https://towardsdatascience.com/gödels-incompleteness-theorems-and-the-implications-to-building-strong-ai-1020506f6234?source=collection_archive---------14-----------------------

数据科学之道

关于制造智能机器,数学逻辑最深刻的结果告诉了我们什么

数据科学之道 专栏探讨了几个世纪以来哲学家们是如何攻克机器学习和数据科学的关键问题的。

Gödel’s proofs suggest strong AI may not be possible with modern computing.

定理的要旨

  • 在现代逻辑中,可以表达算术语句,例如,“给定任意数 x 和 y,x + y = y + x”。
  • 公理是被认为是正确的陈述。例如,概率论的一个公理是,这个叫做“概率”的东西是一个介于 0 和 1 之间的实数。公理作为进一步推理的前提,例如“如果 0 ≤ p ≤ 1,那么……”。
  • 几个公理放在一起形成一个公理系统(如概率公理),从中可以证明许多算术真理(如贝叶斯规则)。
  • 哥德尔提出的问题是,一个人是否可以用一个公理系统来证明所有的算术真理,而不会与不一致——其中不一致意味着系统产生矛盾。
  • 哥德尔证明了对于任何一致的公理系统,都有那个系统无法证明的真理。
  • 这表明数学家所能知道的是有界限的。

对 AI 的影响

AI 研究的目标之一是实现“强人工智能”,即人类级别的通用 AI。目前,我们在图灵机中构建 AI 作为算法,图灵机是一致的公理系统,因此服从定理。

罗杰·彭罗斯和 J.R. Lucas 认为人类意识超越图灵机是因为人类的头脑通过内省可以认识到自己的不一致,这在哥德尔定理下对图灵机来说是不可能的。他们认为这使得图灵机不可能复制人类思维的特征,例如数学洞察力。

了解更多信息

  • [哥德尔的不完全性定理](http://Gödel's incompleteness theorems) —斯坦福哲学百科全书
  • 彭罗斯论物理学与意识 —维基百科

因果推理中的 g-计算

原文:https://towardsdatascience.com/g-computation-in-causal-inference-774099da3631?source=collection_archive---------6-----------------------

因果推理的反事实方法

g-计算算法最早由 Robins 于 1986 年[1]引入,用于在存在受暴露影响的时变混杂因素的情况下估计时变暴露的因果效应,在这种情况下,传统的基于回归的方法将失效。

G-计算或 G-公式属于 G-方法家族[2],它还包括逆概率加权边际结构模型和结构嵌套模型的 G 估计。它们在比标准回归方法更少限制的识别条件下,提供*均潜在结果的对比(如差异、比率)的一致估计。

在这篇文章中,我将详细解释 G-计算在因果分析中的工作原理。

例子

想一个例子——治疗艾滋病毒,衡量治疗效果的方法是检测 CD4 计数,你血液中的 CD4 计数越多,治疗效果越好。我们将结果(CD4 计数)命名为 Y 。我们有两组病人, A =1 表示接受特定治疗, A =0 表示不接受特定治疗。我们在任何治疗前对患者进行测试作为基线,同时还会进行后续测试a1。我们还有一个协变量Z——升高的 HIV 病毒载量,它在基线时是恒定的,在第二次治疗前的随访中测量一次(Z_1)。除此之外,我们还有一个无法测量的共同原因(U)HIV 病毒载量(Z)和 CD4(Y)。

为了测量差异,我们通常使用*均因果效应 E(Y1-Y0),它是一个边际效应,因为它是总体中所有个体水*效应的*均值。

我们如何识别 CD4 计数的变化( Y )是由治疗( A=1 )引起的而不是其他原因?

假设

Causal diagram representing the relation between a treatment at time 0 (A0), HIV viral load just prior to the second round of treatment (Z1), the treatment status at time 1 (A1), the CD4 count measured at the end of follow-up (Y), and an unmeasured common cause (U) of HIV viral load and CD4.

我们使用*均效应来衡量差异,然而,我们无法获得所有信息,因为有些人接受了治疗,有些人没有。我们没有进行倾向评分匹配,所以我们不能保证个人的所有其他条件都是相同的。我们需要证明我们用来测量的*均效应会在整个人口中观察到。这是通过以下假设实现的:

假设 1:反事实一致性

一致性规则指出,一个人在碰巧实现的假设条件下的潜在结果正是该人经历的结果。这允许我们写出:P(Yx = y|Z = z,X = x) = P(Y = y|Z = z,X = x),并确定我们的*均因果效应

假设 2:互换性

可交换性意味着暴露下的潜在结果与实际暴露 A0 或 a1 无关。这是说“数据来自随机对照试验”的假设。如果这个假设成立,你会在 a=0 的组中观察到 Ya=0 的分布的随机子集,在 a=1 的组中观察到 Ya=1 的分布的随机子集。

假设 3:积极性

阳性是假设任何个体都有接受治疗变量所有值的正概率。这种假设是有用的,这样影响就会存在。当在所有混杂因素中存在暴露和未暴露的个体时,该假设将被满足。

在这些假设下,g 方法可以用来估计观测数据的反事实量

G 计算的步骤:

为了评估治疗对 CD4 计数的不同影响,我们实施了以下步骤:

3 steps for G-computation

这个想法是使用反事实(如果接受治疗的患者没有接受治疗,而没有接受治疗的患者接受了治疗,结果会是什么)来创建*均效果的估计,以适应我们的差异测量模型。

感谢阅读我的帖子!在后面的帖子中,我将解释另一种 G 方法,即 IPWC,并解释 TMLE,G 公式和 IPWC 是如何不同和相关的。

直到下一次!

[1] Robins J .在持续暴露期死亡率研究中进行因果推断的新方法——应用于控制健康工人幸存者效应。数学模型。1986;7(9–12):1393–1512.

[2] Robins J 和 Hernan M .时变暴露的因果效应估计。在:菲茨莫里斯 G,大卫 M,韦贝克 G,和莫伦伯格 G(编辑。)纵向数据分析的进展。佛罗里达州博卡拉顿:查普曼&霍尔。2009;553–599.

深入了解熊猫系列

原文:https://towardsdatascience.com/gaining-a-solid-understanding-of-pandas-series-893fb8f785aa?source=collection_archive---------15-----------------------

Photo by Stone Wang on Unsplash

议程

Pandas 的两个主要数据结构是序列和数据帧。这篇文章试图对熊猫系列有一个正确的理解。

数据帧的基础是一个系列。DataFrame 的 docstring 将 DataFrame 定义为:

Can be thought of as a dict-like
container for Series objects

dataframe 上的许多操作返回系列实例。因此,我们必须对级数有一个扎实的了解。

什么是系列

熊猫有两种概念。可以把它想象成一列表格数据。它也可以被想象成一行表格数据。

让我们假设有一个名为accounting的数据库表,它存储不同年份的revenueexpenses

 year   revenue   expense
 2017   1000      800
 2018   1200      900
 2019   1500      1100

所有收入的集合是一个Series,即[1000, 1200, 1500]是一个数列。系列是不同对象/行/实例的相同属性的集合。

Series也可以被认为是表格中的一行,也就是说[2017, 1000, 800]也是一个系列。在这种情况下,系列是单个对象的不同属性的集合。

创建系列

在现实世界中,您很少会创建一个系列。您可能会获得一个 csv 或其他数据源,您可以从中读取数据。pandas 有从这些数据源读取数据的工具。

读取的数据将是熊猫数据帧。您将从数据帧中提取一些序列,并对这些序列进行操作。

这是一个简单的任务。现在,让我们明确地创建一个系列

可以使用pandas.Series创建一个Series

我们在 ipython shell 上试试吧。

In [2]: revenue = pd.Series([1000, 1200, 1500, 800, 900], index=['2014', '2015', '2016', '2017', '2018'])

index关键字参数将标签分配给系列的不同值。这些标签在从系列中检索数据时很方便。

索引系列

让我们从这个系列中获取信息。让我们检索 2016 年的收入。

In [8]: revenue['2016']
Out[8]: 1500

系列也有两种索引方法,分别是.loc.iloc

.loc执行基于标签的索引。

In [9]: revenue.loc['2016']
Out[9]: 1500

.iloc执行基于整数的索引。2016 是第三个条目,即索引 2。

In [10]: revenue.iloc[2]
Out[10]: 1500

revenue.iloc['2016']将失败,并出现KeyErrorrevenue.loc[2]将失败,并出现IndexError

切片系列

我们可以使用与列表切片相同的语法对序列进行切片。我们想从 2014 年到 2016 年分一杯羹。

In [17]: revenue['2014': '2016']
Out[17]:
2014    1000
2015    1200
2016    1500
dtype: int64

注意,返回的数据结构也是一个pandas.Series

In [18]: type(revenue['2014': '2016'])
Out[18]: pandas.core.series.Series

如果要使用整数位置进行切片,就必须使用.iloc。整数位置只能与iloc一起使用。它不能与loc一起使用。

In [20]: revenue.iloc[0:3]
Out[20]:
2014    1000
2015    1200
2016    1500
dtype: int64

返回的对象又是一个序列。

如果我们需要多年的信息,我们必须将一个列表传递给索引语法。让我们看看 2014 年和 2017 年的收入。

In [23]: revenue[['2014', '2017']]
Out[23]:
2014    1000
2017     800
dtype: int64

我们也可以使用revenue.loc[['2014', '2017']]

2014 年是该系列的第一个条目,2017 年是第四个条目。我们也可以使用revenue.iloc[[0, 3]]

In [25]: revenue.iloc[[0, 3]]
Out[25]:
2014    1000
2017     800
dtype: int64

您应该已经注意到,对一个系列进行切片总是会返回另一个系列。

获取系列的标签

我们想要一份我们有收入的所有年份的清单。

In [93]: revenue.index
Out[93]: Index(['2014', '2015', '2016', '2017', '2018'], dtype='object')In [94]: list(revenue.index)
Out[94]: ['2014', '2015', '2016', '2017', '2018']

正如我们所见,Series对象有一个名为index的属性,它返回标签。

过滤系列

我们希望获得收入大于 1000 的所有年份。

In [50]: revenue[revenue > 1000]
Out[50]:
2015    1200
2016    1500
dtype: int64

我们将在下一节了解它是如何工作的。

使用布尔列表进行过滤

布尔列表是支持对序列进行过滤的底层机制。

我们希望获得 2014 年和 2017 年的收入。2014 定位 0,2017 定位 3。

我们必须创建一个与收入相同长度的列表,并将第 0 和第 3 个元素设置为真。

In [75]: l = [True, False, False, True, False] # Set 0th and 3rd element TrueIn [76]: revenue[l]
Out[76]:
2014    1000
2017     800
dtype: int64

我们向索引语法传递了一个布尔值列表,它过滤了这个系列,返回另一个系列。返回的序列只包含布尔列表中相应元素为真的值。

代替列表,我们可以用布尔值创建一个长度为 5 的序列,并使用带有revenue的布尔序列。

In [78]: boolean_series = pd.Series([True, False, False, True, False], index=['2014', '2015', '2016', '2017', '2018'])In [79]: revenue[boolean_series]
Out[79]:
2014    1000
2017     800
dtype: int64

因为我们想对收入使用布尔序列,所以我们必须确保两个序列的索引匹配。

让我们看看revenue > 1000给了我们什么:

In [80]: revenue > 1000
Out[80]:
2014    False
2015     True
2016     True
2017    False
2018    False
dtype: bool

它返回给我们一个序列,类似于我们显式创建的 boolean_series。

既然是一个系列,我们可以直接用这个和revenuerevenue[revenue > 1000]。这正是我们在上一节过滤中所做的。

更多过滤

我们希望获得收入大于 1000 但小于 1300 的所有年份。

In [68]: revenue[(revenue > 1000) & (revenue < 1300)]
Out[68]:
2015    1200
dtype: int64

级数的算术运算

假设我们意识到每年的收入减少了 100 英镑。我们想每年增加 100 的收入来弥补。

In [81]: revenue + 100
Out[81]:
2014    1100
2015    1300
2016    1600
2017     900
2018    1000
dtype: int64

请注意序列的每个值是如何增加 100 的。

对序列的任何算术运算都应用于序列的所有值。

按系列订购

我们希望按升序对收入进行排序。

In [87]: revenue.sort_values()
Out[87]:
2017     800
2018     900
2014    1000
2015    1200
2016    1500
dtype: int64

我们想按降序排列收入。

In [88]: revenue.sort_values(ascending=False)
Out[88]:
2016    1500
2015    1200
2014    1000
2018     900
2017     800
dtype: int64

我们想知道哪一年的收入最高。

In [92]: revenue.sort_values(ascending=False).index[0]
Out[92]: '2016'

revenue.sort(ascending=False)返回一个有序序列。由于一个系列有属性index,我们可以使用它并获得年度最大收入的标签。

不过,有一种更好的方法可以实现这一点。我们将在下一节看到idxmax()

序列上的聚合

让我们找出这些年的总收入。

In [96]: revenue.sum()
Out[96]: 5400

系列有工具可以很容易地找到*均值,最大值和最小值。

In [102]: revenue.mean()
Out[102]: 1080.0In [103]: revenue.max()
Out[103]: 1500In [104]: revenue.min()
Out[104]: 800

我们想知道哪一年的收入最高。

In [106]: revenue.idxmax()
Out[106]: '2016'

序列的分组和聚合

让我们假设某一年的收入可能有多行。

In [2]: revenue_with_multiple_entries = pd.Series([1000, 1200, 1500, 800, 900, 500], index=['2014', '2015', '2016', '2017', '2018', '2017'])In [3]: print(revenue_with_multiple_entries)
2014    1000
2015    1200
2016    1500
2017     800
2018     900
2017     500
dtype: int64

我们有多行 2017 年收入。我们想知道不同年份的总收入。

我们可以通过做一个groupby然后做一个sum来实现它。

In [4]: revenue_with_multiple_entries.groupby(revenue_with_multiple_entries.index).sum()
Out[4]:
2014    1000
2015    1200
2016    1500
2017    1300
2018     900
dtype: int64

数列的最常见值

让我们创建一系列班级学生的名字。

In [6]: names = pd.Series(['steve jobs', 'bill gates', 'mark twain', 'charles darwin', 'charles dickens', 'mark zuckerberg', 'charles darwin'])In [7]: print(names)
0         steve jobs
1         bill gates
2         mark twain
3     charles darwin
4    charles dickens
5    mark zuckerberg
6     charles darwin

你应该已经注意到了,我们没有给这个系列提供明确的index。所以会自动分配一个整数标签。

我们来找一个最常见的名字。

In [10]: names.value_counts()
Out[10]:
charles darwin     2
bill gates         1
mark zuckerberg    1
mark twain         1
steve jobs         1
charles dickens    1

系列上的字符串操作

让我们找出所有以mark开头的名字。

In [16]: names[names.str.startswith('mark')]
Out[16]:
2         mark twain
5    mark zuckerberg
dtype: object

names.str.startswith('mark')返回一个布尔数组,我们将该数组传递给索引语法以过滤序列。

熊猫系列有str属性,允许执行字符串操作。

运用方法

Series 有一个叫做apply的方法,允许进行高级过滤。

我们想找到所有姓氏为darwin的名字。

In [27]: names[names.apply(lambda x: x.split(' ')[-1] == 'darwin')]
Out[27]:
3    charles darwin
6    charles darwin
dtype: object

apply方法需要一个函数传递给它。这就是为什么我们给它传递了一个 lambda 函数。

调用 names.apply()将 lambda 函数应用于序列的所有值。.apply()的返回值是布尔值的一个series

In [26]: names.apply(lambda x: x.split(' ')[-1] == 'darwin')
Out[26]:
0    False
1    False
2    False
3     True
4    False
5    False
6     True
dtype: bool

我们使用布尔型series来过滤原始系列。

在 Twitter 上与我联系,我在 Twitter 上发布关于信息丰富且有价值的编程文章和建议。

使用 FlashTorch 深入了解迁移学习

原文:https://towardsdatascience.com/gaining-insights-on-transfer-learning-with-flashtorch-de344df0f410?source=collection_archive---------45-----------------------

PyTorch 中用于神经网络的开源特征可视化工具包

Visualisation of what AlexNet “sees” in these images of birds, using FlashTorch. Source

设置场景

在我的上一篇文章中,我概述了特征可视化作为一个研究领域,并介绍了FlashTorch一个用于 PyTorch 内置神经网络的开源特征可视化工具包

该软件包可以通过pip进行安装。查看 GitHub repo 获取源代码。你也可以在 Google Colab 的笔记本上使用它,而不需要安装任何东西!

使用闪光灯进行特征可视化

在之前的中,我向你展示了如何使用FlashTorch来可视化卷积神经网络(CNN)在输入图像中“感知”了什么。我是通过从 AlexNet 创建显著图来做到这一点的,Alex net 在 ImageNet 分类任务上进行了预训练。我从任务中挑选了三个类别(大灰猫头鹰、孔雀和巨嘴鸟),并使用这些类别的图像来检查Alex net 在识别这些对象时已经学会了如何在图像中最集中注意力

本质上,我选择了一个我知道会在我要求它做的事情上表现良好的网络,并检查了它的感知:我希望我们将我们的注意力从只关注测试精度转移到开始询问这个网络实际上在做什么。

什么是神经网络感知

为什么会这样?

我们如何解释它的决定/预测?

我创造了FlashTorch来让回答这样的问题变得更容易。而且这些问题不是只是针对你有表现良好的网络的时候!

事实上,网络表现不尽如人意的情况更为常见。但是在这里,我们经常被准确性所困扰。当我们看到糟糕的表现时,我们倾向于直接进行培训,而没有花太多时间去理解为什么它表现如此糟糕。

我可以帮你做到这一点,我想在迁移学习的背景下用一个例子来演示一下。

迁移学习

机器学习中的迁移学习是知识转移的一种形式——一种在一项任务上训练的模型被用于另一项任务的方法,通常作为起点。新任务所需的额外培训量取决于原始&新任务的相似性、培训数据的可用性等。

Traditional Learning vs Transfer Learning. Source

迁移学习经常在计算机视觉和自然语言处理任务中使用,因为它通过利用之前的培训帮助我们节省计算/时间资源。

例如,在 ImageNet (1000 个类)上训练的网络可以在没有太多额外训练的情况下重新用作狗识别器。或者,可以将在大型文本语料库(例如来自 Google 的 Word2Vec )上训练的单词嵌入引入另一个深度神经网络,以从新的语料库中提取单词的向量表示。

ImageNet →花卉分类器

为了测试迁移学习的能力,我决定使用 102 类别花卉数据集将 DenseNet (在 ImageNet 任务上预先训练过)制作成花卉分类器。

事实证明,在没有任何进一步训练的情况下,该模型的表现非常糟糕——高达 0.1%的测试精度!如果你已经算过了…我自己随机猜会更好。

直觉上,这也许是有道理的。原始 ImageNet 数据集中只有少数花卉类,因此不难想象让模型识别 102 种花卉是一件轻而易举的事情。

直觉很好,但是我想在继续训练之前把它具体化。

让我们使用FlashTorch来创建显著图,并可视化网络是什么(不是)看到的。我们将用这张毛地黄的图片作为例子。

这里我们可以欣赏的是,网络,不需要额外的训练,就是关注花杯的形状。但是有许多花有相似的形状(例如,想想风信子)。

对于我们人类来说,很明显(即使我们不知道这个物种的名字),这种花的独特之处在于花杯内的斑驳图案。但是,网络目前的除了花的大致形状之外,不知道在哪里关注,因为在旧任务(ImageNet 分类)中从来没有真正需要过。

既然我们已经了解了为什么网络表现不佳,我觉得已经准备好训练它了。最终,经过反复试验,经过训练的模型成功实现了 98.7%的测试准确率。

这太好了!…但是我们能解释为什么吗?

网络现在看到的是什么,以前不是?

很不一样,对吧?

网络学会了不太关注花的形状,而强烈关注那些斑驳的图案:)

显示神经网络已经学会的是有用的。将它带到另一个层次,并解释神经网络如何学习的过程是特征可视化技术的另一个强大的应用。

向前一步(不是走开!)从准确性

利用特征可视化技术,我们不仅可以更好地理解神经网络对物体的感知,而且我们还能更好地进行:

  • 诊断网络出了什么问题以及为什么
  • 发现并纠正算法中的偏差
  • 从只看准确性向前迈一步
  • 理解网络行为的原因
  • 阐明神经网络如何学习的机制

今天就使用闪光灯吧!

如果你有在 PyTorch 中使用 CNN 的项目,FlashTorch可以帮助你使你的项目更易理解和解释。

如果用了请告诉我你的想法!我将非常感谢您的建设性意见、反馈和建议🙏

谢谢,祝编码愉快!

gale-Shapley 算法简单解释

原文:https://towardsdatascience.com/gale-shapley-algorithm-simply-explained-caa344e643c2?source=collection_archive---------4-----------------------

从这篇文章中,你将了解稳定的配对或稳定的婚姻问题。你将学习如何使用博弈论和盖尔-沙普利算法来解决这个问题。我们将使用 Python 来创建我们自己的解决方案,使用 1962 年原始论文中的定理。

什么是稳定的婚姻或配对问题?

在现实世界中,有些情况下我们会面临配对问题:学生选择他们未来的大学,男人和女人互相寻求建立家庭,互联网服务需要在最短的时间内与用户连接。在所有这些情况下,我们都需要创建满足特定标准的稳定对。我们可以把(A,A)的稳定对想象成一对,其中没有 Aa 有任何更好的选择。

理解它的最好方法是解决实际的例子,我可以推荐《博弈论的洞察》这本书,它包含了大量你可以在纸上解决的练习。但是这里我想用 Python 来解决这个问题:)

问题定义:

在我们的例子中,我们将有两个组,女性和男性。女性名字会以大写字母开头: A、B、C、D 而男性以小写后者: a、B、C、d 。我们需要创造稳定的组合。在此之前,我们做了一个调查,收集一些信息作为我们的出发点。他们每个人都被要求根据个人的同情心给异性排序。其中 1 个是他们最喜欢的人,4 个是他们最不喜欢的人。

比如女人 A 这样回答: d,c,A,b

在 python 中,我们可以创建两个数据框男性和女性:

在数据框中,为了方便起见,用数字代替了等级。例如,如果我们想知道女性 A 的偏好,我们可以读取女性数据框中的列 A :分别为男性 a、b、c、d3、4、2、1 。如果我们想知道男性 a 的偏好,我们可以读取男性数据框中的 a 行: 1、2、3、4 分别对应女性 A、B、C、D

因此,一对男女可以表示为一对数字,例如,对 Aa 将创建一对数字(3,1)。对女人来说,T4 是第三位,但对男人来说,女人是第一位。

因此,在这种情况下,男人 a 完全快乐,但是女人 A 可以尝试与她名单中更高的人创造一对,例如,男人 c,如果对于 c 而言****与 A 创造一对比与他当前的伴侣创造一对更好,那么这两对都会崩溃并创造新的一对。

这就是不稳定配对的一个例子,在这种配对中,一个或两个参与者可以改善情况,但会为他们创造更好的配对。

所以任务是为所有参与者找到稳定的配对。事实证明有一种方法可以达到*衡!

Python 中的 Gale-Shapley 算法

大卫·盖尔和劳埃德·沙普利证明了当两个集合相等时,总有办法产生稳定的配对。我推荐阅读原文[2]来熟悉他们提供的优雅证明。

Python 中有不同的 Gale-Shapley 算法实现[3,4,5],让我们创建一个更接*伪代码解决方案的算法,而不是进入复杂的 OOP。

伪代码解决方案看起来是这样的[6]:

**function** stableMatching {
    Initialize all *m* ∈ M and *w* ∈ W to *free*
    **while** ∃ *free* man *m* who still has a woman w to propose to {
       w = first woman on m’s list to whom m has not yet proposed
       **if** w is *free*
         (m, w) become *engaged*
       **else** some pair (m', w) already exists
         **if** w prefers m to m'
            m' becomes *free*
           (m, w) become *engaged* 
         **else**
           (m', w) remain *engaged*
    }
}

在 Python 中,我能够创建这个解决方案:

总结:

博弈论非常有趣,因为它是根据现实世界的情况来操作的。而且它在大多数时候也不需要复杂的数学仪器,尤其是在合作游戏中。

关于 Gale-Shapley 算法有很多东西我们没有触及:男性人数不等于女性人数时的一般情况以及这个算法可能需要多少次最大迭代。

在看了开源解决方案后,我确信我将能够创建更简约甚至更 Pythonic 化的解决方案。但是我结束了一个相当混乱的周期...🤷‍♂️

你认为盖尔-沙普利算法最 Pythonic 化的写法是什么?

参考资料:

  1. 《对策论的洞见:另一种数学体验》,剑桥大学出版社,即将出版,与 Ein-Ya Gura 合著
  2. Gale D .、Shapley L.S. 大学录取与婚姻的稳定性 //美国数学月刊。1962.第 69 卷。第 9-15 页。
  3. https://rosettacode.org/wiki/Stable_marriage_problem#Python
  4. https://pypi.org/project/matching/
  5. 【https://github.com/QuantEcon/MatchingMarkets.py 号
  6. **【https://en.wikipedia.org/wiki/Stable_marriage_problem **

非数学家的伽罗瓦理论

原文:https://towardsdatascience.com/galois-theory-for-non-mathematicians-3bc08cd40c4a?source=collection_archive---------1-----------------------

一个少年如何发明了一个新的数学分支来解决一个长期悬而未决的方程问题

Image from Wikipedia and Keith Conrad

你可能知道,要解一个 2 次方程,a x +bx+c = 0,我们用的是二次公式。

对于 3 次和 4 次方程存在类似的公式,但是对于 5 次或更高次,它们神秘地消失了。更具体地说,似乎我们不能只用加法、减法、乘法、除法和根式(*方根、立方根等)来构造五次或更高次的解。为什么,数字 5 有什么特别的?这些问题在 19 世纪早期一直困扰着年轻的法国人埃瓦里斯特·伽罗瓦,在他在一场决斗中受致命伤的前一天晚上,他写下了一个新的数学对象“群”的理论,以一种令人惊讶的优雅方式解决了这个问题。

Galois being shot in a duel. Image from Wikimedia.

这就是他做这件事的方法。

TL;速度三角形定位法(dead reckoning)

不同方程的根的集合具有不同的复杂性。有些集合非常复杂,以至于不能只用简单的物体如部首来表达。但是如果我们甚至不能计算它们,我们如何测量根的复杂性,我们应该使用什么样的复杂性度量?

置换根和对称性

答案在于根的对称性。

你可能会问,这有什么关系?这到底是什么意思?

让我们画出两个方程的根,看看我们是否能理解它:

Images from WolframAlpha

据说左边的没有右边的对称。这可能会让你感到惊讶,因为在这个词的口语意义上,如果一个人可以反射或旋转物体而不改变其外观,通常会使用对称。从这个意义上说,左图看起来更对称。

例如:星星比心脏更对称,因为除了反射它之外,还可以旋转它。

Image inspired by Pinterest

但是在我们的例子中,我们将对对称性有一个更一般的看法。我们不仅仅局限于反射和旋转,任何改变物体外观的功能都是公*的。对于根,这意味着任何以任何方式交换(置换)根的函数都是有效的。更多的功能意味着更对称。

事实证明,在正确的情况下,有函数可以按照任何可以想象的顺序排列所有的根,多达 5 个!=120 ,所以高度对称。但是在左边的例子中,如果我们使用变换互换r↔ri↔−i我们必然也互换 r↔r ₅.这限制了我们,因此所有可能的排列都不可能。它不太对称。

置换根的函数称为“自同构”,如果我们将这些自同构组合在一起,我们就得到所谓的“群”(稍后我将回到自同构和群的更好的定义)。

这意味着在正确的情况下,代表根的对称性的组更大更复杂。事实上,右例中的组非常复杂,以至于不能用部首来描述根。

我们怎么知道一个群体有多复杂?为了理解这一点,我们需要更多的理论。

五分位数的大小

首先,我们来看看一个群体的规模。我怎么知道有些五次方有一个 5!大集团?

一般的五重奏通常是这样的:

x⁵+ax⁴+bx +cx +dx+e=0

但是如果我们采用一种更“以根为中心”的方法,我们可以说它看起来像这样:

(x−r₁)(x−r₂)(x−r₃)(x−r₄)(x−r₅)=
x⁵−(r₁+r₂+r₃+r₄+r₅)x⁴+
(r₁r₂+r₁r₃+r₁r₄+r₂r₄+r₃r₄+r₁r₅+r₂r₅+r₃r₅+r₄r₅)x……r₁r₂r₃r₄r₅=0

也就是说,第一个等式中的常数 a,b,c,d,e 被替换为根的对称组合:

r₁+r₂+r₃+r₄+r₅=a
r₁r₂+r₁r₃+r₁r₄+r₂r₄+r₃r₄+r₁r₅+r₂r₅+r₃r₅+r₄r₅=b
(为简洁起见省略了 c 和 d)
r₁r₂r₃r₄r₅= e

仔细观察所有的项,你会发现交换根并不影响等式(例如,试试上面的 b )。对于任何次数的多项式都是如此。由于我们能够交换所有的根,我们可以得出结论,这个一般的五次对称群实际上是所有的置换,也称为 s₅(5 阶对称群)。

域和自同构

现在我们要扩展一下自同构的定义,因为它们不仅仅是置换根的函数。在这个过程中我们需要引入一个叫做“场”的东西。你会说,我们为什么要这么做?原因是,虽然处理根和它们的排列很有趣,但是处理场和它们的自同构更容易一些。这是完全相同的功能,不要担心,只是看它们的另一种方式。

所以,如果等式是,比如说 x–2 = 0,我们将引入字段(√2),而不是处理根、【r₂=−√2】和。这是所有的有理数 Q 加上一个 √2√2 称为“场扩展”。看起来是这样的: a+b√2 a,b∈ Q 。为了能够描述方程的根,我们需要字段Q**(√2)。对于每个域扩展(以及其他数学对象),我们有一堆函数,σₙ,它们将一个数发送给同一域中的另一个唯一数,并遵循条件 σ(a+b)=σ(a)+σ(b)σ(ab)=σ(a)σ(b)σ 是扩展的函数,不触及底层字段 Q 。这些函数称为自同构。顺便说一下,他们也允许根。这是因为对于根 r 😗*

r⁵+ar⁴+br+Cr+dr+e=0⟹
σ(r⁵+ar⁴+br+Cr+dr+e)=σ(0)⟹
σ(r)⁵+aσ(r)⁴+bσ(r)+cσ(r)+dσ(r)+e = 0(
σ 不触及 Q (其中 a、b、c、d、e 住))

这意味着 σ(r) 也是方程的一个解。因为:

σ(r₁)−σ(r₂)=σ(r₁)+σ(−1)σ(r₂)=σ(r₁−r₂)≠0

词根分明,所以我们有 5 个,一定是原来的 5 个。因此 σ 必须置换根。

当然,这适用于任何次数的方程。

因此:

  1. 我们有自己的方程式。
  2. 那个方程有一个域,可能包含几个根式的延伸
  3. 那个域扩张有一个群,是它的所有自同构的集合。

三度的两个例子

示例 1

等式:x x 2x+2 = 0

根是( 1,√2,–√2)(你只要插上就可以自己验证这个了),所以字段一定是Q(√2)

From WolframAlpha

写下我们能想到的所有排列根的方法( e 表示单位排列,它没有任何作用):

(e)
(√2↔–√2)
(1↔√2)
(1↔–√2)
(√2→√2 和 1→√2)
(√2↔−√2 和 1↔−√2)

来测试一个:设 (√2↔−√2)σ₁ :

σ₁(√2+−√2)=σ₁(0)=0=σ₁(√2)+σ₁(−√2)
σ₁((√2)(−√2))=σ₁(−2)=−2=σ₁(√2)σ₁(–√2)

到目前为止一切顺利。又一个。

(1↔√2) 成为 σ₂ :

σ₂(√2+−√2)=σ₂(0)=0≠σ₂(√2)+σ₂(−√2)=1+−√2
σ₂((√2)(−√2))=2≠σ₂(√2)σ₂(−√2)=1(−√2)

显然 σ₂ 不是一个自同构,所以我们将不得不放弃它。其他的 σ 也遇到了类似的问题,剩下的只有 eσ₁ 。这被称为循环群 C ,因为我们只能在一个循环中置换(在这种情况下是一个很小的循环)。

示例 2

等式:x 2 = 0

根是

所以字段必须是

为简洁起见,使用 ζ 。这是它的样子:

From WolframAlpha

人们可以稍微摆弄一下根排列,很快就会注意到在这种情况下它们都是自同构的。于是就有了 3!自同构,即所有的根置换,所以群一定是 S₃

关于上面的图像,另一个有趣的事情是,它看起来像一个等边三角形,并且自同构正好对应于旋转和反射三角形。如果自同构以这种方式对应于正多边形的对称性,则该群称为“二面体群”。在这种情况下 D₃ 。通常所有排列的群 Sₙ 和二面体群 Dₙ 是不一样的,但是在 n=3 的情况下是一样的。

这似乎是一个很好的地方,可以继续进行关于组的更长的讨论。所以,群最初是根的排列的集合,但也可以看作是自同构的集合,或者对称几何对象的旋转和反射。任何改变一个对象使其看起来相同的函数集合都可以被认为是一个组。但是,我们实际上可以看到变换本身,而不必担心它们所作用的对称对象。就像我们做算术时不用担心成堆的苹果一样,我们只是简单地遵循规则,类似地,我们可以定义一些规则,一个组的变换遵循这些规则,并使用它们。

规则大概是这样的:

如果我们先做一个变换,然后再做一个,我们会得到第三个变换,它仍然在这个组中。例如, C₄ 群是一个人在正方形上可以做的所有旋转的群。如果 a 正在旋转 90∘ ,b 正在旋转 180∘ ,c 正在旋转 270∘ ,那么a∫b = c。这里的意思是,先做 b,再做 a,通常称为乘法,因为它(有点)类似于数字的乘法。根据上面的规则,c 必须在组中。这就叫完结。

必须有一个身份元素 (e) 不做任何事情。

每个元素都有一个相反的元素。

现在,我们可以研究不同组的特征,而不必担心根或多边形。

可视化群组

可视化组两种有趣的方法是:

凯莱表

Image inspired Wikipedia

上面是等边三角形的凯雷表, D₃ 组。就是这个组的所有元素,以及我们把它们相乘得到什么元素。例如,如果我们首先做一个 120∘ 旋转 (r) ,然后再次做同样的旋转,我们得到一个 240∘ 旋转 rr=r ,如表中所示。如果我们做一个 120∘旋转翻转 rf 和一个 r 我们最终只是翻转。请注意元件 fr 不交换。元素交换的群称为阿贝尔群。

这个特殊的表仍然是非常对称的,但是不需要这样。遵循规则的元素周围的任何加扰都是有效的。

凯莱图

Image inspired by wikimedia

以上是 D₃ 凯莱图。这里的元素以某种方式显示,显示如何从一个元素到下一个元素,其中边是操作。在这种情况下, 120∘ 旋转和翻转是必要的,这些( rf )也被称为群的生成器,因为可以用它们从单位元素开始生成整个群。

组的用法

Image from Wikipedia

在对称的地方,群体往往是有用的。例如,壁纸组用于描述对称壁纸。有一些壁纸可以旋转 180∘和一些壁纸可以反映和一些我们可以做到这两者,等等。原来只有 17 种,所以这是一种很好的壁纸分类方式。

以上壁纸都属于一个叫 p6m 的群体。

另一个更令人惊讶的是,群体的用途是在物理学中。似乎自然法则遵循一定的对称性。例如,如果一个人变换牛顿第二定律 F=ma,10 分钟后还是一样。自然法则一天不变,似乎表明它们在时间转换方面是对称的。它们也不会从一个地方改变到下一个地方,所以空间的转换也是允许的。因为时间和空间可以变换成任意大小的块,所以描述这些块的群,李群,包含了无限多的元素。

有趣的是,这些对称性都与一个守恒定律有关。时间对称意味着能量守恒,空间对称意味着动量守恒,角对称意味着角动量守恒,等等。艾米·诺特通过将对称性与最小作用原理相结合证明了这一点,最小作用原理是一条自然法则,它表明自然倾向于“走最短的路”。

我觉得有趣的是,大自然的所有复杂和明显的混乱有多少可以用“自然法则不会每天都改变”和“自然倾向于走最短的路”这样的直观概念来解释。

返回字段

间奏曲结束,我们说到哪了?对,我们在讨论x3= 0 及其根和场。

该方程的场是 Q ( √2,ζ),很自然地认为它看起来像这样:a+b √2+cζ,但这是错误的。这样做的原因是我们希望我们的领域是“封闭的”。也就是说,如果我们将场中的两个元素相加或相乘,我们希望它们留在该场中。例如√2 和ζ都在上面的区域,但是√2ζ不在。

子字段和子组

看一下上面 3 级的例子,我们有

第二个域和组似乎比第一个域和组更复杂。我们可以通过计算场情况下的项数或群情况下的自同构数来猜测这一点。但是仅仅计数似乎并不能真正抓住复杂的含义。以小组 C₁₂ 为例。很多元素,但它只是旋转了根,所以看起来并不复杂。一个对应的字段是q**(e^π/6)。它将包含 eπ/6,e2π/6…,但同样不会很复杂。**

记住,担心一个群体有多复杂是理解为什么有些根不能只用偏旁部首来描述的关键。

为了更好地理解复杂性,我们将引入“子场”和“子群”的概念。子字段是指当你删除一些术语,但你仍然有一个封闭的字段。类似地,子群是当你去掉一些自同构,但仍然有一个封闭群。

第一种情况 Q (√2),唯一能做的就是去掉场中的 √2 和群中的两个自同构中的一个(我们不能去掉 (e) 仍然有群)。

至于第二种情况 Q ( √2,ζ) ,就变得有点复杂了。可以通过一次仅移除一个元素来手动提取子字段/组,并查看结果字段/组是否是封闭的。过了一会儿,我们得出这样的结论:

Images by Keith Conrad

有趣的是,场和组都有四个组成部分。现在,一个合理的猜测是子群总是包含子域的自同构。但是他们没有。

固定字段

别担心,我们就快到了,只是稍微复杂一点。要了解这一点,我们来看看字段 Q (⁴√2,我)及其子字段。

Image by Keith Conrad

字段 Q (⁴√2,i) 具有置换群 D₄(与正方形相同)。让我们看看 D₄ 及其子群。

Images by Keith Conrad

在这幅图中,子群晶格是颠倒的,D₄在底部,我将很快谈到这一点,但让我们先来看看子群的子域。 Q (⁴√2,i) 有 5 个大的子场和 3 个小的子场,而 D₄ 只有 3 个大的子场和 5 个更小的子场。

似乎没有足够大的组来排列 5 个大字段。如果你想研究子组和子字段,你最终会得出这样的结论:子组实际上置换的不是子字段,而是不在子字段中的所有东西,它们“固定”或不接触子字段。

所以比如 (f) 修复q【⁴√2】**(r,f) 修复q**(√2)。**

为什么像我们最初猜测的那样,是这样而不是反过来?

我没有一个直观的方法来解释这个问题,我的看法是,我们凭经验发现了它,现在我们可以尝试证明它。证据大概是这样的:

伽罗瓦理论手动波动基本定理证明草图

我们想证明,如果我们把子群格颠倒过来,我们得到与子域格一一对应,其中域是群的固定域。

首先,我想指出,这种情况是合理的。在底部的组中,我们有所有的自同构,它们当然围绕着除了 Q (修复 Q )之外的所有东西移动,在顶部,我们只有 e-自同构,它不围绕任何东西移动(修复所有东西)。

如果我们从底部群开始,去掉几个自同构,去掉的自同构将不再围绕一小部分场移动,因此将固定那部分场。随着我们移除更多的自同构,越来越多的场将不受影响,因此我们将有一个更大的固定场。

更严格地说,我们需要能够比较团队和领域的规模。当然,群的大小就是其中自同构的个数。字段的大小是术语的数量。这两个恰好相同,但为什么会这样呢?

现在,我们可以看看五次的 S₅子群晶格,看到它看起来确实很复杂。但是为了把这和部首联系在一起,我们需要一种方法来分析群和它的子群之间的复杂性。那就是:举例来说,D₄比 C₄复杂多少?为此,我们引入了“商”的概念。商基本上就是群除。这是怎么回事?

在普通的除法中,我们做这样的事情:将 15 个苹果分成 5 个人,我们将苹果集中的苹果分成 5 等份,每一份对应一个人。问题 15/5 的答案是 3,其中一堆,任何一堆都可以,因为它们相等。

当我们分组时,类似的事情也会发生。为了将 D₄除以 C₄,我们将 D₄的 8 种元素分成 4 个相等的组,C₄.的每种元素一组我们如何使各组*等?并不是所有的元素都是相同的苹果。例如,它们可以是非常不同的自同构。因为这个原因,商并不总是可能的。但有时一个组可以分成“陪集”。假设我们把 D₄分成 4 等份,每份 2 个元素。如果幸运的话,我们可以有 4 堆元素,其中所有堆中两个元素之间的关系都是相同的。为了做到这一点,原始群体必须表现出高度的自我相似性。要了解这一点,让我们来看看 D₄.的凯莱曲线图

Image inspired by wikimedia

正如你所看到的,事实上这里有高度的自相似性。左上角、右上角、左下角和右下角看起来都一样。这是我们的陪集。

所以 D₄/C₄基本上是 C₂.的陪集之一因此:D₄/C₄=C₂.

现在,通过引入商,我们实际上有了一个如何从头开始建立群体的概念。正如 21 由 3 和 7 组成一样,群也由它们的子群组成。正如我们可以通过除法得到一个数的组成,21/7=3,所以我们可以通过商得到一个组的组成。因为 D₄/C₄=C₂,这意味着如果我们有一个 C₄群,我们必须乘以 C₂得到 D₄.由于字段和组之间存在对应关系,这将在我们如何构造字段时发挥作用。

激进分子

五元组的子组

现在,我不会展示 S₅的群格的图片,因为它太大了,但是我会说一些关于它的子群的事情。其中一个分组是 A₅ (交替组),很容易检查。为了从 A₅的到 S₅的,我们需要 S₅/A₅=C₂的*。因此,我们可以通过根来达到目的,但是:A₅的一个子群是 A₅/e 的循环群。顺便说一下,这对于任何一个 n≥5 的 An 都是成立的。因此,我们不能通过根来达到目的,唉,任何次数≥5 的多项式都不能通过根来求解。***

这就是十几岁的伽罗瓦如何发明了群的概念来证明一个长期存在的关于五次⁹的不可解性的公开问题。

三等分角

我们从围绕伽罗瓦理论的机器中得到一个有趣的额外事实,在这种情况下,领域的塔定律,是一个自古希腊以来就困扰人类的问题的很好的证明,即:不可能用直尺和指南针将一个角分成三份。显然,希腊人喜欢用这种方式绘画,并对这种方法的局限性感到好奇。

一个例子是在另外两个点中间找到一个点。要做到这一点,把指南针放在两个点上,先围绕一个点画一个圆,然后围绕另一个点。用直尺作为尺子,在两点之间画一条线,然后在两个圆相交的点之间画一条线。中间是线交叉的地方。

但是这种作图方式如何转化为场论呢?嗯,我们可以把上面的问题看成,假设我们有一个两点的场, (x₁,y₁)(x₂,y₂) 。我们希望扩展该字段,使其也包含中间点。为此,我们找到圆的交点 (x−x₁) +(y−y₁) =r(x−x₂) +(y−y₂) =r 。我们得到两个新点 (x₃,y₃)(x₄,y₄) 。他们之间的界线是y=(y₄−y₃)/(x−x₃)x前两点之间的线是 y=(y₂−y₁)/(x₂−x₁)x 。求解 x 得到它们的交点。

Image inspired by Visual Group theory

显然,直尺和圆规的构造相当于解一次和二次方程。

但是三等分一个角等于什么呢?

三倍角公式得出:

但是由于使用直尺和圆规与解一维和二维方程是一样的,所以对于一次运算来说,唯一可能的域扩展是 2,然后使用新的点,我们可以得到 2 的幂: 4,8,16 等,但永远不会是 3。

虽然只使用直尺和圆规不可能将角度分成三份,但使用折纸术是可能的。

求解一般五次方程

应该说,虽然一般的五次项不能用根式求解,但可以用“雅可比θ函数”来求解。

参考

  1. 初学者的伽罗瓦理论:历史透视。约尔格·贝维尔斯多夫
  2. http://pi.math.cornell.edu/~kbro...
  3. 场自同构
  4. https://kconrad.math.uconn.edu/b...
  5. https://faculty . math . Illinois . ed...
  6. Wolfram|Alpha:让世界的知识变得可计算
  7. https://www.wikiwand.com/en/Galois_theory
  8. https://www.wikiwand.com/en/%C3%89variste_Galois
  9. https://www.youtube.com/watch?v=8qkfW35AqrQ&list = PLwV-9dg 53 ndxu 337 smptwm 6 sef 4x-SCLv&index = 36

游戏人工智能与极大极小和蒙特卡罗树搜索

原文:https://towardsdatascience.com/game-ais-with-minimax-and-monte-carlo-tree-search-af2a177361b0?source=collection_archive---------6-----------------------

内部 AI

极大极小和蒙特卡罗树搜索直观指南

Photo by veeterzy on Unsplash

你还记得你发现了臭名昭著的游戏井字游戏并和你的朋友一遍又一遍地玩它的童年时光吗?

你可能想知道是否有某种策略可以利用,让你一直赢(或者至少强迫和棋)。有没有这样一种算法可以告诉你如何在任何给定的时间打败你的对手?

原来是有的。准确地说,有几种算法可以用来预测游戏中的最佳可能走法,例如井字游戏、连接四个、国际象棋和围棋等等。一个这样的算法家族利用树搜索并在游戏状态树上操作。

在这篇博文中,我们将讨论两种著名的树搜索算法,分别叫做极小极大和蒙特卡罗树搜索(缩写为 MCTS)。我们将通过发现其内部工作背后的直觉来开始我们的树形搜索算法之旅。之后,我们将看到如何在现代游戏实现中使用极小极大和 MCTS 来构建复杂的游戏人工智能。我们还将阐明我们将面临的计算挑战,以及如何通过性能优化技术来应对这些挑战。

树搜索背后的直觉

让我们想象你正在和你的朋友玩一些井字游戏。玩的时候,你想知道最佳策略可能是什么。在任何情况下,你应该采取什么样的最佳行动?

一般来说,在决定下一步该怎么走时,有两种模式可供选择:

咄咄逼人:

  1. 下一步棋,这一步棋会立即赢得胜利(如果可能的话)
  2. 下一步棋,这一步棋将为未来的胜利创造条件

防守:

  1. 下一步棋阻止你的对手赢(如果可能的话)
  2. 下一步棋,阻止你的对手在下一轮建立未来的胜利局面

这些模式和它们各自的行动基本上是你赢得井字游戏唯一需要遵循的策略。

你需要做的“唯一”的事情就是看看你现在所处的游戏状态,并通过所有可能的下一步行动进行模拟。你通过假装你已经下了一个给定的棋,然后继续玩游戏直到结束,在 XO 玩家之间交替。在这样做的同时,你正在建立一个你和你的对手可能采取的所有行动的博弈树。

下图显示了这种游戏树的简化版本:

注意,在这篇文章的剩余部分,我们将只使用简化的游戏树例子来节省屏幕空间

当然,我们在上面讨论的策略规则是专门为井字游戏量身定制的。然而,我们可以推广这种方法,使其适用于其他棋盘游戏,如国际象棋或围棋。让我们来看看 Minimax ,一种树搜索算法,它抽象了我们的井字游戏策略,以便我们可以将其应用于其他各种双人棋盘游戏。

极大极小算法

鉴于我们已经建立了对树搜索算法的直觉,让我们把注意力从简单的游戏如井字游戏转移到更复杂的游戏如国际象棋。

在我们开始之前,让我们简单回顾一下国际象棋游戏的属性。国际象棋是一个 2 人的完全信息确定性博弈。听起来很困惑?让我们打开包装:

在国际象棋中,两个玩家(黑和白)互相对战。执行的每一步都确保“完成”,没有任何随机性(游戏不使用任何随机元素,如骰子)。在游戏过程中,每个玩家都可以观察整个游戏状态。没有隐藏的信息,因此每个人在任何给定的时间都有关于整个游戏的完美信息。

由于这些属性,我们总是可以计算出哪个玩家现在领先,哪个玩家落后。在国际象棋比赛中,有几种不同的方法可以做到这一点。评估当前游戏状态的一种方法是将棋盘上所有剩余的白色棋子相加,然后减去所有剩余的黑色棋子。这样做将产生单个值,其中大值偏向白色,小值偏向黑色。这种类型的函数被称为评估函数

基于这个评估函数,我们现在可以为每个玩家单独定义游戏中的总体目标。白棋试图最大化这个目标,而黑棋试图最小化它。

让我们假设我们正深陷于一场正在进行的国际象棋比赛中。我们是玩家白,已经下了几个聪明的棋,通过我们的评估函数计算出了一个很大的数字。现在轮到我们了,但是我们被卡住了。哪一个可能的步骤是我们能做的最好的?

我们将用我们在井字游戏中遇到的同样的方法来解决这个问题。我们建立了一个潜在的行动树,可以根据我们所处的游戏状态来执行。为了简单起见,我们假设只有两种可能的走法(在国际象棋中,每个给定的游戏状态*均有 30 种不同的选择)。我们从代表当前状态的(白色)根节点开始。从那里开始,我们分支出 2 个(黑色)子节点,代表我们在采取 2 个可能的行动之一后所处的游戏状态。从这两个子节点,我们再次分支出两个独立的(白色)子节点。每一个都代表了我们从黑色节点采取两种可能的行动之一后的游戏状态。这种节点的分支一直持续下去,直到我们到达游戏的结尾或者达到预定义的最大树深度。

生成的树看起来像这样:

假设我们在树的末尾,我们现在可以用我们的评估函数计算每个结束状态的游戏结果:

有了这些信息,我们现在知道了当我们从根节点开始,到我们计算游戏评估的最后一个节点结束时,我们可以预期的游戏结果。因为我们是白牌玩家,看起来最好的选择是让我们最终以我们的评估函数计算出的最高结果结束游戏。

虽然这是真的,但有一个问题。仍然有一个黑人玩家参与其中,我们不能直接操纵她会选择什么行动。如果我们不能操纵这一点,为什么我们不根据我们的评估函数来估计黑人玩家可能会做什么呢?作为一名白人球员,我们总是试图最大化我们的结果。黑人玩家总是试图最小化结果。有了这些知识,我们现在可以遍历我们的游戏树,一步一步地计算所有单个树节点的值。

怀特试图最大化结果:

而布莱克想把它最小化:

完成后,我们现在可以根据刚刚计算的评估值选择下一步行动。在我们的案例中,我们选择最大化我们结果的下一个可能的行动:

我们刚刚学的是所谓的极小极大算法的一般流程。极大极小算法得名于这样一个事实,即一个玩家想要最小化-结果,而另一个玩家试图最大化-结果。

密码

def minimax(state, max_depth, is_player_minimizer):
  if max_depth == 0 or state.is_end_state():
    return evaluation_function(state) if is_player_minimizer:
    value = -math.inf
    for move in state.possible_moves():
      evaluation = minimax(move, max_depth - 1, False)
      min = min(value, evaluation)
    return value value = math.inf
  for move in state.possible_moves():
    evaluation = minimax(move, max_depth - 1, True)
    max = max(value, evaluation)
  return value

通过修剪减少搜索空间

Minimax 是一个简单而优雅的树搜索算法。只要有足够的计算资源,它总能找到最佳的下一步棋。

但是有一个问题。虽然这种算法对于像井字游戏这样简单的游戏来说是完美的,但是对于像国际象棋这样更复杂的游戏来说,在计算上是不可行的。其原因是所谓的树分枝因子。我们之前已经简要地谈到了这个概念,但是让我们再看一看。

在我们上面的例子中,我们人为地限制了一个人可以玩的潜在移动到 2,以保持树的表示简单和容易推理。然而,现实情况是,通常有两个以上的可能下一步行动。*均来说,一个棋手在任何给定的游戏状态下可以走大约 30 步。这意味着树中的每个节点都有大约 30 个不同的子节点。这叫做树的宽度。我们将树的宽度表示为 w

但是还有更多。大约要连续 85 回合才能下完一盘棋。将此转化为我们的树意味着它的*均深度为 85。我们将树的深度表示为 d

给定 wd ,我们可以定义公式 w^d ,它将显示我们*均需要评估多少个不同的位置。

输入国际象棋的数字,我们得到了 30^85.以围棋棋盘游戏为例,其宽度 w 约为 250,*均深度 d 约为 150,我们得到 250^150.我鼓励你把这些数字输入计算器,然后按回车键。不用说,当代计算机甚至大规模分布式系统将“永远”处理所有这些计算。

这是否意味着 Minimax 只能用于井字游戏等游戏?绝对不行。我们可以运用一些巧妙的技巧来优化搜索树的结构。

一般来说,我们可以通过修剪单个节点和分支来减少搜索树的宽度和深度。让我们看看这在实践中是如何工作的。

阿尔法-贝塔剪枝

回想一下,Minimax 是建立在一个前提上的,即一个玩家试图根据评估函数最大化游戏的结果,而另一个玩家试图最小化它。

这种游戏性行为直接转化为我们的搜索树。在从底部到根节点的遍历过程中,我们总是为任何给定的玩家选择各自的“最佳”移动。在我们的例子中,白人玩家总是选择最大值,而黑人玩家选择最小值:

看看上面的树,我们可以利用这个行为来优化它。方法如下:

考虑到目前的游戏状态,我们应该以深度优先的方式构建我们的树。这意味着我们应该从一个节点开始,并通过从头到尾玩游戏来扩展它,然后再返回并选择我们想要探索的下一个节点:

遵循这个程序可以让我们识别出永远不会在早期使用的招式。毕竟,一个玩家最大化结果,而另一个玩家最小化结果。在搜索树中,根据评估函数,玩家会在更糟糕的情况下结束的部分可以从我们想要扩展和探索的节点列表中完全删除。我们从搜索树中删除这些节点,从而减少树的宽度。

树的分支因子越大,我们可能节省的计算量就越大!

假设我们可以将宽度*均减少 10,那么我们将不得不进行 w^d =(30−10)^85 = 20^85 计算。这已经是一个巨大的胜利了。

这种修剪搜索树中在游戏过程中永远不会被考虑的部分的技术被称为阿尔法-贝塔修剪。Alpha-Beta 修剪得名于参数α和β,这两个参数用于记录玩家在树上行走时可以获得的最佳分数。

密码

def minimax(state, max_depth, is_player_minimizer, alpha, beta):
  if max_depth == 0 or state.is_end_state():
    return evaluation_function(state) if is_player_minimizer:
    value = -math.inf
    for move in state.possible_moves():
      evaluation = minimax(move, max_depth - 1, False, alpha , beta)
      min = min(value, evaluation)
      beta = min(beta, evaluation)
      if beta <= alpha:
        break
      return value value = math.inf
  for move in state.possible_moves():
    evaluation = minimax(move, max_depth - 1, True, alpha, beta)
    max = max(value, evaluation)
    alpha = max(alpha, evaluation)
    if beta <= alpha:
      break
    return value

使用 Alpha-Beta 剪枝来减少树的宽度有助于我们在具有大分支因子的游戏中利用 Minimax 算法,这在以前被认为是计算上太昂贵了。

事实上,深蓝,由 IBM 开发的国际象棋计算机在 1997 年击败了国际象棋世界冠军加里·卡斯帕罗夫大量使用了并行化的基于阿尔法-贝塔的搜索算法。

蒙特卡罗树搜索

似乎极小极大结合阿尔法-贝塔剪枝足以构建复杂的游戏人工智能。但是有一个主要问题会使这些技术变得无用。这是定义一个稳健合理的评价函数的问题。回想一下,在国际象棋中,我们的评估函数把棋盘上所有的白棋加起来,减去所有的黑棋。这导致当白色有优势时的高值,以及当情况有利于黑色时的低值。虽然这个函数是一个很好的基线,绝对值得尝试,但通常需要包含更多的复杂性和微妙之处,才能得到一个合理的评估函数。

一旦底层的内部情况浮出水面,简单的评估指标很容易被欺骗和利用。对于围棋等更复杂的游戏更是如此。设计一个足够复杂的评估函数来捕捉大部分必要的游戏信息,需要大量的思考以及软件工程、数学、心理学和游戏方面的跨学科领域的专业知识。

难道没有一个普遍适用的评估函数,我们可以利用它来评估所有的游戏,不管它们有多简单或多复杂?

有,有!这叫做随机性。有了随机性,我们就让机会成为我们的向导,来决定下一步该怎么走。

在下文中,我们将探索所谓的蒙特卡洛树搜索(MCTS) 算法,该算法严重依赖随机性(名称“蒙特卡洛”源于蒙特卡洛中的赌博区)作为值*似值的核心组件。

顾名思义,MCTS 还建立了一个博弈树,并对其进行计算,以找到最高潜在结果的路径。但是这棵树的构造有一点不同。

让我们再一次假装我们正在作为玩家怀特下棋。我们已经玩了几轮了,现在又轮到我们来选择我们想玩的下一步棋了。此外,让我们假设我们不知道任何评估函数,我们可以利用来计算每一个可能的移动的价值。有没有什么方法可以让我们知道哪一步棋可以让我们最终获胜?

事实证明,有一个非常简单的方法可以解决这个问题。为什么我们不让两个玩家从我们现在所处的状态开始玩几十个随机游戏呢?虽然这听起来可能违反直觉,但仔细想想,还是有道理。如果两个玩家都从给定的游戏状态开始,玩数千次随机游戏,并且玩家白赢得 80%的时间,那么这个状态一定有什么东西给了白优势。我们在这里所做的基本上是利用大数定律(LLN) 来为我们可能的每一步棋找到“真实的”游戏结果。

以下描述将详细概述 MCTS 算法如何工作。为了简单起见,我们再次只关注任何给定状态下的 2 个可走的棋步(因为我们已经发现*均有 30 个不同的棋步可供我们选择)。

在我们继续之前,我们需要弄清楚一些次要的定义。在 MCTS,我们为树中的每个节点记录 2 个不同的参数。我们称这些参数为 tnt 代表“总计”,代表该节点的总值。 n 是“访问次数”,它反映了我们在遍历树时访问这个节点的次数。当创建一个新节点时,我们总是用值 0 初始化这两个参数。

除了我们为每个节点存储的 2 个新参数,还有所谓的“置信上限 1”(UCT)公式,如下所示

这个公式基本上帮助我们决定我们应该从哪个即将到来的节点和潜在的游戏移动开始我们的随机游戏系列。在公式中,xi 代表我们正在处理的游戏状态的*均值, C 是一个我们需要手动定义的叫做“温度”的常数(我们在这里的例子中只是将其设置为 1.5。稍后将详细介绍), N 表示父节点访问量, ni 表示当前节点访问量。当在候选节点上使用这个公式来决定进一步探索哪个节点时,我们总是对最大的结果感兴趣。

不要被数学吓倒,只要注意到这个公式是存在的,并且在我们使用我们的树时会有用。在遍历我们的树时,我们将更详细地了解它的用法。

解决了这个问题之后,是时候让 MCTS 找出我们可以采取的最佳行动了。

我们从我们已经熟悉的树的同一个根节点开始。这个根节点是我们的起点,反映了当前的游戏状态。基于这个节点,我们分支出两个子节点:

我们需要做的第一件事是使用上面的 UCT 公式,计算两个子节点的结果。事实证明,我们需要为 UCT 公式中的几乎每个变量插入 0,因为我们还没有对树及其节点做任何事情。这将导致两种计算的∞结果。

我们已经用一个很小的数字替换了分母中的 0,因为零除没有定义

考虑到这一点,我们可以自由选择要进一步探索的节点。我们从最左边的节点开始,执行我们的首次展示阶段,这意味着我们从这个游戏状态开始玩几十个随机游戏。

一旦完成,我们就得到这个特定首次展示的结果(在我们的例子中,玩家白的获胜百分比)。我们需要做的下一件事是沿着树向上传播这个结果,直到到达根节点。在这样做的时候,我们用我们遇到的每个节点各自的值来更新 tn 。一旦完成,我们的树看起来像这样:

接下来,我们再次从根节点开始。我们再次使用 UCT 公式,代入我们的数字,计算两个节点的得分:

假设我们总是选择具有最高值的节点,我们现在将探索最右边的一个。我们再一次基于这个节点提议的移动来执行我们的首次展示,并且在我们完成所有的随机游戏之后收集最终结果。

我们需要做的最后一件事是传播这个结果,直到我们到达树的根。在此过程中,我们会更新遇到的每个节点的参数。

现在,我们已经成功探索了树中的 2 个子节点。你可能已经猜到了。我们将再次从根节点开始,计算每个子节点的 UCT 分数,以确定我们应该进一步探索的节点。这样做,我们得到以下值:

最大值是我们为最左边的节点计算出的值,所以我们决定进一步研究这个节点。

假设这个节点没有子节点,我们添加两个新节点,这两个新节点表示我们可以对树进行的潜在移动。我们用 0 初始化它们的两个参数( tn )。

现在我们需要决定我们应该进一步探索这两个节点中的哪一个。你是对的。我们使用 UCT 公式来计算它们的值。假设两者的 tn 值都为零,那么它们都是∞,所以我们决定选择最左边的节点。我们再一次进行展示,检索这些游戏的值,并将该值向上传播到树,直到到达树的根节点,同时更新所有节点参数。

下一次迭代将再次从根节点开始,在这里我们使用 UCT 公式来决定我们想要进一步探索哪个子节点。因为我们可以在这里看到一个模式,我不想让你感到厌烦,所以我不打算详细描述接下来的步骤。我们要做的是遵循我们在上面使用的完全相同的程序,可以总结如下:

  1. 从根节点开始,使用 UCT 公式计算每个子节点的分数
  2. 选择您已经计算出最高 UCT 分数的子节点
  3. 检查孩子是否已经被探访过
  4. 如果没有,进行首次展示
  5. 如果是,从那里确定潜在的下一个状态,使用 UCT 公式来决定选择哪个子节点并进行展示
  6. 将结果传播回整个树,直到到达根节点

我们迭代这个算法,直到用完时间或者达到预定的访问、深度或迭代的阈值。一旦发生这种情况,我们评估我们的树的当前状态,并挑选使值 t 最大化的子节点。多亏了我们玩过的几十个游戏和大数定律,我们可以非常肯定这一步是我们可能玩的最好的一步。

就这些了。我们刚刚学习、应用和理解了蒙特卡罗树搜索!

你可能会同意 MCTS 是一个计算密集型的地方,因为你必须运行成千上万的随机游戏。这绝对是真的,我们需要非常聪明地知道我们应该在哪里投入资源,以便在我们的树中找到最有希望的路径。我们可以用前面提到的 UCT 公式中的“温度”参数 C 来控制这种行为。通过这个参数,我们可以*衡“勘探与开发”之间的权衡。

大的 C 值使我们进入“探索”模式。我们将花更多的时间访问探索最少的节点。 C 的一个小值将我们置于“利用”模式,在这种模式下,我们将重新访问已经浏览过的节点,以收集更多关于它们的信息。

鉴于利用随机性的简单性和适用性,MCTS 是一种广泛使用的博弈树搜索算法。 DeepMind 使用深度神经网络扩展了 MCTS,以优化其在寻找最佳围棋走法方面的性能。最终的游戏 AI 非常强大,达到了超人的水*,并且以 4 比 1 击败了围棋世界冠军李·塞多尔。

结论

在这篇博文中,我们研究了两种不同的树搜索算法,它们可以用来构建复杂的游戏人工智能。

虽然 Minimax 与 Alpha-Beta 剪枝相结合是一种可靠的解决方案,可以很容易地定义评估游戏结果的评估函数,但是蒙特卡罗树搜索(MCTS) 是一种普遍适用的解决方案,因为它依赖于随机性,所以不需要评估函数。

原始的极小极大和 MCTS 只是开始,可以很容易地扩展和修改,以在更复杂的环境中工作。 DeepMind 聪明地将 MCTS 与深度神经网络结合起来预测围棋棋步,而 IBM 将阿尔法-贝塔树搜索扩展到计算可能的最佳棋步来下棋。

我希望这种对游戏人工智能算法的介绍激发了你对人工智能的兴趣,并帮助你理解下次你在电脑上玩棋盘游戏时会遇到的底层机制。

你有任何问题/反馈吗?请随时通过电子邮件或 Twitter 联系我!

最初发表于philippmuens.com

《权力的游戏》第八季情感分析

原文:https://towardsdatascience.com/game-of-thrones-sentiment-analysis-1d3e158704cc?source=collection_archive---------21-----------------------

SPOILERS ARE COMING!

作为这本书和这部剧的超级粉丝,我忍不住分析了粉丝们对播出的最后一季的反应。这项分析的数据来自三个子网站(r/gameoftrones、r/freefolk 和 r/asoiaf)和冰与火论坛。我和我在梅蒂斯大学的一位同学,T2 大学的德雷克·巴洛一起进行分析,因为我们渴望剖析社交媒体上明显泛滥的各种反应。

Source: Washington Post

每集都有多次失误,像这样的引用已经在社交媒体上到处分享。这是一个苛刻的判断,我们将调查球迷们在观看最后一季时的情绪,看看事实是否如此。

我们从使用 VADER 情感分析工具分析所有四个*台的评论开始,从该季首播前两周开始,到大结局播出后的第二天结束。VADER 特别适合情感分析,因为它可以识别大写字母、表情符号和标点符号等元素。首先,我们检查了总的结果:

Aggregate fan reactions over the course of the season

很容易看到这一季中产生强烈意见的剧集,如《长夜》(夜王)、《钟声》(君临)和《铁王座》(大结局)。然而,以这种方式可视化数据的一个缺陷是,它淡化了低容量论坛的情绪。例如,冰与火论坛里的观点在这个观点里看起来基本上是一集比一集*。我们想探究这是否是真的,所以决定也看看卑鄙的情绪。

Mean sentiment over time

一旦我们考虑到四个频道的人数差异,并取每个频道每天的*均情绪,得到的图片就更加*衡,很容易观察到论坛上的粉丝的表达能力,以及他们的反应比三个子主题上的粉丝更加极端。整个赛季的总体情绪没有我们预期的那么消极。

将各频道的反应分开来看,与论坛和自由民 redditors 的反应相比,《权力的游戏》subreddit 似乎总体上更积极。《七国骑士》中感觉良好的一集引发了本季最高水*的积极反应,其次是《临冬城》首播前的整体预期水*。

在分析的这一点上,我很兴奋地发现粉丝们并不像社交媒体反应的那样讨厌这部剧。但是我们也很想知道他们在每集之后到底在讨论什么。尽管我们这次只拿到了六个,但每个都充满了内容和 OMG 时刻,因此详细剖析它们似乎是显而易见的。我将一集一集地给你详细分析(可以在我的 GitHub 上找到),但是强调一些我们最好奇的发现。

pyLDAviz helps us look at the results topic by topic

看看这一季首播前的话题——显然每个人都在想白行者,令人兴奋的是,当粉丝们讨论夜王的象征以及如何通过牺牲卡斯特的孩子来制造白行者的过程时,观察到“螺旋”和“孩子”这样的词就在列表的顶部附*。

另一个奇怪的话题来自《钟声激越》这一集,对我来说这是最有争议的一集,丹妮似乎心血来潮决定烧毁一座城市。这一集的主题之一是杰米和瑟曦戏剧性的结局,以及君临和大部分人民的毁灭。

pyLDAviz depicting the topics of the Bells episode, which deals with the destruction of King’s Landing

在一个季度内发生了这么多史诗般的毁灭场景和这么多主要角色的死亡之后,第八季结束了我们所有人在许多周日都屏住呼吸观看的一场演出,聚集在一起观看更多我们心爱的角色遭遇他们经常不合时宜的死亡。正如我们在该系列最后一集《铁王座》之后看到的粉丝评论一样,最严厉的反应听起来最响亮,但负面反应中也有对该剧和演员的赞赏,人们感谢该剧将他们最喜爱的小说带入生活。

pyLDAviz for The Iron Throne highlights the fans saying good-bye to the series

总的来说,我们了解到社交媒体上的帖子很难解读,因为它们充满了情感和讽刺。《权力的游戏》这部剧承载了很多粉丝的希望,任何结局都可能让他们失望。

《权力的游戏》为奇幻类型进入主流媒体铺*了道路,并为流行奇幻小说的其他高预算改编打开了大门。我们已经走到了一个时代的尽头,这是一段令人惊叹的旅程。

上面分析的所有可视化和代码都可以在这里找到:

[## natashaborders/Game _ of _ Thrones _ 情操 _ 分析

我们使用自然语言处理来检查粉丝对该系列最后一季的反应'。然后进一步…

github.com](https://github.com/natashaborders/Game_of_Thrones_Sentiment_Analysis)

请随时在 LinkedIn 或 Twitter 上找到我,进行《权力的游戏》聊天:

[## Natasha Borders,MBA -数据科学家- Metis | LinkedIn

加入 LinkedIn 数据科学家,具有市场研究和品牌管理、CPG、pet 和沉浸式活动的背景…

www.linkedin.com](https://www.linkedin.com/in/natashaborders/) [## 娜塔莎(@natalissaelil) |推特

娜塔莎的最新推文(@natalissaelil)。数据科学家|分析师。加利福尼亚州旧金山

twitter.com](https://twitter.com/natalissaelil)

《权力的游戏》Twitter 情绪与谷歌云*台和 Keras

原文:https://towardsdatascience.com/game-of-thrones-twitter-sentiment-with-keras-apache-beam-bigquery-and-pubsub-382a770f6583?source=collection_archive---------12-----------------------

具有 AI *台、Apache Beam / DataFlow、BigQuery 和 Pub/Sub 的端到端管道

Photo by Tyler Lastovich on Unsplash

《权力的游戏》的最后一季显然引起了很多人的关注,所以我想通过转向从不轻声细语的 Twitter 社区,更深入地了解人们在《权力的游戏》最后一集之前、期间和之后的感受。

在这篇博文中,我们将看看如何利用谷歌云*台上可用的技术栈来构建一个端到端的解决方案来解决这个问题。

我们走吧!

source: created Blackbringer on GIFER (source)

重点是实现一个完全可行的解决方案,而不是完善整个流程中的单个组件。所以任何一个单独的积木都可以被完善!

为了保持可读性,我没有包括所有的代码,但一切都可以在 这个 Github repo 上找到,完全注释。

基本思想

整个管道的大致轮廓如下:

general architecture (source: own creation)

基本上,想要做到的是:

  1. 在虚拟机上运行一个脚本,抓取《权力的游戏》上的推文
  2. 有一个发布消息的发布订阅主题
  3. 有一个服务的 ML 模型来分类推文情绪
  4. 让阿帕奇波束流管道提取推文并分类
  5. 将分类的推文输出到 BigQuery,进行分析

在这篇文章的其余部分,我们将分别浏览所有不同的组件,以一个和谐的管道富矿的大型管弦乐队来结束!

我们将非常依赖谷歌云*台,包括以下组件:

  • 计算引擎:在上运行 tweepy 脚本
  • Cloud PubSub:缓冲推文
  • 云数据流:托管 Apache Beam runner
  • 人工智能*台:通过 API 服务于我们的 ML 模型
  • BigQuery:存储我们的推文

1.GCE 上捕获推文的脚本

Google Compute Engine logo (source)

使用 tweepy API 可以很容易地捕获与几个搜索词相关的推文,如下所示:

要将其发送到 Google Cloud PubSub,我们只需使用客户端库:

这样做之后,事情就简单了:

  • 在 Google 计算引擎上设置虚拟机(我使用了一个简单的 n1-standard-1)
  • 将脚本复制到 Google 云存储的一个存储桶中
  • SSH 到虚拟机
  • 将脚本从存储桶复制到环境中
  • 在虚拟机上安装 python3
  • 运行 python 脚本

2.作为消息代理的云发布主题

Google Cloud PubSub (source)

Pub/Sub 是一个很棒的消息中间件,它充当整个管道中的事件接收和交付系统。

特别是在这种情况下,推文的流入速度可能会比流媒体管道获得推文的速度快得多,这是一个很好的工具,因为接收和交付是异步解耦的。

Pub/Sub 还可以将收到的消息存储几天,因此,如果您的下游任务难以跟上,也不用担心。

创建一个主题非常简单:只需导航到你的 GCP 控制台,进入发布/订阅菜单:

PubSub console UI (source: own screen-capture)

从这里开始,只需点击创建主题按钮,并为您的主题填写一个名称。为了将来参考,我把我的命名为“got_tweets”。

3.人工智能*台上的服务 ML 模型

Google Cloud ML Engine (source)

对于收到的每条推文,我们想要确定所表达的情绪(大概是对该集的)是积极的还是消极的。这意味着我们必须:

  • 寻找合适的数据集
  • 训练一个机器学习模型
  • 服务于这个机器学习模型

资料组

当想到情感分析时,我们很快就会想到“IMDB 电影评论”数据集。然而对于这个特定的目的,这个经典似乎不太适合,因为我们在这里处理的是 tweets。

幸运的是,包含 160 万条带标签(正面和负面)推文的 Sentiment140 数据集似乎非常适合这种情况。更多信息和数据集,请访问这个视频页面。一些例子:

sample from the Sentiment140 dataset

对文本的预处理是在一个单独的类中完成的,这样以后调用模型时可以重用它:

模型

对于分类模型本身,我基于 2014 年著名的 Yoon Kim 关于多频道 CNN 文本分类的论文(来源)。为了便于开发(以及以后的部署),我使用 Keras 作为高级 API。

CNN architecture overview (source)

基于 CNN 的模型提供了额外的好处,即在我的小型本地工作站(NVidia GTX 1050Ti,4GB 内存)上训练该模型仍然是可行的。而基于 RNN 的模型(通常用于情感分类)将具有长得多的训练时间。

我们可以尝试通过加载一些预训练的单词嵌入来给模型增加一些活力。在这种情况下:Glove 2.7B Twitter 嵌入看起来是一个不错的选择!

完整的代码可以在这本笔记本中找到。

我们为 25 个时期训练了模型,其中有两个 Keras 回调机制:

  • 当确认损失达到稳定水*时,回调以降低 LR
  • 当验证损失在一段时间内没有改善时,提前停止回调,这导致它在 10 个时期后停止训练

这里可以看到训练和测试曲线:

因此我们获得了大约 82.5%的准确度。

为模型服务

人工智能*台为机器学习模型提供了一个可管理的、可扩展的服务*台,其中内置了一些很好的好处,如版本控制。

现在对于主机来说,我们的模型有一个特殊的方面,这使得它在人工智能*台中的服务变得不那么微不足道:事实上,我们需要以我们在训练时所做的相同方式来规范化、标记化和索引我们的文本。

尽管如此,还是有一些选项可供选择:

  • 将 tf.keras 模型包装在一个 tf 模型中,并添加一个 Hashtable 层来保持标记化 dict 的状态。更多信息在这里。
  • 全力以赴,为您的数据实现一个 tf.transform 预处理管道。关于这个的伟大博客文章在这里。
  • 稍后在流管道本身中实现预处理。
  • 使用 AI *台 Beta 功能,拥有一个自定义模型预测类。

鉴于既没有时间也没有资源来完成 tf.transform,而且用额外的预处理可能会使流管道过载,这似乎是一个糟糕的选择,最后一个看起来是可行的。

轮廓看起来像这样:

overview of the serving architecture (source: own creation)

自定义模型预测类非常简单,Google 的 peeps 在这里有一个很棒的博客。我的看起来像这样:

要由此创建一个人工智能服务*台模型,我们只需:

  • 打包自定义预测和预处理。py 文件
  • 将这个包连同持久模型和预处理类实例一起上传到 bucket
  • 从这里开始,创建一个你想命名的模型
  • 在这个模型中,基于上传的项目创建一个新版本,并使用一些测试版魔法:

4.阿帕奇光束流管道

Cloud Dataflow (source)

推文以流的形式出现,这实际上是一个无限的数据集。因此,流管道似乎是从发布/订阅主题中捕获 tweets 并处理它们的完美工具。

我们将使用 Apache Beam 作为编程模型,并在 data flow runner(Google Cloud 上用于运行 Beam 管道的托管环境)上运行管道。如果你想了解更多关于 Apache Beam 及其范例的内容,可以访问网站。

首先,在流式传输时,我们必须考虑窗口策略。这里,我们只使用 10 秒的固定窗口。

Fixed windowing strategy (source)

也可以采用其他策略,例如移动窗口策略。这可能会导致对托管 ML 模型的额外调用。所以固定窗口似乎是最容易开始的。

我们管道中的主要步骤是:

  • 以 10 秒为间隔拉入发布/订阅消息
  • 将它们分批,每批 50 条消息(不要太大,否则请求的正文会太大)
  • 通过调用托管的 ML 模型对它们进行分类
  • 将它们写入 BigQuery 集合
  • 同时,对这 10 秒钟的*均情绪进行分组,并将其写入第二个 BigQuery 集合

在云数据流上运行时,它看起来如下:

screen capture of the created dataflow pipeline

完整代码粘贴在这里有点长,不过可以在 我的 Github repo 上找到完整的。

5.有一个 BigQuery 集合来接收结果

BigQuery (source)

如前所述,我们有两个 BigQuery 表来将结果流式传输到:

  • 一个是单独的帖子,带有情感标签,将来可能会重新标记它们,并微调我们的分类器
  • 一个用于每 10 秒窗口的*均预测情绪

screen capture of the created dataset and tables

您可以从 UI 中创建它们,并指定一个模式(当然,该模式必须映射到您的 Beam pipeline 作业中指定的模式)。

跑步

我花了几个小时运行整个管道,以捕捉这一集之前、之中和之后的情绪。

鉴于 tweets 的数量可能会很快变得相当大,观察所有组件的扩展能力也是很好的:

  • 人工智能*台:这个故事中真正的 MVP,当负载增加时,在后端扩展得非常好,试图保持响应时间稳定:

Requests per second for calls to AI Platform model

Response times during the run, nice n’ stable

  • 云数据流:事后看来,Java 流感觉比 Python 流更扎实一点。当流式传输 Python 管道时,自动缩放当前不工作;这导致系统延迟时间在整个运行过程中不断增加:

System delay (in second, right hand side axis)

  • BigQuery :完全不是问题。BQ 使用流缓冲区操作,并定期将数据卸载到表本身。同样对于后期分析,BQ 从来都不是问题。

在 7 个小时的时间里,总共收集了大约 50 万条推文。下面是一些例子,以及他们预测的情绪(警告:剧透警报!)

(source)

结果呢

至于主要问题,我们可以试着把它框定为:

每分钟在推文中表达的*均情绪是多少。在发作前、发作中和发作后的一小时内。

通过一些 SQL 查询魔术(参见回购中的笔记本),再加上一些注释,就足够简单了:

  • 分数被标准化为*均值 0 和标准偏差 1
  • 移动*均和原始*均情绪都被显示
  • 提到了该剧的一些关键场景

👉所以很明显,社区在节目开始前对 GoT 非常敌视,在剧集开始时逐渐放下了他们的干草叉和火把。

👉可以这么说,布兰被封为国王很受欢迎,我也认为这是一个非常好的情节转折😃!

👉另一个积极的场景是塔斯的布蕾妮在《骑士书》中写詹姆的时候。

👉在这一集之后,社区似乎对最后一集相当消极,大约 45 分钟后,在再次变得消极之前,他们改变了主意…

他们最终对这一集相当负面,这似乎反映在 IMDB 评分只有 4.4 分😮。有人可能会说,这一集没有机会,因为社区在这一集之前就已经相当负面了,所以这种情绪多少是从不利的偏见开始的。

这是事实吗?没有人确切知道,但我对结果很满意👍。

(source)

所以我们有它!使用谷歌云提供的工具箱来回答我们的问题。仅供参考:手术的总成本最终大约为 5 美元,我认为这是相当合理的!

博弈论——历史和概述

原文:https://towardsdatascience.com/game-theory-history-overview-5475e527cb82?source=collection_archive---------15-----------------------

什么是博弈论&为什么它与今天相关?

Published On Setzeus

生活就是生存&生存就是竞争。每当两个或两个以上的实体面临限制,如固定数量的资源,在赢/输的情况下,竞争就出现了。这是必然的&自然的。从生态系统中的食物链*衡来看,这是一种进化——当然,这种天生的行为同样适用于人类。任何形式的竞争都源于战略。

博弈论是应用数学的一个分支,用于创建最佳策略,以便在不确定和知识不完整的竞争环境中取得成功(就像大多数现实生活场景一样)。这是在所有行业和学科的日常生活中发现的冲突情况下决策和建模的数学研究。

Published On Setzeus

国家为领土而战,企业为市场份额而战,动物为资源而战,政党为选票而战。在一个由相互依赖的代理人统治的世界里,这些代理人旨在增加他们在动态系统中的“价值”,博弈论有着极其密切的关系。

虽然这一学术学科&这一领域本身在 20 世纪 50 年代才正式建立,但博弈论般的见解在数百年的历史中清晰可见。下面,我们将回顾古代的背景& 20 世纪 50 年代的加速发展。

古代

事后看来,博弈论的基本思想在历史上多次出现。从《孙子兵法》到查尔斯·达尔文的进化发现,它一直是人类行为的驱动力。然而,古代博弈论的基础通常归功于以下三部具体著作的流行:

  • 奥古斯丁·古诺的研究财富理论的数学原理
  • 弗朗西斯·伊西德罗·埃奇沃思笔下的数学灵媒
  • 埃米尔·波莱尔的算法和概率计算,

这些经典著作中的每一部都简要地窥视了博弈论的未来;他们每个人都站在(他们那个时代的)知识的边缘&试图用数学来描绘一些背景下(比如财富)的人类行为。尽管如此,正如上文所详述的,这些都只是学科在阴影中前进的低语——该领域直到 20 世纪 50 年代才获得正式认可。

巨人队——诺伊曼和纳什

虽然许多贡献者在博弈论的历史中占有一席之地,但人们普遍认为现代分析始于约翰·冯·诺依曼,并由约翰·纳西进一步提供了其方法框架。

很可能博弈论在约翰·冯·诺依曼第一次在战略 (1928 年)的 博弈论 上发表论文之前并没有名字。虽然不是他的巨著,但这篇论文极大地推进了这个领域——它的意义最好通过回顾博弈论中提出的**基本定理来理解:****

博弈论的基本定理表明,在两人游戏的大类中, 总是有可能 找到一个双方都不应该单方面偏离的均衡。这种均衡存在于任何满足以下标准的双人游戏中:

  1. 游戏是有限的
  2. 游戏之一完整信息
  3. 这是一个零和游戏

今天被称为极大极小定理,它仍然非常相关&是任何博弈论 101 课程的关键部分。然而,诺伊曼的下一篇文章是&仍然是博弈论的圣杯。

Published On Setzeus

博弈论与经济行为 ,由约翰·冯·诺依曼&经济学家奥斯卡·莫根施特恩于 1944 年出版,被认为是将博弈论正式确立为一个跨学科研究领域的开创性文本。事实上,在该书 60 周年纪念的介绍中,普林斯顿大学出版社将其描述为“现代博弈论所基于的经典著作”

第二个浪子回头的人不是别人,正是《美丽心灵》的约翰·纳西。作为诺贝尔奖获得者,约翰·纳西声称博弈论的名声来自于扩展诺依曼先前定义的 两人 博弈均衡。纳什均衡被称为&适用于更多种类的游戏,纳什证明了非零和博弈中的每一个有限的 n 人(不仅仅是 2 人零和博弈)都有一个明确定义的最优策略。

最后—基础知识&囚徒困境

在诺依曼和纳什的肩膀上,博弈论凶猛地推进到所有的行业和学科。在 50 年代早期,一连串的活动导致了进一步的发展(重复博弈& Shapley 值)以及最初的应用(见于哲学和政治学)。将* 70 年后,博弈论仍然非常活跃。

我们走吧!我们探索了应用&浏览了博弈论的历史。现在自然的下一步是用一个例子来说明。在应用数学的这个角落里,“囚徒困境”是最受关注的经典博弈论问题。为了边做边学,我们接下来会解决这个问题。