TowardsDataScience-博客中文翻译-2021-二十六-

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

TowardsDataScience 博客中文翻译 2021(二十六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

意甲(足球)——带有 Plotly 和 Dash 的简单仪表盘

原文:https://towardsdatascience.com/create-a-simple-dashboard-with-plotly-dash-8f385ba1dd6d?source=collection_archive---------27-----------------------

自从上次我使用意甲数据并用 Plotly 创建了一些图表(通过下面的链接查看文章),我想我应该更进一步,尝试创建一个仪表板,这样我就可以在一个页面上显示所有有趣的图表——这就是今天更新的开始。

照片由达维德·扎维亚在 Unsplash 上拍摄

先决条件:

类似前面文章提到的步骤,玩数据前的第一件和两件事是:获取数据清理数据。

当前项目使用的数据来自 Kaggle,提供 Massimo Belloni 。https://www.kaggle.com/massibelloni/serie-a-19932017

运行几行代码来组合来自不同 csv 文件的所有数据:

# Import the packages for data cleaning:
import pandas as pd
import glob
import numpy as np# Setup the file path & get all files
path = r'....\SerieA'
all_files = glob.glob(path + "/*.csv")table = []for filename in all_files:
    data = pd.read_csv(filename, index_col=None, header=0)
    table.append(data)frame = pd.concat(table, axis=0, ignore_index=True)#Only use the first eight columns
df = frame.iloc[:,0:7]

我还为接下来的可视化添加了几列:

# Identify the winner:
df['Winner'] = np.where(df['FTR'] == 'H',df['HomeTeam'],
                          np.where(df['FTR'] == 'A', df['AwayTeam'], "Draw"))# Identify if the winner is home team or away team:
df['Result'] = np.where(df['FTR'] == 'H','HomeTeamWin',
                          np.where(df['FTR'] == 'A', 'AwayTeamWin', "Draw"))# The year of the match:
df['Year']=pd.DatetimeIndex(df['Date']).year

我将清理后的数据保存到文件夹中,这样我下次就可以轻松地使用它,而不用再次运行上面的代码:

df.to_csv('seriearaw.csv')

准备好图表:

对于这个控制面板,我希望有四个图表—两个饼图、一个树状图和一个折线图。

# get the right package:
import plotly.express as pxchart1 = px.pie(df, values =df.groupby('Result')['Result'].count(),
               title='Serie A - results from 1993 - 2017',
                height = 500)
chart1.update(layout=dict(title=dict(x=0.5)))

图 1

chart2 = px.pie(df, values = df.groupby('Winner')['Winner'].count(),title = "Serie A Result from 1993 - 2017 - Most Win Team", height = 500)chart2.update(layout=dict(title=dict(x=0.5)))
chart2.update_traces(textposition='inside', textinfo='percent')

图 2

chart3 = px.treemap(df, path=['Winner'], values = 'TotalGoal',height = 500, title = "Serie A Result from 1993 - 2017 - Most Win Team")chart3.update(layout=dict(title=dict(x=0.5)))
chart3.update_traces(textinfo = 'label + value')

图 3

# Create a different dataframe for chart4:
total_goal =df.groupby('Year')['TotalGoal'].agg('sum').reset_index(name ='Sum')
total_goal = total_goal[(total_goal.Year != 2017) & (total_goal.Year != 1993)]chart4 = px.line(data_frame = total_goal, x ='Year', y = 'Sum', title = 'Total Goals by Year',
              line_shape = 'spline',height=500)
chart4.update(layout=dict(title=dict(x=0.5)))
chart4

图 4

设置仪表板:

:构建仪表板需要三个包:

import dash# html is used to set up the layout, and dcc is used to embed the graphs to the dashboard:
import dash_core_components as dcc
import dash_html_components as html

样式:当前仪表板采用了外部表的样式。我的理解是,你非常欢迎创造自己的风格,但为了使起点更容易,有一些模板可用。

# Setup the style from the link:
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']# Embed the style to the dashabord:
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

嵌入图表:为了将我们刚刚创建的四个图表嵌入 dash,我们使用 dash_core_components 包。我们还在这里设置了这些图表的布局。

请不要在这里使用“ className ”,它用于定义图表看起来有多大。想象一下,一个仪表板页面可以平均分为 12 列,如果一个图形等于“四列”,这意味着该图形将是仪表板的三分之一(4/12)宽。在下面的代码中,我们用 graph 1–3 表示 4 列,用 graph4 表示 12 列。猜猜仪表盘长什么样?

graph1 = dcc.Graph(
        id='graph1',
        figure=chart1,
        className="four columns" 
    )graph2 = dcc.Graph(
        id='graph2',
        figure=chart2,
        className="four columns"
    )graph3 = dcc.Graph(
        id='graph3',
        figure=chart3,
        className="four columns"
    )graph4 = dcc.Graph(
        id='graph4',
        figure=chart4,
        className="twelve columns"
    )

定义每个图表的样式后,我们定义这些图表在仪表板中的位置。从上面的代码中,您可能会发现,我们将把 graph1、2 和 3 放在一行,而把 graph4 放在另一行:

# setup the header
header = html.H2(children="SerieA Dataset Analysis")# setup to rows, graph 1-3 in the first row, and graph4 in the second:
row1 = html.Div(children=[graph1, graph2, graph3],)
row2 = html.Div(children=[graph4])# setup & apply the layout
layout = html.Div(children=[header, row1, row2], style={"text-align": "center"})
app.layout = layout

酷,我们已经创建了图表并设置了仪表板布局,最后一步是运行应用程序,看看您的仪表板看起来如何:

if __name__ == "__main__":
    app.run_server()

请注意,我在这个项目中使用的是 jupyter notebook,这些代码可以很好地使用它。当我在看其他一些文章时,他们用“app.run_serviver(debug = True)”来运行仪表板,但这对我不起作用。

这就是这个简单仪表板的最终外观!玩得开心!

参考:https://coderzcolumn . com/tutorials/data-science/build-dashboard-using-python-dash-plotly-and-deploy-online-python anywhere

为你自己和你的伴侣或朋友创建一个 Spotify 播放列表

原文:https://towardsdatascience.com/create-a-spotify-playlist-for-yourself-and-your-partner-or-friend-8c224e3775d1?source=collection_archive---------29-----------------------

实践教程

使用 spotify 库创建一个版本的 Spotify Duo Mix

照片由海蒂·芬在 Unsplash 上拍摄

Spotify 提供阿朵订阅,附带一个名为 Duo Mix 的独特播放列表。这个播放列表是为两个用户准备的,结合了他们的音乐品味。

我女朋友和我都很想看看这个播放列表是关于什么的。我们开始听,但不知何故感觉有点不对劲。艺术家是“正确的”,但歌曲不是,播放列表几乎没有我们两人实际听过的歌曲。它也很难在不同风格之间转换,从一首冰冷的爵士歌曲变成了电子乐、说唱或金属核心(好吧,这可能对我来说也有点……)。我们不满意,也不再听播放列表中的每周更新。然而,我喜欢这个想法,并认为一定有一种方法来创建我们都希望的播放列表。

所以我决定自己创建一个播放列表,但不是手动的,因为我想每周更新。我首先想到使用机器学习和其他更复杂的方法,但后来我提醒自己,我有一个需要工作解决方案的问题。如果问题不需要,我们的目标不是尝试新的机器学习算法。

我的目标是:

  • 包括一些我们最喜欢的歌曲以及我们最近都喜欢的歌曲
  • 包括基于这些收藏夹的新歌
  • 限制一位艺术家的歌曲数量
  • 基于共同喜欢的音乐创造整体的聆听体验,而不仅仅是提供个人品味的混合

我最终得到了一个可行的解决方案,但没有使用机器学习,它实际上只是一点数据争论,通过相似性度量对 Spotify 的推荐进行一些提炼,还有一点随机性。但它很有效,我们对目前的播放列表很满意,并将继续改进它,可能通过机器学习。如果有我们喜欢和不喜欢的歌曲的数据,一个训练有素的模型可以改善一切。

准备创建播放列表

获取数据

我开始使用我已经创建的 Spotify 应用程序,并通过该应用程序验证我们的帐户。如果你不确定如何做这些事情,看看我之前的文章带你完成这个过程。

我首先为我们两个查询以下数据:

  • 长期、中期和短期顶级艺术家
  • 长期、中期和短期的顶部跟踪
  • 和一些保存的用户曲目(最近 50 首)

我使用了下面的函数,它实际上只是组合了一堆查询并产生了三个数据帧。

请注意,我在这里调用我编写的函数,是为了将 Spotify API 查询结果转换成可用的数据框架。我不会在这里一一细说。一些在我关于 Spotify 的另一篇文章中(见上文)。你可以在 Github 上找到完整的代码(查看所有功能,请参阅 spotifuncs.py)。

第一个重要的数据是用户的所有热门曲目,我把它们合并成一个完整的热门曲目列表,涵盖了从短期到长期的所有热门曲目。请注意,我只从长期顶级曲目中抽取了 15 首歌曲,这样做而没有设置随机种子,而不是在每次运行代码时得到相同的结果。在这个过程中,总是使用长期收藏的完整列表会导致在几周的时间里重复太多,从而导致播放列表的重复。

第二个重要的部分是顶级艺术家的数据,就像所有时间帧的曲目一样。艺术家对以后的过滤过程很重要。

最后,我还检索了用户保存的最新 50 首曲目。这里 50 是上限,这很不幸,因为这实际上限制了数据的使用。

上周播放列表

为了避免连续两周遇到相同的歌曲(这很可能是因为短期和中期的热门歌曲不会有太大变化),上周的播放列表是从“Playlist.csv”中读取的。这个文件只是一个空的。我第一次运行代码的时候。但是在播放列表创建过程结束时,新创建的播放列表会保存在其中。csv 文件,所以它包含上周的播放列表。我用了其中的数据。csv 文件,用于在该过程的各个阶段为新的播放列表过滤歌曲。

建立播放列表

创建播放列表需要几个步骤来“组装”组成它的所有构件。这些是:

  1. 上周播放列表中没有的常见热门曲目
  2. 每个用户与其他用户的顶级曲目最相似的顶级曲目的示例
  3. 每个用户都喜欢的艺术家(他们的顶级艺术家之一)的顶级曲目样本
  4. 用户保存的歌曲示例
  5. 步骤 1 中添加到播放列表的每首曲目的推荐曲目(通过 Spotify API 和附加过滤)。-4.

公共顶部轨道

播放列表是由常见的热门曲目启动的,上周的播放列表中还没有出现这些曲目。因为这些歌曲都是用户的最爱,理论上他们应该喜欢。

我创建了一个数据框架,通过查找出现在两个用户的顶级曲目数据框架中的曲目来查找常见的顶级曲目。这可以通过多种方式来实现,我使用了以下函数进行所有数据帧的比较:

只有在上周的播放列表中没有出现的常用热门曲目才会被添加到播放列表中。

用户最喜欢彼此相似的曲目

下一个构建块由来自两个用户的顶级曲目的歌曲组成,这些歌曲在音频特征的水平上彼此最相似。

对于这个任务,提取每个用户唯一的顶部轨迹,并计算相似性矩阵。相似度基于音频特征(不包括“调”和“模式”),并通过余弦相似度进行计算(请参见 spotifuncs.py 中的 create_similarity_score())。从该矩阵中,提取 30 个最高相似性得分和相应的指数。对应于这些索引的歌曲被放入数据帧中,任何重复的被丢弃,并且为新的播放列表抽取 10 首歌曲的样本。

普通顶级艺术家

下一步根据普通艺术家过滤热门曲目。我试图找到共同的艺术家(在 2 个用户中),然后通过这些艺术家过滤他们的热门歌曲。这背后的逻辑如下:
一首曲目可能仅在一个用户的“热门曲目”中,然而,它可能是由两个用户都喜欢的艺术家创作的。在这种情况下,该曲目是双人播放列表的良好候选,因为两个用户都可能会喜欢它,但它可能是其中一个用户的新发现。如果双方都已经知道并喜欢它:仍然是一个很好的播放列表适合!

潜在问题

对我来说,这种过滤方法经常导致歌曲列表只包含很少的艺术家,而是该艺术家的几首歌曲(这也是因为 Spotify 真的注意到了你何时无法停止听一张专辑..).为了在新的播放列表中没有太多同一艺术家的歌曲,我从数据帧中取样。为此,我根据艺术家出现的频率为行分配权重,然后从两个数据帧中取样。
这种方法工作得相当好,但是仍然有一些缺陷(这可能部分是由我的倾听行为造成的)。

从存储的轨道采样

在创建播放列表时,我的目标是大约 25 首已知曲目(以及 25 首推荐的新歌)。为了实现这一点,并以某种方式考虑到前面步骤的随机性质,我在最后一步用采样保存的曲目填充播放列表。对于这一步,我还要确保没有一首抽样歌曲已经出现在上周的播放列表中。

从 Spotify 推荐中添加新曲目

在这最后一步,我添加了新的曲目来填充播放列表的另一半。

不想简单地添加 Spotify 根据歌曲推荐的歌曲,这些歌曲已经在播放列表中了。因此,获得 Spotify 推荐只是第一步。我正在检索每首歌曲的多首歌曲推荐,然后根据相似性评分再次过滤。

不幸的是,Spotify API 不接受 25 首种子曲目用于推荐查询,因此,我最终将该过程分成 5 首种子曲目的“包”,每个“包”检索 25 首曲目。这 125 个推荐通过它们与播放列表中已知曲目的相似性被进一步过滤。

播放列表完成了!

现在剩下唯一要做的就是将曲目添加到播放列表中(在播放列表描述中添加一张漂亮的图片并感谢你的伴侣的耐心不是可选的)。

我希望你能以此为灵感,为自己和他人建立一个播放列表。我也希望你发挥创造力,找到解决这个问题的其他方法。让我知道你造了什么!

附注:我故意跳过了一些代码,以保持文章的合理长度,如果你想看,都在 Github 上。

-梅林

https://ms101196.medium.com/membership

创建一个网上冲浪应用程序

原文:https://towardsdatascience.com/create-a-surfing-web-app-34da6201f57e?source=collection_archive---------34-----------------------

python 如何帮助你找到完美的冲浪板

在 Unsplash 上由 NICO BHLR 拍摄的照片

企业支付天文数字的数据,以确保他们领先竞争对手一步。有了免费的数据集,特别是关于最理想的冲浪板,冲浪就意味着商业,对吗?

什么是 Python Web App?

Python web 应用程序是一个网页,其中的指令/动作是使用 Python 编程创建的。例如,以下代码片段创建了一个下拉选项,用户可以在其中选择多个波高作为过滤器:

wave_height = st.sidebar.multiselect(**"Wave height"**, df[**'wave_height'**].unique())
st.write(**"Wave height selected"**, wave_height)

这是一种创造性的方式来展示您的 python 脚本可以做什么,而不需要其他人在他们的计算机上安装 python-他们所需要的只是互联网连接。

虽然 python 有助于定义您在 web 应用程序上的操作,但 web 框架会处理细节。这就是 细流 的用武之地。 Streamlit 为您设计仪表板。

“Streamlit 可在几分钟内将数据脚本转化为可共享的 web 应用。
全部用 Python。全部免费。不需要前端经验。”— 细流公司,2021 年

本教程将使用 Streamlit 作为 web 框架的选择,但是,理解其他选择也是有好处的

Web 框架

用于使用基于 Python 的编程来构建 web 应用的流行 web 框架包括: Dash StreamlitVoilaFlaskDjango

Flask 是一个没有数据分析能力的 web 框架。它更像是一个“从零开始建造”的工程工具,允许更多的定制。它更擅长构建较小的定制应用和网站,如 Reddit 和 Airbnb。而 Django 则致力于帮助创建流量更大的复杂网站,如 Spotify 和 Instagram。

Flask 是一个 web 框架的情况下, StreamlitDash 将例如在 Flask 上运行,因为它们被认为是“仪表板工具”。 Streamlit 是向利益相关者展示“价值证明”的绝佳方式,而 Dash 则是在您需要将仪表板投入生产并供公司使用的情况下。

如果你在 Jupyter Notebook 中编写代码,并希望在网页上显示你的发现,那么你可以使用像 Viola 这样的插件。Streamlit 还不能在 Jupyter 笔记本上使用,但是可以运行你的。例如 PyCharm 中的 py 文件。

在选择了最适合的 web 框架之后,你还需要选择一个 web 服务器来托管你的网站,这里有各种免费和付费的选项。

一个流行的例子是谷歌应用引擎,它是在你的谷歌云项目下创建的。其他受欢迎的云提供商包括亚马逊网络服务(AWS) 和微软 Azure 。

这里的是比较这三种云服务的备忘单:

(崔佛·琼斯,2020,来源)

工作示例

数据

你可以从 kaggle (作者:【洛雷罗】 ) 下载我在这个工作示例中使用的公开可用的数据集。 df_surf.csv 数据集是由冲浪者回答的在线调查。每一行代表一个单独的冲浪者,每一列代表回答的问题。这些问题涉及冲浪板、波浪、冲浪者、操作和冲浪者的表现。

创建您的项目

通过在 PyCharm 中创建新项目,它将为您创建一个‘main . py’文件。将 df_surf.csv 保存在与此 main.py 文件相同的位置。您可以重命名。py 文件,但是要确保修改我的代码来导入您重命名的文件。

在 PyCharm 终端中,安装以下软件包:

pip install streamlit
pip install pandas
pip install numpy

main.py 脚本中,插入以下代码,并查看我的注释。如果你是 Streamlit 的新手,[这里的](https://share.streamlit.io/daniellewisdl/streamlit-cheat-sheet/app.py #streamlit #python)是一张可以在 streamlit 网站上找到的备忘单,由 Daniel Lewis 于 2021 年创建。

#import the packagesimport pandas as pd
import numpy as np
import streamlit as st*#import the dataset and create a checkbox to shows the data on your website*
df1 = pd.read_csv(**"df_surf.csv"**)
if st.checkbox(**'Show Dataframe'**):
    st.write(df1)#Insert some sentences in markdown format**'''
# Surfing App
'''**#Read in data again, but by using streamlit's caching aspect. Our whole app re-runs every time we make small changes, which is infeasible the more complicated our code becomes. So this is the recommended way to import the data.df = st.cache(pd.read_csv)(**"df_surf.csv"**)#create side bars that allow for multiple selections:age = st.sidebar.multiselect(**"Select age"**, df[**'surfer_age'**].unique())
st.write(**"Age selected"**, age)weekly_surfs = st.sidebar.multiselect(**"Surfer Exercise frequency"**, df[**'surfer_exercise_frequency'**].unique())
st.write(**"Frequency selected"**, weekly_surfs)surfer_experience = st.sidebar.multiselect(**"Surfer Experience"**, df[**'surfer_experience'**].unique())
st.write(**"Experience selected"**, surfer_experience)surfer_gender = st.sidebar.multiselect(**"Surfer Gender"**, df[**'surfer_gender'**].unique())
st.write(**"Gender selected"**, surfer_gender)wave_height = st.sidebar.multiselect(**"Wave height"**, df[**'wave_height'**].unique())
st.write(**"Wave height selected"**, wave_height)board_type = st.sidebar.multiselect(**"Board Type"**, df[**'board_type'**].unique())
st.write(**"Board type selected"**, board_type)#create a sidebar to select the variable output you want to see after making your multiple selectionsvariables = st.sidebar.multiselect(**"Select what you want to see for your selection"**, df.columns)
st.write(**"You selected these variables"**, variables)# return the sub-set data  of variables you want to seeselected_data = df[(df[**'surfer_age'**].isin(age))]
subset_data = selected_data[variables]
data_is_check = st.checkbox(**"Display the data of selected variables"**)
if data_is_check:
    st.write(subset_data)

在您的终端中,您将运行以下命令:

streamlit run main.py

终端中将出现以下内容:

作者图片

单击本地主机链接,您的 web 应用程序将在浏览器中打开:

作者图片

这就是了。您自己的网络应用程序,探索棋盘类型和策略。

结论

通过观察向这些冲浪者提出的一系列问题,你可以对实现特定动作所使用的冲浪板类型以及冲浪者的类型有所了解。一个从未在 5 英尺浪上做过削减的专业人士,还是一个用他/她的长板偷走所有乐趣的初学者?

本教程只是一个入门,但你可以添加更多的数据,可视化,甚至视频剪辑来丰富你的故事。但在那之前,现在是时候去得到那个完美的波浪了。

奥斯汀·尼尔在 Unsplash 上拍摄的照片

使用 Streamlit、MongoDB 和 Heroku 在 30 分钟内创建一个 Web 应用程序

原文:https://towardsdatascience.com/create-a-web-app-in-under-thirty-minutes-with-streamlit-mongodb-and-heroku-41f211953786?source=collection_archive---------5-----------------------

快速开发和部署可伸缩 web 应用程序的有志全栈开发人员指南

克里斯里德在 Unsplash 上的照片

曾几何时,创建 web 应用程序还是像马克·扎克伯格和埃隆·马斯克这样的神童的工作。或者,你可以进入一所名牌大学,用你生命中最好的四年时间(和你父母的退休储蓄)学习编程,然后最终开发出低于 90 年代风格的网络应用程序。从那以后我们已经走了很长一段路。随着开源工具和云基础设施的泛滥,开发和部署非凡的应用程序在很大程度上已经大众化了。老实说,做一名开发人员可能从来没有这么简单过,你所需要的只是一堆正确的工具,而且你可以胜任大多数工作。

我将向您介绍三个主要工具,我自己曾大量使用它们来开发前端用户界面、提供服务器端基础设施,以及最终将所有优点部署到 web 服务器上。在本教程中,我们将创建一个简单的工作推荐应用程序。用户将选择他们希望工作的国家,然后上传他们的简历。随后,该应用程序将分析上传的文件中的关键词,并将搜索公司数据库以找到最相似的匹配。在我们继续之前,我假设你已经精通 Python 和它的一些包,比如 Pandas 和 NLTK,并且你有一个 GitHub 帐户。

1.细流

Streamlit 是一个全新的 web 框架,它几乎填补了 Python 开发者的 web 开发空白。以前,人们必须使用 Flask 或 Django 将应用程序部署到 web 上,这需要对 HTML 和 CSS 有很好的理解。幸运的是,Streamlit 是一个纯粹的 Python 包,学习曲线非常浅,将开发时间从数周减少到了数小时,真的。虽然它被标榜为机器学习和数据科学应用程序的框架,但我发现这相当不光彩;事实上,许多人(包括我自己)已经使用 Streamlit 来炫耀令人眼花缭乱的通用应用程序。

在本节中,我将向您展示如何实时安装、构建和运行 Streamlit 应用程序。首先,在您的环境中安装 Anaconda 和 Streamlit。或者,您可以在 Anaconda 提示符下运行以下命令。

pip install streamlit

一旦解决了这个问题,继续打开您选择的 Python IDE,并在您刚刚下载 Streamlit 的环境中打开它。现在让我们创建一个简单的界面,用户可以选择他们想要工作的国家,也可以上传他们的简历。最初,我们需要导入所有包,如下所示:

除了 Streamlit 和 Pandas,我们还需要 pdfplumber 和 PyPDF2 来处理我们上传的简历。rake_nltk、nltk 和它们的相关单词库需要从简历文本中解析关键短语,io 需要将二进制简历文件转换成 Python 可读的解码形式。

随后,我们创建用户界面,为国家/地区添加文本输入,为简历添加文件上传程序,并通过多选单词框选择获得的关键短语,如下所示:

上面调用的函数“keyphrases”通过使用 nltk 库来分析简历文本以发现相关的关键字。该功能如下所示:

最后,我们将 Python 脚本保存在我们环境的目录中,并在 Anaconda 提示符下执行以下命令,以在本地运行我们的 Streamlit 应用程序:

streamlit run *file_name.py*

您会注意到 web 应用程序将被转发到您的本地主机端口:

[http://localhost:8501](http://localhost:8501)

现在,您应该看到以下内容:

简化页面。图片作者。

继续上传您的简历,生成如下所示的关键短语:

关键短语生成。图片作者。

Streamlit 的美妙之处在于,您可以实时更新您的代码,并即时观察您的更改。因此,您可以随时进行尽可能多的修改。

2.MongoDB

没有服务器端组件的 web 应用程序是不完整的,还有什么比 MongoDB 更好的学习与数据库交互的方法呢?虽然在这种情况下,我们的数据集是结构化的,并且使用像 MongoDB 这样的非关系数据库架构是多余的,但与所有可扩展的应用程序一样,在某种程度上,您可能会最终处理大量的非结构化数据,所以最好在一开始就进入正确的生态系统。更不用说 MongoDB 必须提供的一系列特性,比如全文索引和模糊匹配。

对于这个应用程序,我从 kaggle.com 下载了一个全球公司的公共数据集。我已经删除了它的一些属性,将数据集的总大小减少到 100 兆字节;请记住,MongoDB 提供了一个高达 512 兆存储的免费层集群。接下来,继续开设 MongoDB Atlas 帐户,然后注册一个组织和一个项目。随后在 AWS 的 US-East-1 区域建立一个名为“M0 沙盒”的免费层集群。这将确保我们有最小的延迟,因为我们的 Heroku web 服务器也将托管在同一地区。

构建 MongoDB 集群。图片作者。

选择 MongoDB 自由层集群。图片作者。

选择 MongoDB 集群区域。图片作者。

创建集群后,MongoDB 需要几分钟的时间来配置服务器。配置完成后,您需要将用于连接到集群的 IP 地址列入白名单。虽然出于明显的安全原因,我不推荐这样做,但是为了简单起见,您可以将所有 IP 地址列入白名单。从“安全”菜单中选择“网络访问”,如下所示:

配置 MongoDB 集群的网络访问。图片作者。

随后,选择“允许从任何地方访问”,并选择所需的时间范围,如下所示:

将 MongoDB 集群的 IP 地址列入白名单。图片作者。

接下来,您需要设置一个连接字符串来远程连接到您的集群。从“数据存储”菜单中选择“集群”,然后单击集群窗口上的“连接”,如下所示:

正在设置 MongoDB 连接。图片作者。

输入将用于连接到该群集的用户名和密码,如下所示:

为 MongoDB 集群访问选择用户名和密码。图片作者。

创建用户后,单击“选择连接方法”继续下一步,您应该选择“连接您的应用程序”,如下所示:

正在为 MongoDB 集群创建连接字符串。图片作者。

出现提示时,选择“Python”作为驱动程序,选择“3.6 或更高版本”作为版本。将为您创建一个连接字符串,如下所示:

MongoDB 连接字符串。图片作者。

您的连接字符串和完整的驱动程序代码应该是:

client = pymongo.MongoClient("mongodb+srv://test:<password>[@cluster0](http://twitter.com/cluster0).nq0me.mongodb.net/<dbname>?retryWrites=true&w=majority")
db = client.test

复制该字符串并用您在前面步骤中创建的实际密码替换''部分。

现在我们已经了解了 MongoDB 的所有逻辑,让我们加载数据集吧!选择集群中的“收藏”,然后点击“添加我自己的数据”。

将数据加载到 MongoDB 集群中。图片作者。

出现提示时,输入数据库和集合的名称以继续加载数据。请注意,MongoDB 中的“集合”与任何其他数据库中的表同义;同样,“文档”与其他数据库中的行相同。有多种方法可以将数据集加载到新创建的数据库中;最简单的方法是使用 MongoDB Compass 桌面应用程序,你可以在这里下载。下载并安装后,使用之前生成的连接字符串继续连接到集群,如下所示:

MongoDB 指南针桌面应用程序。图片作者。

MongoDB 指南针数据库。图片作者。

连接后,您应该能够找到您在前面的步骤中创建的数据库和集合。继续并点击“导入数据”将您的数据集上传到您的收藏中。一旦加载了数据,就需要创建一个全文索引,以便以后查询数据。全文索引实际上是对数据库中的每个单词进行索引;这是一种非常强大的索引形式,非常类似于搜索引擎所使用的。为此,您需要在互联网上导航回您的 MongoDB 集群,并在您的集合中选择“搜索索引”选项卡,如下所示:

在 MongoDB 中创建全文索引。图片作者。

单击“创建搜索索引”。这将通过以下窗口提示您,您可以在其中修改索引,但是,您可以通过单击“创建索引”继续使用默认条目。

在 MongoDB 中创建全文索引。图片作者。

既然已经配置了数据库、加载了数据集并创建了索引,您就可以在 Python 中创建查询函数,使用用户输入从数据库中提取记录,如下面的函数所示:

上面代码片段中的第一行建立了到数据库中集合的连接;请确保输入您的密码。或者,您可以将您的密码存储在一个配置文件中,并在您的代码中作为一个参数调用它,如果您希望更安全地处理密码的话。

为了查询您的 MongoDB 集合,您需要使用“聚合”特性,它只是 MongoDB 中的一个过滤管道。管道的第一阶段(\(search)是利用我们的全文索引的部分;这里,我们使用模糊匹配来匹配我们先前生成的简历关键短语和数据集中的“行业”属性。下一阶段(\)project)使用文档排名来按照分数降序排列匹配的查询。第三阶段(\(match)过滤掉不包含用户指定的国家的文档。最后一个阶段(\)limit)只是将返回结果的数量限制为 10 个。

既然我们已经整理了查询函数,我们需要在我们的 Streamlit 页面代码中再添加几行代码,以添加一个执行查询并显示搜索结果的搜索按钮,如下所示:

求职推荐网站。图片作者。

3.赫罗库

如果你已经做到了这一步,那么你会很高兴地知道你离完成只有几下鼠标的距离。多亏了 Heroku,将一个网络应用程序部署到云端只需点击几下鼠标。值得一提的是,Streamlit 开发了自己的【一键部署】选项,您可以将 GitHub 存储库与 Streamlit 集成,并免费部署您的应用。然而,问题是您的存储库需要是公共的,直到 Streamlit 发布其企业部署版本来迎合私有存储库,然后对许多人来说这将是一个交易破坏者。

在我们继续之前,您需要创建四个将与您的源代码一起部署的文件。

1.requirements.txt

您需要一个 requirements.txt 文件,其中包含 Heroku 需要为您的应用程序安装的所有软件包。这可以使用“pipreqs”包生成。在 Anaconda 提示符下键入以下命令来安装 pipreqs:

pip install pipreqs

然后把你的目录换成一个文件夹,只有包含你的源代码,其他什么都没有。

cd C:/Users/..../folder/

然后键入以下内容:

pipreqs

将使用以下软件包生成 requirments.txt 文件:

pymongo[tls,srv]==3.6.1
lxml==4.5.2
nltk
pdfplumber==0.5.24
pymongo==3.11.0
pandas==1.0.5
rake_nltk==1.0.4
streamlit==0.69.2
PyPDF2==1.26.0

2.setup.sh

setup.sh 文件告诉 Heroku 如何配置 Streamlit 应用程序,可以使用文本编辑器如 Atom 创建,并且必须以. sh 扩展名保存。

3.Procfile

类似地,Procfile 是一个配置文件,它告诉 Heroku 在启动时运行我们的源代码。它也可以用 Atom 文本编辑器创建,请注意它没有扩展名。

4.nltk.txt

nltk.txt 文件告诉 Heroku 使用哪个单词库。只需将以下内容添加到文件中,并确保使用文本文件的“LF”UNIX 格式保存它。

wordnet
pros_cons
reuters

准备好源代码和这四个文件后,将它们上传到一个私有的 GitHub 存储库中(以免公开任何密码)。然后去 Heroku 开个账户,如果你还没有的话。我们将使用免费的 Dyno 层,这足以部署一个实验性的应用程序。选择下面的“新建”按钮,继续创建新应用程序:

创建 Heroku 应用程序。图片作者。

出现提示时,输入您的名称,并选择“美国”地区。

创建 Heroku 应用程序。图片作者。

随后,选择“GitHub”部署方法和您的存储库,如下所示:

GitHub 与 Heroku 的集成。图片作者。

向下滚动到底部,选择存储库的正确分支,然后选择“部署分支”按钮来部署您的应用程序。Heroku 轻松构建您的应用程序时,请高枕无忧。完成后,假设没有错误,您将获得 web 应用程序的链接。鉴于你使用的是免费层,你第一次运行该应用程序将需要一段时间来曲柄启动。

由于您的 Heroku 帐户与 GitHub 集成在一起,您可以随时更新/修改您的代码,并像以前一样重新部署应用程序。有了 Heroku,你甚至可以设置自动操作,这样每当你的存储库更新时,应用程序就会自动重新部署。您还可以随时向 MongoDB 数据库添加数据,这些数据会立即反映在 web 应用程序中。因此得名“可扩展的 web 应用程序”。祝贺您使用 Streamlit、MongoDB 和 Heroku 部署您的 web 应用程序!

有用的链接

如果您想了解更多关于数据可视化、Python 以及将 Streamlit web 应用程序部署到云中的信息,请查看以下(附属链接)课程:

使用 Streamlit 开发 Web 应用程序:

https://www.amazon.com/Web-Application-Development-Streamlit-Applications/dp/1484281101?&linkCode=ll1&tag=mkhorasani09-20&linkId=a0cb2bc17df598006fd9029c58792a6b&language=en_US&ref_=as_li_ss_tl

使用 Python 实现数据可视化:

https://www.coursera.org/learn/python-for-data-visualization?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW2aEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

面向所有人的 Python 专业化:

https://www.coursera.org/specializations/python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW16Ewvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

使用 Streamlit 和 Python 构建数据科学 Web 应用程序:

https://www.coursera.org/projects/data-science-streamlit-python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgTzrEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

GitHub 资源库:

https://github.com/mkhorasani/JobMatch

新到中?您可以在此订阅和解锁无限文章。

使用 Merchant Center BigQuery exports 创建高级 Google 购物洞察

原文:https://towardsdatascience.com/create-advanced-google-shopping-insights-using-merchant-center-bigquery-exports-f81f65399a2c?source=collection_archive---------12-----------------------

利用产品级别价格竞争力需求和受欢迎程度数据,基于所有谷歌购物商家

亚采克·迪拉格在 Unsplash 上的原始照片

商品级别价格竞争力和基准数据,已经在商家中心界面提供,可以导出到 Google BigQuery。利用这些导出,您可以创建对产品目录的高级见解,这些见解也可以用于自动化。

在本教程中,您将学习如何:

  • 基于从 Google Shopping 上的所有商家到 Google BigQuery 的数据,导出产品和品牌层面的市场洞察数据
  • 使用商家中心的数据丰富您的产品信息,如价格竞争力相对需求产品排名来创建有价值的高级见解。
  • 使用示例查询将数据合并并加入到您的产品提要中。
  • 将出口用于其他实际用例。

注: 你喜欢这篇文章吗?阅读 原文 (以及其他许多动手营销技术相关文章)上【stacktonic.com】🚀

将商业中心连接到 Google BigQuery

第一步,你需要一个有效的计费帐户谷歌云项目。如果不存在,您可以查看这些说明。

官方的谷歌文档提供了在商业中心和谷歌大查询之间建立数据传输服务的所有信息。建立连接后,Merchant Center 将每天导出几份报告。

来源:谷歌

商户中心出口解释

传输服务可以导出几种报告类型。您不必导出所有报告(可以在设置导出时进行配置)。

要知道,以 GBs 来说,商业中心的出口并没有那么小。例如,对于每个可用的谷歌产品类别和国家,它将导出 10.000 个顶级产品。所以这可能会在你的谷歌云项目中产生一些成本。参见本文最后一章的提示。

最重要的出口;

另见 本概述 在谷歌官方文档中。

一些最有趣的性质和定义;

  • price_benchmark_value :特定产品的平均(点击加权)价格,基于所有在购物广告上宣传相同产品的商家。商家之间匹配产品是以 GTIN 为基础的。
  • 排名:该产品在购物广告、谷歌产品类别和国家级别上的受欢迎程度。受欢迎程度是基于销售产品的估计数量。排名每天更新,但导出的数据最多会延迟 2 天。
  • previous_rank :过去 7 天的排名变化。
  • 相对 _ 需求.最小/。max /。bucket :一个产品相对于在同一个类别和国家中具有最高流行等级的产品的当前估计需求。还包括桶(例如非常高)
  • 上一个 _ 相对 _ 需求.最小/。max /。桶:同上,只计算最近 7 天。
  • price _ range . min / price _ range . max:不含小数的价格范围下限和上限。不包括运费。

实际使用案例

结合不同的报告,您可以想到以下用例;

  • 产品反馈状态:获取与您的产品反馈相关的商家中心和购物错误及通知。
  • 产品库存优化:使用畅销书报告,你可以根据谷歌产品类别和国家的顶级产品完整列表,检查哪些热门产品已经在你的库存中,哪些潜在产品可以添加。
  • 价格和投标优化:使用价格竞争力基准信息,您可以检查自己在价格方面相对于竞争对手的表现。
  • 趋势产品和品牌:根据过去 X 天/周/月畅销书排行榜的变化,确定趋势产品/品牌。每个国家有所不同
  • 产品提要丰富化:用谷歌市场洞察数据丰富你的产品提要
  • 基于规则的自动化:根据产品反馈的丰富程度,暂停和启用渠道中的活动/产品(如谷歌购物)或调整出价。例如基于价格竞争力。

利用商家中心的市场洞察丰富产品数据

示例查询

为了向您展示如何组合数据,我构建了一个查询,该查询将在产品级别上连接和组合不同的 Merchant Center 表中的数据。

一些评论:

  • 谷歌并没有为你 feed 中的每一个产品提供数据。要么是某个产品不在畅销书排行榜上,要么就是谷歌不提供或者不计算(数据不够,可能还有其他一些原因)。或者你有其他商家不提供的独特产品。
  • 使用畅销书 _ 顶级产品 _ 库存作为映射表,通过连接 rank_id (在两个表中都可用),将畅销书 _ 顶级产品数据与您的产品数据连接起来
  • 您系统中已知的“原始”产品 ID 在不同的出口中并不直接可用。它在 product_id 字段中可用,但是您必须拆分该值并选择最后一部分,因为 Google 向其添加了附加信息,例如:online:NL:NL:**
  • 这些报告包含大量数据。例如,畅销书报告包含每个谷歌产品类别和国家的 10.000 本畅销书。出于效率原因,尽量只选择需要的国家。同样重要的是,在谷歌提供的表格中,同一产品可以在不同的国家重复出现。
  • 报告包含嵌套和重复的数据,请确保您理解表格结构。例如,产品错误和通知是嵌套的。

示例:用基准和价格竞争力数据丰富产品提要

下面的查询将产生这个表,您可以在您的原始产品提要上匹配它,并且可以作为自动化规则的输入(在产品级别上)

确保根据您的情况用正确的值替换数据集/表名

GitHub 上也有代码

结束语

使用 BigQuery Merchant Center 导出,您可以大规模生成洞察,并将其用于自动化。但是请记住,导出保存了大量数据,因此可能会在您的 Google Cloud 项目中产生一些成本(您可能不需要所有的数据)。这些表是按日期分区的,因此您可以编写一个 Python 脚本或使用 Airflow 删除超过 X 天的分区,以保持 BigQuery 中的数据量(可能在您创建了一些聚合报告之后)。

使用 cli 权限创建气流角色

原文:https://towardsdatascience.com/create-airflow-roles-with-permissions-from-cli-64e05aaeb2fc?source=collection_archive---------14-----------------------

直接从 cli 而不是 UI 创建具有 dag 级别气流权限的角色

作者图片

成为管理员

Airflow 提供了一种通过 RBAC 角色管理多个用户权限的方法。这些权限可以直接从 Airflow 的 UI 编辑(RBAC 默认使用 Airflow ≥ 2.0 激活。

图片作者。气流中默认 RBAC 角色的 UI 视图

只有当连接的用户拥有管理员角色时,才能访问这些角色。

默认情况下,当您第一次连接到 Airflow 时,角色是 Op,这是仅次于 Admin 的第二高角色。此角色没有足够的权限来管理角色。要成为管理员,请使用以下命令:

airflow users add-role -e *your_email* -r Admin

现在您是管理员,刷新气流页面,您应该可以访问具有角色和权限的安全菜单。

您将看到可以直接从 UI 编辑角色和权限。还可以创建 dag 级别的权限,即仅适用于给定 dag 的权限。现在假设您希望一些用户只访问一些特定的 Dag。直接从用户界面对多个 dag 使用 Dag 级别的权限非常容易出错且非常耗时,因为您必须从用户界面手动选择权限,甚至无法进行复制粘贴。

这就是为什么我创建了一个脚本,用于直接从 cli 创建具有预定义权限的角色。

剧本

以下是用于创建具有足够权限来管理特定 Dag 的角色的脚本。

最新版本托管在本回购。

默认情况下,该脚本使用预定义的权限,允许用户仅访问参数中给定的 Dag,以便可以在同一个气流中托管由多个 Dag 组成的多个项目。

请注意,可以根据您的特定用例在代码中直接编辑权限。气流 RBAC 许可语法的详细列表可以在气流代码中找到。

例子

假设我的气流中有两把匕首。每个项目一个。我想为这两个项目创建一个角色,以便只授权从事特定项目的用户查看相应的 dag。

图片作者。气流中的两个 Dag

创建角色

然后,我使用该脚本为 Dag“tutorial”创建一个访问受限的新角色。

python3 rbac_roles_cli.py \
-u http://localhost:4444 \
-r TutorialRole \
-d tutorial
  • -u:(url)air flow UI 根页面的 URL。
  • -r: (role)新角色的名称。
  • -d:(Dag)允许访问的 Dag 列表,用空格分隔。

如果返回错误,请检查您是否是 Airflow 的管理员,以及使用-d 选项指定的 Dag 是否存在。

向用户添加角色

现在,我们必须使用 Airflow 的 cli 向现有用户添加新角色。如果用户尚未在 Airflow 中创建,请遵循这些步骤。

airflow users add-role -e tutorial_user@gmail.com -r TutorialRole

从管理员用户的角度来看,我们可以在“Security menu”>“List Roles”中看到已经正确创建了角色。通过分析权限,您可以看到 dag 级别的权限也被添加到角色中。

图片作者。在气流 UI 视图中创建的角色

现在,为了确保用户只拥有已创建的角色,您可以使用以下命令删除其他角色,如 Op 或 Admin:

airflow users remove-role -e tutorial_user@gmail.com -r Op
airflow users remove-role -e tutorial_user@gmail.com -r Admin

如果一个给定的用户有多个角色,这个用户的权限将是每个角色权限的总和,所以你必须小心,这个用户只有这一个角色。

测试权限

现在,使用创建的角色登录帐户。

图片作者。用户对创建的角色中定义的 Dag 具有有限的访问权限。

用户现在只能访问创建角色时给出的 dag:在本例中,只能访问 Dag“tutorial”。用户甚至可以编辑 dag,查看日志和代码。如果您想个性化该用户的权限,您可以在代码中自由添加/删除一些权限。

与 Cloud Composer 兼容

有人用 Cloud Composer 直接在 Google 云平台管理自己的气流。因为 Composer 在访问 GCP 的资源之前需要对 Google 进行认证,所以我们必须生成一个 Google 访问令牌,以便在使用脚本之前对 GCP 进行认证。

创建 OAuth 凭据

为了与 Google APIs 通信,我们必须使用在 GCP 创建的个人令牌。这个令牌是 OAuth 令牌。要创建该令牌,请执行以下操作:

在 GCP:API&服务>凭证 > 创建凭证 > OAuth 客户端 ID > 电视和受限设备

创建了 OAuth 令牌,现在您拥有了一个客户端 ID 和一个客户端秘密

获取授权码

在以下 URL 中替换您的用户 ID,并在浏览器中直接调用它。

https://accounts.google.com/o/oauth2/v2/auth?client_id=client _ id&redirect _ uri = urn:IETF:WG:oauth:2.0:OOB&scope = https://www . Google APIs . com/auth/userinfo . profile&response _ type = code

该页面要求您使用您的 Google 帐户登录,然后复制显示的代码:这是授权代码。这个代码是临时的,所以我们将创建一个比这个更长的令牌。

图片作者。谷歌授权码

获取访问令牌

现在启动一个新的终端,粘贴这个 curl 并用您在上一步中复制的代码替换authorization _ code,用在 GCP 用 OAuth 令牌创建的客户端 id 和 secret 替换 client_idclient_secret

curl -s \
 — request POST \
 — data \
“code=***authorization_code***&client_id=***client_id***&client_secret=***client_secret***&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code” \
[https://accounts.google.com/o/oauth2/token](https://accounts.google.com/o/oauth2/token)

此 post 请求的响应应遵循以下模式:

{
  “***access_token***”: “ya29.a0ARrdaM-az...”,
  “expires_in”: 3599,
  “refresh_token”: “1//03uXjr...”,
  “scope”: “https://www.googleapis.com/auth/userinfo.profile",
  “token_type”: “Bearer”,
  “id_token”: “eyJaaza...“
}

复制响应中给出的 access_token。

使用脚本

最后,我们将使用之前用于标准气流的相同命令,只是我们必须为访问令牌指定一个选项,以便与受 Google 保护的 Composer Airflow 页面进行交互。

python3 rbac_roles_cli.py \
-u ***https://...composer.googleusercontent.com*** \
-r TutorialRole \
-d tutorial \
***-t access_token***

将用户添加到角色

可以使用 gcloud beta cli API 添加用户。

gcloud beta composer environments run example-environment — location europe-west1 users add-role — -e name[@organization.com](mailto:tristan_bilot@carrefour.com) -r TutorialRole

结论

Airflow 没有提供一种直接在 cli 中创建具有特定权限的角色的本机方法,除非使用一个复杂的、糟糕的、带有长卷的 API。提议的脚本使用 Python 轻松地操作这个 API,以便创建具有权限的角色。如果发生任何问题,请随时提出问题。尽情享受吧!

使用 PyWebIO 创建一个处理无聊的应用程序

原文:https://towardsdatascience.com/create-an-app-to-deal-with-boredom-using-pywebio-d17f3acd1613?source=collection_archive---------14-----------------------

实践教程

建议用户在无聊时使用 Python 进行哪些活动

动机

你有没有无聊到在谷歌上搜索:“无聊的时候做什么?”如果您可以创建一个应用程序,使用 Python 向用户推荐当天的随机活动以及与该活动相关的书籍,这不是很好吗?

作者 GIF

可以在这里用上面所示的 app 玩。在本文中,我将向您展示如何使用 PyWebIO、Bored API 和 Open Library 用几行代码创建这个应用程序。

在进入代码之前,让我们收集创建应用程序所需的工具。

工具

PyWebIO —用 Python 创建一个 Web 应用程序

PyWebIO 是一个 Python 库,允许你在没有 HTML 和 Javascript 知识的情况下构建简单的 web 应用。它比 Django 和 Flask 更容易学习,但比 Streamlit 更容易定制。

要安装 PyWebIO,请键入:

pip install pywebio

无聊的 API——无聊的时候找些事情做

无聊 API 帮你无聊的时候找事情做。你只要去 https://www.boredapi.com/api/activity就能得到一项活动的建议。

刷新页面会得到不同的结果:

如果您喜欢参与某一类型的活动,请将?type=activity-name添加到 API:

[https://www.boredapi.com/api/activity?type=education](https://www.boredapi.com/api/activity?type=education)

输出:

开放图书馆

开放图书馆是一个开放的、可编辑的图书馆目录,收录了所有出版过的书籍。Open Library 提供了一套 API 来帮助开发人员使用他们的数据。

您可以通过访问以下网址获得 Open Library 搜索结果的 JSON 文件:

[https://openlibrary.org/search.json?title=friends+influence+people](https://openlibrary.org/search.json?title=friends+influence+people)

产出摘要:

现在我们已经收集了创建应用程序所需的工具,让我们利用这些工具来创建一个应用程序。

创建应用程序

创建下拉列表

首先,创建一个下拉列表来显示所有活动类型:

上述代码的详细信息:

  • put_markdown:写减价
  • select:创建下拉菜单
  • start_server:启动一个 web 服务器,在上面服务 PyWebIO 应用。debug=True告诉服务器当代码改变时自动重新加载。

作者 GIF

根据所选选项显示活动

正常情况下,PyWebIO 的输入表单在成功提交后会被销毁。

作者 GIF

然而,用户可能希望使用不同的输入,所以我们需要找到一种方法来防止输入表单在成功提交后消失。这可以用pywebio.pin轻松完成。

对上述代码的解释:

  • while True:允许用户无限期插入新输入
  • put_select:类似于select小部件,但是被pin小部件函数用来检测输入的变化
  • pin_wait_change:监听一列 pin 小工具。当任何小部件的值改变时,该函数返回改变的小部件的名称和值。
  • with use_scope('activity', clear=True):当范围内有新的输出时,清除最后一个输出

输出:

作者 GIF

使用 Bored API 获得一个随机活动

接下来,我们将使用 Bored API 获得一个基于活动类型的随机活动。为此,我们将:

  • 创建一个名为get_activity_content的函数,它使用requests.get[https://www.boredapi.com/api/activity](https://www.boredapi.com/api/activity)发出请求。
  • 将我们从下拉栏获得的输入传递给函数get_activity_content。如果输入的值是education,API 将是[https://www.boredapi.com/api/activity?type=education](https://www.boredapi.com/api/activity?type=education)

作者 GIF

不错!

使用 Open Library 获取图书建议

建议要做的活动是好的,但不是很足智多谋。如果用户想了解他们将要做的活动的更多信息,该怎么办?这就是为什么我们也会建议他们使用开放图书馆阅读一些有用的资源。

从开放图书馆获取相关书籍的步骤:

  • 获取活动名称:下图中,活动名称为“给你生命中有影响力的人写一封感谢信”

作者图片

  • 从活动名称中提取名词短语:名词短语是以一个名词如“一个漂亮的女孩”为首的一组两个或两个以上的词。我们将使用 spaCy 从文本中提取名词短语:
$ pip install spacy
$ python -m spacy download en_core_web_sm
['a thank', 'you', 'an influential person', 'your life']
  • 使用提取的名词短语搜索书名。例如,为了搜索标题与your life相关的书籍,我们将把?title=your+life添加到 API 中:
[https://openlibrary.org/search.json?title=your+life](https://openlibrary.org/search.json?title=your+life)

在下面的代码中,我们使用从名词短语中提取的查询从 Open Library 获取相关书籍:

第一本书的输出示例:

  • 显示书名和作者的表格:JSON 输出很无聊。让我们使用pywebio.output.put_table将 JSON 结果转换成表格:

输出:

作者图片

太棒了。由于请求图书可能需要很长时间,我们还将在代码中添加put_loading,以便用户知道网站仍在加载:

结果:

作者 GIF

不错!

结论

恭喜你!你刚刚学习了如何使用 PyWebIO、Bored API 和 Open Library 创建一个 app 。我希望这篇文章能给你用 Python 创建一个有趣的应用程序的动力。

既然使用 PyWebIO 创建一个应用只需要几行代码,为什么不试一试呢?

请在这里随意使用本文的源代码:

https://build.pyweb.io/get/khuyentran1401/bored_app

我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上与我联系。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

[## 使用 SimPy 在 Python 中模拟真实事件

towardsdatascience.com](/simulate-real-life-events-in-python-using-simpy-e6d9152a102f)

创建一个出色的 Streamlit 应用程序,并使用 Docker 进行部署

原文:https://towardsdatascience.com/create-an-awesome-streamlit-app-deploy-it-with-docker-a3d202a636e8?source=collection_archive---------2-----------------------

本文全面概述了使用 streamlit 和 Docker 部署简单情感分析应用程序的分步指南

由 Timelab Pro 在 Unsplash 上拍摄的照片

介绍

作为机器学习或软件工程师,我们希望与他人分享我们的应用程序/模型及其依赖性。如果处理不当,这个过程不仅会耗费我们的时间,还会耗费我们的金钱。如今,与其他开发人员合作的最受欢迎的方式之一是使用源代码管理系统(例如 Git)。这可能还不够,因为您在自己的计算机上开发的令人惊叹的模型可能因为不同的原因而无法在其他人的计算机上运行。所以解决这个问题的一个更好的方法可能是使用 Docker 容器,以便能够“复制”你的计算机,并让其他人可以访问它。在本文中,我们将按照以下顺序学习这一概念:

  • 训练一个简单的情感分类器
  • 使用良好的软件项目结构创建相应的 Streamlit 应用程序
  • 为 streamlit 应用程序创建 Docker 映像
  • 运行容器中的图像

机器学习模型

因为主要目标是引导您完成使用 Streamlit 和 Docker 部署模型的步骤,所以我们不会在模型培训上花费太多时间。

笔记本中的模型训练

有用的库 以下是有用的库

(图片由作者提供)

读取垃圾数据 读取数据集并显示 3 个随机样本

(图片由作者提供)

spam_data.v1.unique() == >数组(['ham ',' spam'],dtype=object)

观察:我们有两个标签,对应一个 2 类分类问题。然后,我们需要将这两个标签编码成数字格式,用于模型训练。

(图片由作者提供)

特征和目标

(图片由作者提供)

特征提取&模型训练 我们使用朴素贝叶斯分类器

(图片由作者提供)

什么是 Streamlit 以及它如何有用

Streamlit 是一个开源框架,数据科学和机器学习团队可以使用它来为业务执行更好的数据可视化,还可以将模型部署到生产环境中(而不是使用 Flask、Django、FastAPI,它们可能需要相当长的模型部署时间),如下面的数据科学生命周期所示。

图片由作者根据 Analytics Vidhya 定制

创建我们的 Streamlit 应用

先决条件

  1. 创建并激活虚拟环境

(图片由作者提供)

2.安装项目依赖项

(图片由作者提供)

3。构建项目

以如下所示的方式构建项目具有以下优势:

  • 简化协作
  • 维护干净健壮的代码
  • 使部署更加容易
  • 等等。

(图片由作者提供)

实现
项目包
_ _ init _ _。py 是一个空文件。下面是其余两个文件(data_processor.py 和 model_trainer.py)的内容

data _ processor . py 的内容

model_trainer.py 的内容

train_model.py 内容

app.py 的内容

运行 app
运行模型主要有两个步骤。必须从项目的根本着手:

(图片由作者提供)

运行第二个命令后,我们终于可以与应用程序进行交互了。下面是两个场景:

  1. 所提供的消息被分类为垃圾邮件的情况

(图片由作者提供)

2.提供的消息被分类为垃圾消息(非垃圾邮件)的情况

(图片由作者提供)

申请归档的时间到了

创建 docker 层 为了能够对应用程序进行 docker 化,我们需要在 docker 文件夹中创建一个 Docker 文件。该文件包含如下所示的七条主要指令。

  1. (来自):从 docker hub 获取一个官方的 python 映像,然后我们的文件将从该映像构建。
  2. (WORKDIR):创建/app 作为应用程序的工作目录
  3. (复制源目标):将文件从源文件夹复制到目标文件夹。
  4. (运行):运行 requirements.txt 文件以安装项目依赖项。
  5. (EXPOSE):用于公开模型要使用的端口。
  6. (ENTRYPOINT) & (CMD):创建一个入口点,以便最终使映像可执行。

(图片由作者提供)

构建 Docker 映像 以下命令构建名为streamlitspamapp的映像,标记为 最新 版本。这个图像是从以前的 docker 文件构建的。

(图片由作者提供)

(图片由作者提供)

从 docker build 命令的上一个结果中,我们可以看到我们的映像已经按照前面的解释创建好了。

运行容器 镜像构建完成后,我们需要用下面的命令将它运行到一个容器中。

🚫确保在运行这个命令之前停止之前的 streamlit 应用程序,否则,您可能会遇到一个漂亮的消息错误,告诉您端口已经被使用

(图片由作者提供)

前面的命令会自动生成两个 URL。你的可能和我的不一样。

(图片由作者提供)

您使用 docker 部署了您的 streamlit 应用程序🎉🎉🎉!

文章结尾

在本文中,您已经学习了如何构建一个简单的机器学习模型,实现相应的 streamlit 应用程序,并最终使用 Docker 进行部署。您现在可以使用一些云提供商平台,如 Azure、AWS、GCP,在几分钟内部署容器!
如需进一步阅读,请随时关注我在 YouTube 上的文章,并参考以下链接:

额外资源

Github 代码

再见🏃🏾

你能创建一个空的熊猫数据框,然后填充它吗?

原文:https://towardsdatascience.com/create-an-empty-pandas-df-one-row-at-a-time-61b770476bae?source=collection_archive---------26-----------------------

讨论为什么应该避免创建空的数据帧,然后一次追加一行

照片由 Glen Carrie 在 Unsplash 上拍摄

介绍

在 pandas 的上下文中,一个非常常见的问题是,您是否真的可以创建一个空的数据帧,然后通过一次追加一行来迭代地填充它。然而,这种方法往往效率很低,应该不惜一切代价避免。

在今天的文章中,我们将讨论一种替代方法,它将提供相同的结果,但比创建一个空的数据帧,然后使用循环在其中追加行要有效得多。

要避免什么

当然,实际上可以创建一个空的 pandas 数据帧,然后以迭代的方式追加行。这种方法看起来特别像下面这样:

import numpy as np
import pandas as pd
from numpy.random import randint# Make sure results are reproducible
np.random.seed(10)# Instantiate an empty pandas DF
df = pd.DataFrame(columns=['colA', 'colB', 'colC'])# Fill in the dataframe using random integers
**for i in range(7):
    df.loc[i] = [i] + list(randint(100, size=2))**print(df)
 *colA colB colC
0    0    9   15
1    1   64   28
2    2   89   93
3    3   29    8
4    4   73    0
5    5   40   36
6    6   16   11*

尽管上面的方法可以达到目的,但必须避免,因为它效率很低,而且肯定有更有效的方法,而不是创建一个空的数据帧,然后使用迭代循环来构建它。

一个更糟糕的方法,是在循环中使用append()concat()方法。

值得注意的是,[**concat()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html#pandas.concat)(因此也是**append()**)制作了数据的完整副本,不断地重用这个函数会对性能产生重大影响。如果需要在几个数据集上使用该操作,请使用列表理解。

— 熊猫文档

改为使用列表

不用使用loc[]属性或append/concat方法以迭代的方式追加行,您实际上可以将数据追加到一个列表中,最后直接从预先创建的列表中实例化一个新的 pandas DataFrame。这甚至在官方的熊猫文档中也有提及。

迭代地将行追加到数据帧可能比单个连接计算量更大。更好的解决方案是将这些行追加到一个列表中,然后将该列表与原始数据帧连接在一起。

— 熊猫文件

import numpy as np
import pandas as pd
from numpy.random import randint# Make sure results are reproducible
np.random.seed(10)data = []
for i in range(7):
    data.append([i] + list(randint(100, size=2))df = pd.DataFrame(data, columns=['colA', 'colB', 'colC'])print(df)
 *colA  colB  colC
0     0     9    15
1     1    64    28
2     2    89    93
3     3    29     8
4     4    73     0
5     5    40    36
6     6    16    11*

使用列表(追加或删除元素)要高效得多,而且在迭代地将行追加到 pandas 数据帧时,您必须始终首选这种方法。

最后的想法

在今天的文章中,我们讨论了为什么避免创建空的 pandas 数据帧并迭代填充它们是重要的,因为这将显著影响性能。

相反,我们探索了如何使用列表迭代地构建这样的结构,并最终从创建的列表中创建新的 pandas 数据帧。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

你可能也会喜欢

从美国劳工统计局平面文件网站创建可供分析的数据集

原文:https://towardsdatascience.com/create-analysis-ready-datasets-from-the-u-s-bureau-of-labor-statistics-flat-files-web-c83a54e2c064?source=collection_archive---------23-----------------------

循序渐进的指南

美国劳工统计局(BLS)网站是美国经济数据的丰富来源之一,研究经济学家、数据科学家、金融专业人士、记者和数据爱好者经常访问该网站来搜索有关经济的信息。网站定期发布关于就业、失业、通货膨胀和价格、生产率、消费者支出和时间使用等经济指标的数据。虽然大多数指标是以汇总(或国家)数据的形式提供的,但有些指标是细分到国家以下各级的。本文特别面向那些不熟悉使用值和元数据分开存储的数据的分析师,旨在帮助这些分析师快速准备好数据以供分析。

BLS 网站不遗余力地简化对数据的访问,包括以表格、摘要和可视化形式排列已发布的系列。一些经常被访问的主题被超链接到一个交互式数据查看器(,就像这个)上,从这里可以下载数据。BLS 网站还有一个数据检索工具(这里是),用户可以通过这个工具从网上获取数据。数据也可以通过公共数据应用编程接口 (API)来检索,以实现对经济数据的编程访问,出版商希望开发者能够利用这些数据来创建应用。该 API 有两种格式,具有不同的需求和功能。访问 BLS 数据的说明总结在这样一个页面上 one ,包括如何访问平面文件 FTP 站点(参见示例)。在需要大量数据的情况下,需要平面文件,而获取数据超出了可用数据检索工具的能力。

虽然这些说明告诉您不同的文件是如何关联的,但它没有告诉新手如何将不同的文本文件组合成对分析有用的数据集。本文的目的是提供一个详细步骤的示例,分析师(尤其是使用这种文件的新手)可以使用这些步骤将不同平面文件中的信息组合成可用的格式。这些步骤是用 python 完成的( R 也可以用),因为以编程方式工作时操作更容易。此外,由于我试图从本地失业统计(LAUS)网站获取美国大都市统计区(MSA)的月度失业数据,因此我在此描述的示例将集中于此,但同样的步骤也可以(很可能)用于获取其他指标。

在下载和使用数据集的过程中,一些数据集被组织成用于数据值的文件以最小化文件大小,而包含关于数据的元数据的数据字典在单独的文件中可用。FTP 平面文件就是这种情况。数据字典解释了数据文件的组织(参见此处的、此处的和此处的用于 LAUS 平面文件数据)以及关于数据的其他信息。还建议用户阅读上面示例链接末尾的信息,以便更好地理解数据。本指南还可以作为清理数据集并为分析做好准备的教程。该任务的最终产品是 1990 年至 2021 年 9 月美国大都市统计区域(MSA)月度失业率的纵向(或面板)数据集。

实施流程:GitHub 回购可在:https://github.com/tyngbayi/Using_LAUS_flatfiles找到

步骤 1 :导入相关 python 库,检索 metro 和 area 数据集,并另存为。csv 文件。

import pandas as pd
import numpy as npimport urllib
from urllib.request import urlretrieve# urls for time series and area code data
url1='[https://download.bls.gov/pub/time.series/la/la.data.60.Metro](https://download.bls.gov/pub/time.series/la/la.data.60.Metro)'
url2='[https://download.bls.gov/pub/time.series/la/la.area](https://download.bls.gov/pub/time.series/la/la.area)'

第二步:读入数据,检查一些信息

df1 = pd.read_csv(‘filepath/timeseries.csv’, delimiter=”\t”) df.head()

作者图片

df.info()

作者图片

调用 info()方法会在一些列名周围显示一些空白。这可以通过重命名列来解决。

df1.rename(columns={'series_id                     ':’series_id’, 
                    '       value':’unemployment’}, inplace=True)

步骤 3 :删除一些列并创建新列

df1.drop(‘footnote_codes’, axis = 1, inplace=True)df1[‘measure’] = df1[‘series_id’].apply(lambda x: x[18:].strip())df1.head()

作者图片

第四步:使用 float 函数将失业数据转换为数值数据类型。但是由于一些“坏的”值必须被删除,这就产生了错误。

cnt = 0unemployment_dict = {}for row in df1[‘unemployment’]:
 if row is not None:
 try:
 float(row)
 pass
 except ValueError:
 unemployment_dict[cnt] = row
 cnt+=1print(unemployment_dict)

作者图片

步骤 5 :创建区号列,这是一个惟一的 MSA 标识符,将用于合并失业统计数据和区号名称

df2[“area_code”] = df2[‘series_id’].apply(lambda x: x[3:18])

作者图片

第六步:读入 MSA 名称文件,只选择 MSA 数据行(area_type_code B),准备与失业统计合并

df3 = pd.read_csv(‘filepath/area_codes.csv’, delimiter=”\t”)
df3.head(5)

作者图片

步骤 7 :合并失业统计和地铁数据集

df5 = df2.merge(df4, on=’area_code’)

第 8 步:只选择月数据的行

monthly_unemployment = df5[df5[‘period’] != ‘M13’]
monthly_unemployment.head()

作者图片

当然,可以做一些进一步的清理,例如创建城市和州名的列,或者城市名和州名的单独列;过滤季节性未调整行;或者只处理年度数据(M13 期),这取决于分析师的目标。

我希望这能帮助那些对比 BLS 网站上的其他数据检索方法所能提供的大得多的数据集感兴趣的分析师。本文特别面向那些不熟悉使用值和元数据分开存储的数据的分析师,旨在帮助这些分析师快速准备好数据以供分析。

此外,当我试图获取数据时,我正在使用 Python,并没有寻找使用 R 的选项。有一天,当我不那么忙的时候,我可以搜索一个 R 教程或图书馆,使 LAUS 的数据随时可用,如果我找不到,我可以开始工作。

用 Flask 和 Heroku 创建和部署一个简单的 Web 应用程序

原文:https://towardsdatascience.com/create-and-deploy-a-simple-web-application-with-flask-and-heroku-103d867298eb?source=collection_archive---------2-----------------------

通过简单的交互式 web 应用程序分享您的作品

照片由将提升到 Unsplash 上

假设您已经用 Python 编写了一个非常酷的脚本来进行一些有趣的数据分析,现在您想向其他人演示它。很有可能,发送一个.py文件并要求其他人运行它,或者演示自己在命令行上运行它,都不会像一个包装精美的 web 应用程序那样有把握。通过使用 Python 包flask,我们可以相当快地创建一个这样的交互式应用程序。在本文中,我将制作一个简单的 web 应用程序,显示主页被访问的次数,并将其部署在 Heroku 上与其他人共享。

注意——以下所有截图均由作者拍摄。

设置项目和文件夹层次

向下游部署我们的项目的最简单的方法是在 GitHub 上创建一个新的存储库,我们所有的文件都将存放在那里。因此,我开始在 github.com/n-venkatesan/sample-webapp 创建一个新的回购协议,并将其克隆到我的本地电脑上。当创建存储库时,您可以选择用一个.gitignore文件初始化——我建议从下拉菜单中选择Python,以避免不必要的文件被签入 Git。

> git clone [https://github.com/n-venkatesan/sample-webapp](https://github.com/n-venkatesan/sample-webapp)> cd sample-webapp/

现在我们需要做的就是创建一个名为templates的文件,我们的 HTML 文件将存放在这里:

> mkdir templates

文件夹结构设置完毕!

创建新的虚拟环境

我们希望我们的开发从一个全新的开始,这样我们就只安装我们的应用程序绝对需要的依赖项——这在我们以后部署我们的 web 应用程序时尤其重要。

> python3 -m venv venv> source venv/bin/activateIf you see the name of the virtual environment (venv) before the command prompt, you have successfully activated the new environment(venv) > Success!

我们现在需要安装我们的应用程序所需的依赖项,它们是flaskgunicorn,这是运行我们的应用程序所需的 Python web 服务器接口。

(venv) > pip install flask gunicorn

酷——现在我们可以开始创建我们的应用程序了!

为网页编写 HTML

在我们的templates/目录中,创建一个名为index.html的新文件。这将是当我们试图访问我们的 web 应用程序时显示的页面。要查看呈现的 HTML 是什么样子,您可以在 web 浏览器中打开该文件。本教程假设你对 HTML 和 CSS 有一个非常基本的了解,但是有很多像 W3School 这样的资源可以帮助你快速上手。

我们的页面将只包含两个元素,一个标题写着Welcome!,下面一个段落写着This site has been visited n times.,其中n是到目前为止网站被访问的实际次数。我们将把这两个元素嵌套在一个<div>块中,以便稍后做一些 CSS 样式。标签表示标题和段落之间的换行符。

<div>
    <h1>Welcome!</h1><br>
    <p>This site has been visited {{ count }} times.</p>
</div>

关于上面的 HTML 块,唯一可能出现的新内容是段落块中的{{ count }}文本。双花括号({{ }})意味着您正在该块中运行 Python 代码——所以我们引用变量count的值,稍后我们将把它传递给 HTML 模板。

在当前状态下,我们的页面如下所示:

非常基本——让我们添加一些格式!首先,让我们为文本选择不同的字体。我喜欢去谷歌字体,那里有各种各样的免费字体可以使用——对于这个应用程序,我选择了一种叫做 Rubik 的字体。在每个字体粗细的旁边,有一个按钮,上面写着“选择这种样式”——单击其中的至少一个,将在右边打开一个窗口,其中有代码,您可以复制/粘贴到您的 HTML 中,以访问该字体!我只是选择了Regular 400字体的粗细,并得到了下面的代码,我把它添加到了我的index.html文件的顶部:

<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Rubik&display=swap" rel="stylesheet">

现在我们可以使用 CSS 来设置页面的样式——我们首先在index.html中创建一个样式标签,然后将所有的 CSS 代码放在这里。我们将使页面上所有文本的字体变得像魔方一样,这可以通过改变与所有元素相对应的属性*来实现。此外,我们将把所有内容从页面顶部向下移动 50 像素,将标题设为红色,并更改标题和段落部分的字体大小。我将这段代码添加到字体链接的正下方,但在任何实际页面内容之前。

<style>
    * {
        font-family: "Rubik", "sans-serif";
    } div {
        text-align: center;
        margin-top: 50px;
    } h1 {
        color: red;
        font-size: 40pt;
    } p {
        font-size: 24pt;
    }
</style>

看起来好多了!现在,我们可以添加运行我们的应用程序的 Python 后端了!

创建烧瓶应用程序

在我们的主项目文件夹中,我们可以创建一个名为app.py的文件,它将成为我们的 web 应用程序的后端。我们需要做的第一件事是导入所需的包。

from flask import Flask, render_template

Flask是我们将用来实例化我们的应用程序的,而render_template是我们将用来把我们上面写的 HTML 连接到我们的应用程序的。

我们现在必须创建我们的应用程序,我将把它存储在一个名为app的变量中:

app = Flask(__name__)

现在,我们需要处理路由——路由是一个 URL 模式,也就是说,你的网站的基本 URL 会有路由/,而你的网站中的另一个路由可能有路径/route_path。由于我们的应用程序只有一个页面,我们只需要为/路线编写一个函数。为了指定路径,我们在函数上方使用了一个装饰器,格式为@app.route(route_path)。该函数目前什么都不做,因为我们刚刚在主体中添加了一个pass

@app.route("/")
def index():
    pass

我们的功能需要做 4 件事:

  1. 加载一个名为count.txt的文件,我们将使用它来跟踪当前访问站点的人数
  2. 将计数增加 1
  3. 用新的计数值覆盖count.txt的内容
  4. 使用插入的 count 变量的值呈现我们之前编写的 HTML。

加载电流计数

让我们首先在主项目文件夹中创建一个名为count.txt的文件,其中只有0作为唯一的字符(因为我们目前没有访问者)。

(venv) > less count.txt0
count.txt (END)

现在,在我们的函数index()中,我们可以添加以下代码来读取count的当前值:

@app.route("/")
def index(): # Load current count
    f = open("count.txt", "r")
    count = int(f.read())
    f.close()

我们以读取模式(r)打开文件count.txt,用f.read()读取文件内容,用int()将值转换为整数。最后,我们用f.close()关闭文件。

增加计数

我们可以用下面的一行代码做到这一点:

@app.route("/")
def index(): # Load current count
    f = open("count.txt", "r")
    count = int(f.read())
    f.close() # Increment the count
    count += 1

覆盖计数值

类似于我们在读取 count 时所做的,我们现在以覆盖模式(w)打开文件count.txt,并在再次关闭文件之前,将新 count 的值(用str()转换为字符串)写入文件。

@app.route("/")
def index(): # Load current count
    f = open("count.txt", "r")
    count = int(f.read())
    f.close() # Increment the count
    count += 1 # Overwrite the count
    f = open("count.txt", "w")
    f.write(str(count))
    f.close()

渲染 HTML

既然我们每次路由到/时计数都会增加,我们需要呈现我们之前编写的 HTML,但是插入了count的值。还记得我们如何在名为templates的子文件夹中创建index.html文件吗?这是因为flask有一个名为render_template()的函数,它会自动查看这个文件夹,并可以获取与 HTML 文件中引用的变量相对应的关键字参数!在这种情况下,我们通过编写{{ count }}来引用 HTML 中名为count的变量的值。因此,通过使用render_template()传递值,我们可以在 HTML 中引用它。

@app.route("/")
def index(): # Load current count
    f = open("count.txt", "r")
    count = int(f.read())
    f.close() # Increment the count
    count += 1 # Overwrite the count
    f = open("count.txt", "w")
    f.write(str(count))
    f.close() # Render HTML with count variable
    return render_template("index.html", count=count)

运行应用程序

我们快完成了!要运行我们的应用程序,我们需要在我们的app.py代码中添加以下几行:

if __name__ == "__main__":
    app.run()

当我们从命令行调用 Python 脚本时,上面的代码启动我们的应用程序 web 服务器。现在,运行我们的应用程序:

(venv) > python app.py* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)

如输出所示,我们的 web 服务器运行在127.0.0.1:5000,也可以通过localhost:5000访问。导航到此 URL,您会发现:

呜哇!由于 count 的当前值也存储在count.txt文件中,所以即使您停止并重新启动 web 服务器,您也会得到准确的总计数值!

将应用程序部署到 Heroku

Heroku 是一项服务,它允许您部署这个 Python web 应用程序,这样任何拥有该链接的人都可以使用它。你应该做的第一件事是在 Heroku 上创建一个免费帐户。一旦你创建了一个帐户,从你的仪表板,点击按钮“创建新的应用程序”。在这里,为您的应用程序命名,然后单击“创建应用程序”。

在部署我们的 web 应用程序之前,我们需要添加几个文件供 Heroku 识别。第一个是名为requirements.txt的文件,本质上是一个 Python 依赖列表,Heroku server 需要安装它来运行您的应用程序。幸运的是,通过在虚拟环境中工作,您已经安装了所需的依赖项。因此,创建我们的requirements.txt文件非常简单:

(venv) > pip freeze > requirements.txt(venv) > less requirements.txtclick==7.1.2
Flask==1.1.2
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
Werkzeug==1.0.1
requirements.txt (END)

这些都是之前运行pip install flask gunicorn时安装的依赖项。

第二个文件叫做Procfile,它是 Heroku 如何运行应用程序的指令列表。这个文件将是一行程序,它指定了两件事:

  1. 要使用的 web 服务器接口(gunicorn
  2. 应用程序的名称(app)
web: gunicorn app:app

现在您已经创建了requirements.txtProcfile,我们可以将所有这些签入我们的 GitHub repo:

(venv) > git add .
(venv) > git commit -m "Added web application files"
(venv) > git push origin main

现在,在我们的应用仪表板上,我们可以通过点击相关按钮来选择连接到 GitHub。然后我们将被重定向到登录 GitHub 并允许 Heroku 使用。然后,我们可以选择与我们的项目相关联的存储库。

将 Heroku 应用程序连接到 Github

最后,我们有两个选择:

  1. 自动部署—这将导致每次有新的推送到指定分支上的存储库时,应用程序都要重新部署。
  2. 手动部署—您可以通过单击按钮从指定分支手动部署应用程序

自动与手动应用程序部署

我们现在将手动部署-单击“部署”按钮后,您将看到几分钟的构建日志,之后您将看到您的应用是否已成功部署。

你可以点击“查看应用”来查看你的超棒的网络应用!你可以在这里看到这个教程的结果。请记住,如果你的应用程序没有收到很多流量,它会在几个小时后进入休眠模式,所以下次你试图访问它时,它可能需要几秒钟才能启动。此外,Heroku 机器每天重启一次,因此您将丢失对本地文件系统的更改。如果你想让count.txt文件不受影响,你应该把它放在像亚马逊 S3 这样的云文件存储系统上,并使用你的应用程序发出请求。然而,对于这个例子,我想保持简单,所以当机器重新启动时,计数会每隔一段时间重置一次。

本文中的所有代码都可以在这个库中找到。

结束语

感谢您的阅读!你可以在我的个人 GitHub 页面看到我的一些作品。我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系,以获取更多更新和文章。

创建并发布您自己的 Python 包

原文:https://towardsdatascience.com/create-and-publish-your-own-python-package-ea45bee41cdc?source=collection_archive---------12-----------------------

关于如何 pip 安装您定制的软件包的简短指南

这些鸟是从源头安装的 pip(图片由詹姆斯·温斯科特在 Unsplash 上提供)

您可能对 requests、Pandas、Numpy 和许多其他可以用 pip 安装的包很熟悉。现在是时候创建自己的包了!在这篇文章中,我们将通过所需的步骤来打包和发布您的 Python 代码,供全世界进行 pip 安装。首先,我们将看看如何打包您的代码,然后我们如何发布它,使其易于访问。

(你更愿意和像同事这样的少数人分享你的代码吗?也可以允许人们从私有库 pip 安装包。甚至当 将你的包放入 Docker 容器时也是如此!T22)

目标和准备

在本文中,我创建了几个真正重要的函数,希望与大家分享。让我们创建一个名为“ mikes_toolbox 的包,人们只需通过pip install mikes_toolbox就可以使用它。

首先,我们将概述一下安装过程是如何工作的:如果有人调用pip install mikes_toolbox,代码必须来自某个地方。Pip 在 PyPi 上搜索具有该名称的包;Python 包索引。你可以把这个想象成 Python 包的 YouTube。首先我们将代码打包,然后上传到 PyPi,这样其他人就可以找到我们的包,下载并安装它。

包装

首先,我们将封装我们的代码。我们将创建一个名为“toolbox_project”的项目目录,其中包含以下目录和文件:

toolbox_project
    mikes_toolbox
        __init__.py
        functions.py
        decorators.py
    LICENSE.txt
    README.md
    setup.cfg
    setup.py

项目文件夹的内容由两部分组成:mikes_toolbox 文件夹和 4 个附加文件。该文件夹是我们包含源代码的实际包。这 4 个附加文件包含如何安装软件包的信息和一些附加信息。

一个包含我们的代码并附有安装说明的包(图片由 Christopher Bill 在 Unsplash 上拍摄)

包文件夹

mikes_toolbox 是我们实际的包,包含了我们所有的源代码。请确保将该文件夹命名为您想要的包名。在我的案例中,它包含以下内容:

  • mikes_toolbox/function.py 和 decorators.py 这是我的源代码。Function.py 包含了一个函数比如叫做 weirdCase();一个可以让字符串完全不可读的函数。
  • mikes_toolbox/init。py 这个文件是必需的。它告诉 python mikes _ toolbox 是一个 Python 包文件夹。你可以让它空着。您可以选择在这里包含 import 语句,以便更容易地从您的包中导入代码。一个例子:
    包括from functions import weirdCase。这样一来,人们就不必在软件包安装完毕后进行from mikes_toolbox.functions import weirdCase,而是直接from mikes_toolbox import weirdCase

LICENSE.txt

描述人们如何使用您的许可证。从这个站点中选择一个,然后将内容粘贴到这个文件中。

README.md

这个文件包含关于这个包的信息:它是做什么的?它有什么特点?如何安装使用?在此查看示例或在此查看示例。
这个文件是用标记写的。在这个站点上查看一个已经包含一些示例标记的编辑器;只需根据您的需求进行编辑即可。

setup.cfg

这是一个简单的文件,只包含下面的代码。参考 README.md。

[metadata]
description-file = README.md

setup.py

该文件确保软件包正确安装。复制下面的代码,并在需要的地方进行修改。大多数条目都是符合逻辑的,但 download_url 需要一点解释(见下文):

下载 _ 网址

当你pip install pandas pip 在 PyPi 上搜索熊猫时。一旦找到,PyPi 就告诉 pip 在哪里可以下载这个包。大多数情况下,这是 git 存储库中的一个文件。download_url 关键字指的是这个文件的位置。为了获得一个 URL,我们首先把源代码放在 pip 可以到达的地方。最好的方法是将您的代码上传到 GitHub repo 并创建一个版本。这个过程超级简单,步骤如下:

  1. 创建一个存储库(名称不必与包名相匹配,但更有序)。
  2. 在你的回购中,在右边;单击“创建新版本”
  3. 填写“标签版本”与 setup.py 中的相同(版本关键字)
  4. 给发布一个标题和描述。这并没有反映在包装中,这纯粹是为了在您的回购中保持一个概览
  5. 点击“发布发布”
  6. 复制“源代码(tar.gz)”的链接地址
  7. 将复制的链接地址作为下载 url 的值粘贴在 setup.py 中

就是这样!您的软件包现在可以下载和安装了。下一步是处理分销。

分配

到目前为止,我们所做的唯一一件事就是打包我们的代码并上传到 GitHub,pip 仍然不知道我们的包的存在。因此,让我们确保 pip 可以找到我们的软件包,以便人们可以安装它。

(图片由凯皮尔格在 Unsplash 上拍摄)

PyPi 帐户

如果你想在 YouTube 上发布视频,你需要先创建一个帐户。如果你想上传软件包到 PyPi,你也需要先创建一个帐户。去 PyPi 注册一个账号。继续之前,请确认您的电子邮件地址。

创建源分布

这将创建一个 tar.gz 文件,其中包含运行包所需的所有内容。打开一个终端,cd 到您的项目目录并执行下面的命令:

python setup.py sdist

(对终端不熟悉?查看 文章为绝对基础知识)

上传

我们准备好上传我们的包了!首先,我们需要 pip 安装 Twine,这将有助于我们上传。简单来说就是pip install twine

最后一步是实际上传包。在终端中,如果您还不在项目目录中,请转到该目录并执行

python -m twine upload dist/*

Twine 会要求您提供 PyPi 凭证,但在此之后,您的包应该会被上传!

测试

创建一个新的 python 项目,并(可选地)启动一个新的虚拟环境。然后pip install mikes_toolbox。通过调用来测试代码

from mikes_toolbox import weirdCase

print(weirdCase("This function is essential and very important"))

更新您的包

如果你更新你的包,你需要确保更新 setup.py 中的版本,并在 GitHub 上创建一个带有相同标签的新版本。此外,更新 setup.py 中的 download _ URL。
一旦完成,用户就可以使用

pip install mikes_toolbox --upgrade

结论

在这些简单的步骤中,你已经学会了如何使用 PyPi 和 pip 打包你的代码并发布给全世界。此外,您还创建了一个存放代码的中心位置,可用于跟踪 bug、发布问题或请求新功能。不再通过邮件共享代码

我希望我已经阐明了很多创建和分发 Python 包的过程。如果你有建议/澄清,请评论,以便我可以改进这篇文章。同时,查看我的其他关于各种编程相关主题的文章。编码快乐!

—迈克

页(page 的缩写)学生:比如我正在做的事情?跟我来!

https://mikehuls.medium.com/membership

使用 Python 创建和读取二维码

原文:https://towardsdatascience.com/create-and-read-qr-code-using-python-9fc73376a8f9?source=collection_archive---------1-----------------------

如何使用 python 制作和读取二维码的简单分步指南

什么是二维码?

QR 码是机器可读的二维像素化条形码,可用于存储各种信息。二维码中的 QR 代表快速反应。二维码是由汽车制造商电装波的日本工程师 Masahiro Hara 于 1994 年发明的,用于追踪汽车零部件的运动。
2010 年代后期,随着手机光学功能的改善和广泛采用,二维码越来越受欢迎。
如今,二维码正被广泛用于各种应用,如在线支付、查看酒店菜单、共享 wifi 密码、获取产品价格和其他详细信息等。二维码已经变得如此流行,以至于现在每部新的智能手机都内置了二维码阅读器。

在这篇文章中,我们将学习如何使用 python 来读取和生成 QR 码。

生成二维码

安装二维码模块 我们将使用二维码包生成二维码。
第一步是使用 pip 命令安装软件包。

pip install qrcode

软件包的完整文档可以在软件包的 PYPI 主页中获得。

简单二维码

使用 qrcodemake 函数,将数据作为参数传递,可以生成一个简单的 qr 码。下面的代码生成一个二维码,上面写着“你好,世界”

#Import Library
import qrcode#Generate QR Code
img=qrcode.make('Hello World')
img.save('hello.png')

Hello World 的二维码(图片由作者提供)

你可以用你的智能手机阅读上面的代码。

注意:不要使用手机读取随机二维码,因为它可能包含恶意代码/链接。

高级二维码

可使用 QRCode 对象定制 QR 码,该对象具有以下参数:

一、版本 :
二维码有 40 个版本,控制码的大小。
1 为最小,40 为最大。
版本 1 将创建一个 21X21 矩阵二维码。

二。误差修正 :
该参数控制用于二维码的误差修正。误差修正率从 7%到 30%不等,如下所示。
错误 _ 更正 _L:高达 7%
错误 _ 更正 _M:高达 15%
错误 _ 更正 _Q:高达 25%
错误 _ 更正 _H:高达 30%

三世。box_size :
该参数控制二维码每个方框中的像素数

四。边框 :
该参数控制边框的粗细。默认边框为 4 像素厚。

QRCode 对象具有以下功能,可用于创建 QR 码。

一、添加数据
二维码的内容可以作为参数传递给这个函数。

二。制作
如果不确定使用哪个版本的二维码,可以通过以下方式自动设置版本:
a. 设置版本参数为
b. 设置适合参数使为真。

三。制作图像
该功能生成二维码。它还可用于使用 fill_colorback_color 参数设置二维码的填充颜色和背景颜色。

下面的代码生成一个指向我的中等个人资料的 QR 码。

qr = qrcode.QRCode(
    version=1,
    error_correction=qrcode.constants.ERROR_CORRECT_L,
    box_size=10,
    border=4,
)
qr.add_data("[https://abhijithchandradas.medium.com/](https://abhijithchandradas.medium.com/)")
qr.make(fit=True)img = qr.make_image(fill_color="red", back_color="black")
img.save("medium.png")

高级二维码(图片由作者提供)

读取二维码

我们将使用 OpenCV 读取二维码。如果没有安装软件包,可以按如下方式安装:

pip install cv2

二维码可以使用 OpenCV 的 QRCodeDetector 对象的 detectAndDecode 函数进行解码。

import cv2img=cv2.imread("medium.png")
det=cv2.QRCodeDetector()
val, pts, st_code=det.detectAndDecode(img)
print(val)Output:
[https://abhijithchandradas.medium.com/](https://abhijithchandradas.medium.com/)

detectAndDecode 函数返回 QR 码的内容、盒子角的坐标和二进制化的 QR 码。关于使用 OpenCV 读取二维码的更多信息,您可以参考 OpenCV QRCodeDetector 类参考。

资源:

教程的代码可以在我的 GitHub Repo 中找到。

成为会员

我希望你喜欢这篇文章,我强烈推荐 注册中级会员 来阅读更多我写的文章或成千上万其他作者写的各种主题的故事。
你的会员费直接支持我和你看的其他作家。你也可以完全接触到 Medium 上的每个故事。

相关文章:

照片由阿尔伯特·胡在 Unsplash 上拍摄

从你的个人数据中创造美丽的艺术

原文:https://towardsdatascience.com/create-beautiful-art-from-your-personal-data-9dc0abfeeaf?source=collection_archive---------16-----------------------

我的跑步之旅;作者图片

教程-数据即艺术-亲和力

一步一步的教程来创造美丽的艺术使用数据工具和亲和力设计

大家好,我是 Gregor,一名数据科学家,一名热情的非竞赛跑步者。我也喜欢摄影艺术,与此同时——和其他一切一样——我仍在学习。

1.介绍

我在全职工作之外保持创造性的策略之一是写数据科学。我最近写了一篇关于如何提取和可视化我的智能手表收集的数据的文章。这是我最喜欢分享的技术和知识。但是最近,我读了一篇来自切斯卡·柯克兰的文章,她在文章中描述了她如何在封锁阶段收集个人数据,以及她如何利用这些数据创作出漂亮的海报,我当时就知道我被忽悠了。我也对数据艺术有所了解,我从乔治·诺比尔和斯蒂芬妮·波萨维克的亲爱的数据项目中找到了美好的灵感。

请跟随我从数据中创造个人艺术的旅程。在这篇文章中,我将向你展示我的设置,包括数据和工具,如何执行创建艺术的步骤,以及如何使用它的想法。

2.设置

为了创造一些与我平时创作完全不同的东西,我使用了不同于其他作品的工具。这里有一个我用过的工具的列表,但是你可以自由地做出你自己的选择。

  1. 数据本身
  2. 数据可视化工具 rawgraphs.io
  3. affinity Designer(Adobe Illustrator 的替代产品)
  4. 额外的图形资源(如纸质背景)

运行数据;作者图片

数据 在我的情况下,我利用了我的 Garmin sport-/智能手表在过去十年中收集的跑步数据。请随意 阅读我的颇具技术性的文章《如何检索和清理此类数据 》。该数据最重要的属性包括日期时间信息以及关于跑步距离的信息。

但是任何数据都可以。正如我在介绍中提到的,我的目标是从个人数据中创造个性化的艺术。这可能包括健身数据(Garmin connect、Strava、Apple Watch)、营养数据(如卡路里摄入量、水消耗量)、健康数据(体重测量、每日步数)。尽管如此,请随意使用您喜欢的任何数据。

https://rawgraphs.io 上可用图表概述(图片由作者提供)

数据可视化工具
但我最近发现了一个名为 rawgraps.io 的免费在线服务,它允许你创建大量不同的数据图表(取决于你的数据类型)。按照我的理解,它在你的浏览器中工作,但是数据没有上传到他们的后端;在你的电脑上,所有的东西都可以在你的浏览器中运行。

RAW Graphs 是一个开源的数据可视化框架,旨在使复杂数据的可视化表示对每个人来说都很容易。RAW Graphs 主要是为设计师和 vis 极客设计的工具,旨在提供电子表格应用程序(如 Microsoft Excel、Apple Numbers、OpenRefine)和矢量图形编辑器(如 Adobe Illustrator、Inkscape、Sketch)之间缺少的链接。— rawgraphic 的网站

他们提供了广泛的图表类型。有些很常见,比如条形图、箱线图、折线图。我发现最有趣的是不属于 MS Excel 或典型数据科学包的图表,如等值线图、桑基图或蜂群图。

卢卡斯·拉克,CC BY-SA 4.0<https://creativecommons.org/licenses/by-sa/4.0,通过维基共享

亲和设计师 如上所述,亲和设计师是 Adobe Illustrator 的替代品。这是一个矢量图形编辑器,它允许你 创建概念艺术、印刷项目、标志、图标、UI 设计、实体模型和更多

它适用于所有平台。与 Adobe 不同,Affinity 产品只需一次性付款,无需任何订阅。它目前减价 50%。如果你正在寻找一个免费/开源的 vector 应用,请尝试一下 Inkscape 。

附加图形资源 我直接从 Affinity 购买了一些纸质的背景。它叫做“ 涂抹水彩&洗 ”。我可以想象,你也可以在网上找到有趣的选择。

3.程序

在接下来的段落中,我将概述我所采取的步骤。

第一步:raw graphs . io
T22 首先,请前往 rawgraphs.io 。在这里,您可以选择将您的数据上传或复制粘贴到网站上(或者在浏览器中)。

截图自 rawgraphs.io(作者提供 gif)

其次,选择一个有趣的情节或图表。在我的例子中,我选择了蜂群图。但是请随意使用你喜欢的任何图表。第三,请向下滚动,直到你到达映射部分。对于 x 轴,我选择了我的日期栏,对于尺寸栏我选择了跑步距离、,对于颜色,我选择了跑步的年份。

当您进一步向下滚动时,图表会自动呈现在您面前。您可以在这里进一步定制。我选择将色标从顺序更改为发散,并更改了配色方案。同样,请随意使用提供给您的选项。最后,将您的图表作为 SVG 文件导出到您的计算机上。

第二步:亲缘关系设计者

首先,我创建一个新文件,长宽比为 5:4 横向(宽:3000 像素,高:2400 像素)。

在关联性设计器中创建新文件;作者图片

其次,我打开左侧的资产窗口,选择涂抹纸。对于我的图像,我选择了纸张#9,并将其拖到屏幕中间的空白画布上。我用手柄来定位它,这样它就覆盖了整个画布。

选择纸质背景;作者图片

第三,我应用一个颜色调整到纸张背景。你可以在菜单栏Layer > New Adjustment > Recolor下找到。我将色调改为 50,饱和度改为 50,亮度改为 9。

对背景应用重新着色调整;作者图片

第四,您可以导入之前创建的 svg 图。将文件从文件浏览器拖到画布中,或者使用File > Place ... > select your image。您可以使用左侧的裁剪工具来调整大小和裁剪。

将图表放入画布;作者图片

接下来,我们将混合模式从正常更改为线性燃烧。你可以在右边的图层面板中实现。只要确保您首先选择了图形图层。

混合模式和标题图表的更改;作者图片

然后,我使用框架文本工具(快捷键 T)在图表上方放置一个文本框架。我把我的图表命名为跑步十年。在图表下方,我添加了一个带有年份和更多信息的图例。随意使用字体、颜色和文本大小。

添加图例;作者图片

当然,在图表中加入一些个人亮点。我发现传统的图表框架几乎不可能做到这一点。

添加个人详细信息;作者图片

第三步:尝试一些变化

这里,完成的定义是什么?我猜每当这个作品被送到印刷厂:-)。我尝试了这个版本的一些变化。为此,我推荐使用画板功能。如果你想了解更多关于 Affinity Designer 的知识,请看看他们的教程。

人像替代;作者图片

在第一个版本之后,我创造了一个肖像的替代品。我还添加了我自己的另一张照片来填补一些空白(在我不常跑步的几年里)。请注意,我为这张额外的图片使用了变暗混合模式。接下来,我对照片进行了一些模糊处理,这样就不会影响到图表,同时也降低了不透明度。

背景照片模糊;作者图片

接下来,我在风景模式下尝试了一个等高线图。我还改变了一些字体和颜色。

等高线图替代;作者图片

Martin Péchy 在 Unsplash 和 Kam Idris 在 Unsplash 的照片;由作者修改

4.结论

在这篇文章中,我向你展示了我从跑步数据中创造个性化艺术的尝试。很明显,我已经超出了我的能力范围,但是它让我尝试了一些新的东西,我肯定可以学到更多关于矢量编辑器的知识。

我将打印并装裱一个版本——希望——说服我的妻子把它挂在我们家的墙上。

你怎么想呢?你有什么反馈给我吗?

如有任何问题和意见,请随时联系我。谢谢你。点击此处查看我的更多文章:

  1. 了解我如何为媒体设计文章
  2. 了解我如何获得和分析我的 Garmin 跑步数据
  3. 了解如何为您的 Python 代码设置日志记录
  4. 了解如何使用链接(或管道)在 Python 中编写干净的代码
  5. 学习如何使用 R 分析你的 LinkedIn 数据
  6. 学习如何使用图形语法在 Python 中以描述性的方式创建图表

Gregor Scheithauer 是一名顾问、数据科学家和研究员。他专门研究流程挖掘、业务流程管理和分析。你可以在LinkedInTwitter上和他联系,或者在 Medium 上这里。谢谢大家!

使用 Excel 和 Tableau 创建定制的投资分析仪表板

原文:https://towardsdatascience.com/create-custom-investment-analytics-dashboards-with-excel-and-tableau-7d304eeebfc4?source=collection_archive---------21-----------------------

投资、数据分析、Excel 和 Tableau

使用 Excel 的 STOCKHISTORY 函数获取股票价格数据和 Tableau 来构建投资分析仪表板

纽约的纽约证券交易所。照片由 Unsplash 上的 David Vives 提供。

“对知识的投资回报最高。” —本杰明·富兰克林

介绍

昨晚,当我回顾我的投资和当天的股市新闻时,一篇关于九月效应的文章引起了我的注意。人们用这个词来描述 9 月份股市低回报的假定历史趋势。在浏览了几篇关于这个话题的文章后,我进一步研究了它,以了解它是否准确,以及它是否会影响我 9 月份的股票投资。

我在我的经纪人网站、谷歌和雅虎上研究股票图表。这些网站提供了令人难以置信的投资分析工具,但没有一个能提供我所需要的东西来更好地理解九月效应的可能模式。所以,我做了我自己的仪表板,而且很有效。仪表板回答了我关于 9 月份股市是否总体持续下跌的问题。

本文将演示如何使用 Microsoft Excel 获取股票价格数据,并在 Tableau 中构建一个九月效应仪表板。您可以使用这里描述的工具和技术来执行各种其他投资分析和跟踪投资。

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

九月效应数据分析项目概述

下面是我制作的“纽约证券交易所综合价格和九月效应”Tableau 仪表板的截图,它帮助我了解九月效应以及它是否真的存在。用 Excel 和 Tableau Public 构建不到两个小时。它应该作为未来定制投资分析项目的坚实基础。

九月效应仪表板。图片由作者提供。

以下是构建仪表板的步骤概述:

  1. 在 Excel 中,使用 STOCKHISTORY 函数检索每个月第一天纽约证券交易所(NYSE)综合指数的价格。例如,获取从 1966 年 1 月到 2021 年 7 月的价格数据。
  2. 在 Excel 中,计算每个月的价格变化和价格变化率。Excel 计算比率如下:比率=(month 2 price-month 1 price)/month 1 price。例如,1966 年 1 月 1 日的价格是 533.33 美元,1966 年 2 月 1 日的价格是 524.56 美元。因此,1966 年 1 月的变化率为-0.0165533853,百分比变化为-1.64%。
  3. 打开 Tableau 桌面或 Tableau 公共桌面应用程序。然后,将 Tableau 连接到上面步骤 1 和 2 中创建的 Excel 电子表格和工作表。
  4. 在 Tableau 中,创建一个九月效应工作表,显示一段时间内 NYSE 指数的价格和每月的价格变化百分比。此外,创建一个工作表,显示按月排序的每月平均价格变化百分比(不包括年份)。最后,创建另一个月度变化工作表,但按价格变化百分比排序。
  5. 组装一个包含上述三个工作表的 Tableau 仪表板。
  6. 将 Tableau 仪表板发布到 Tableau 服务器或 Tableau 公共服务器(在我的例子中)以与最终用户共享。

使用 Microsoft 365 中的股票历史功能

Excel 股票历史功能概述

我使用 Excel 已经很多年了,但是直到昨晚我在谷歌搜索“股票历史”来研究九月效应时,我才听说过它的股票历史功能。发现这个功能促使我建立了投资仪表板。该函数返回指定时间范围内几乎任何股票、ETF、共同基金和一些证券指数的价格历史。

请注意,在作为微软 365 订阅产品一部分的 Excel 的联网版本中,STOCKHISTORY 函数仅在 有效。例如,我订阅了微软 365 系列,所以我立即将 STOCKHISTORY 投入使用。

选择用于股票历史的综合股票指数

STOCKHISTORY 将投资工具(股票、ETF 或共同基金)或综合指数股票作为其第一个参数。我最初想用标准普尔 500(标准普尔 500)综合指数价格来分析九月效应。但是 STOCKHISTORY 只返回了过去十年的月值。因此,在对综合指数做了一些研究后,我选定了纽约证券交易所(NYSE)的综合指数。

纽约证券交易所是一家美国证券交易所,于 1792 年获得了第一笔交易证券。到目前为止,全球最大的证券交易所,其上市公司的市值在 2018 年 2 月达到 30.1 万亿美元。投资者每个交易日都在交易所交易数十亿美元。

纽约证券交易所在 20 世纪 60 年代中期建立了它的综合指数(股票代码:NYA)。1965 年 12 月 31 日开市时,该交易所给该指数的初始值为 50 点。2003 年,纽约证交所将该指数重新设定为 5000 点,接近 2002 年的收盘点位。

今天,纽约证券交易所列出了 2000 多种股票。其中大约 1600 家是美国公司,其余的是外国公司。因此,该指数很好地代表了股票市场。与它的规模相比,标准普尔 500 综合指数列出了 500 家大公司,道琼斯工业平均指数(DJIA)列出了 30 家著名公司。

基于纽约证交所的规模和历史,它似乎很适合我的需求。另外,与标准普尔 500 综合指数不同,STOCKHISTORY 函数返回纽约证券交易所指数从 1966 年 1 月到 2021 年 7 月的月度价格。

利用股票历史获取纽约证券交易所综合指数价格

虽然许多 Excel 函数可以访问多个工作表单元格中的数据,但它们通常在单个单元格中写入和显示数据。另一方面,STOCKHISTORY 可以将数据“溢出”到其他单元格中。例如,查看下面的截图。STOCKHISTORY 函数检索 NYA 股票交易所(NYSE 综合指数)55 年来的月度价格数据。因此,即使函数驻留在单元格 A2 中,其结果也会溢出到区域 A2:B69 中。

在 Excel 中使用股票历史函数。图片由作者提供。

出于我的目的,我将 STOCKHISTORY 调用如下:

=股票历史(" NYA "," 1–1–1966 "," 9–1–2021 ",2,0)

从左至右,以下是其参数的含义:

  1. 股票 —股票、电子资金转账、共同基金、其他证券或指数的代码。在这种情况下,“NYA”是纽约证券交易所综合指数的股票代码。
  2. 开始日期 —所需日期范围的第一天。在这种情况下,该值为“1–1–1966”
  3. 结束日期 —所需日期范围的最后一天。在这种情况下,该值为“9–1–2021”
  4. 间隔 —每个数值代表的时间间隔。允许的值为 0(每天)、1(每周)和 2(每月)。我选择 2(每月),因为我需要按月计算值的变化。

有关 STOCKHISTORY 函数及其参数的更多信息,请参见下面“了解更多”一节中的链接。

“我将告诉你如何变得富有。关上门。当别人贪婪的时候要恐惧。在别人恐惧的时候贪婪。” —沃伦·巴菲特

创建 Excel 电子表格

为了获取纽约证券交易所综合指数(股票代码 NYW)值数据并准备在 Tableau 中使用,我创建了一个名为“NYSE _ June . xlsx”的 Excel 电子表格,其中有一个名为“NYA”的工作表。完成后,它将在四列中包含计划的 Tableau 九月效果仪表板所需的所有数据。

按照以下步骤重新创建 NYA 工作表:

  1. 在第 1 行的 A 到 D 列中,输入“日期”、“价格”、“下个月的价格”和“变化”的列名
  2. 在单元格 A2 中,按照上一节所述输入此公式:=股票历史(" NYA "," 1–1–1966 "," 9–1–2021 ",2,0)
  3. 在单元格 A2 中,按[Enter]键。如果函数正常工作,日期和价格数据应该填充 A 列和 B 列到 69 行。如果没有,请确保您拥有有效的 Microsoft 365 订阅,并且您的计算机已连接到 Internet。
  4. 将 A 列中的每个日期格式化为日期值。为此,右击单元格并点击[单元格格式…]。一个对话框将显示可能的格式列表。单击[日期],然后单击[确定]。
  5. 将此公式输入单元格 C2: =B3 。然后,将公式复制并粘贴到单元格 C3 到 C69 中。虽然这一栏是必要的,但可能并不明显。总之,它的存在确保了单元格 C2 到 C69 中的公式拥有计算其值所需的所有值。
  6. 将此公式输入单元格 D2: =(B3-B2)/B2 。然后,将此公式复制并粘贴到单元格 D3 至 D69 中。对于每个月,该公式计算从当月到下月的价格变化率。
  7. 保存电子表格文件。

该电子表格应该类似于下图所示。请注意列名右侧的向下箭头符号。它们是我添加的过滤器,用来帮助我检查数据。

纽约证券交易所综合指数数据电子表格样本。图片由作者提供。

创建 Tableau 可视化和仪表板

纽约证券交易所综合指数数据已经获得、准备并存储在一个 Excel 文件中。以下总结步骤描述了在 Tableau Public desktop 中连接文件和构建可视化效果。虽然我使用 Tableau 已经超过五年了,但它需要一些尝试和错误。因此,描述创建仪表板的每个步骤的教程超出了本文的目的。

此外,如果您想使用免费的 Tableau Public 而不是整个 Tableau,请注意,您只能将您的工作保存到 Tableau Public 网站。这使得你的可视化可以被世界上的任何人使用。所以,一定要排除网站上的机密信息。

安装 Tableau

若要执行以下步骤,您需要安装 Tableau Desktop 或 Tableau Public Desktop 的副本。要安装 Tableau Public Desktop,请按照 Tableau Public 主页上的说明进行操作,并下载本文末尾“了解更多”一节中列出的链接。Tableau 公共桌面应用程序和 Tableau 公共网站上的发布是免费的。

连接到数据

打开 Tableau 桌面或 Tableau 公共桌面应用程序。然后,按照下面列出的步骤连接到 Excel 电子表格和工作表。参考截图中的例子。

  1. 在“连接”标题下,单击[Excel]。
  2. 在“打开”对话框中,导航到存储 NYSE 综合指数电子表格文件的文件夹。
  3. 单击电子表格的名称,然后单击[打开]。

使用 Tableau 连接到 Excel 文件。图片由作者提供。

月度指数价格数据应该显示在“数据源”窗口中,如下所示。

Excel 中的数据已成功加载到 Tableau 中。图片由作者提供。

构建工作表和控制板

Tableau 项目包含一个名为“纽约证券交易所和九月效应”的仪表板它包括三个工作表,称为“九月效应”、“月度变化”和“月度变化等级”仪表板讲述了“九月效应”的部分故事,至少使用了 1966 年开始的纽约证券交易所综合指数数据。

如上所述,我不会提供组装工作表和仪表板的详细说明。取而代之的是,每张照片的截图会提供它们是如何制作的想法。

Tableau Public 入门

如果您是 Tableau 的新手,我建议您按照以下步骤开始学习如何使用该工具:

  1. 安装免费的 Tableau 公共桌面应用程序。请参阅本文末尾“了解更多”一节中的链接。
  2. 创建一个免费的 Tableau 公共帐户,以便您可以将可视化效果保存并发布到 Tableau 公共网站。
  3. 观看免费的 Tableau 在线培训视频。有关更多信息,请参见下面“了解更多”部分中的培训资源链接。

创建工作表

Tableau 公共桌面应用程序中的“九月效应”工作表如下所示。蓝色线条图描绘了纽约证券交易所综合指数的月值。条形图显示了指数的月度变化(增加或减少)。

纽约证券交易所和九月效应可视化。纽约证券交易所和九月效应可视化。图片由作者提供。

下面显示的“每月变化”工作表以条形图显示了指数每月的平均百分比变化。

纽约证券交易所综合指数月平均变化条形图。图片由作者提供。

如下所示的“月度变化等级”工作表与“月度变化”工作表相同,只是条形图按月度变化百分比降序排列。

纽约证券交易所综合指数月度平均变化条形图,按变化百分比降序排列。图片由作者提供。

创建工作表后,我将它们组装到一个仪表板中,如下所示。请注意,三个图表的时间窗口受位于右下角的“日期范围”过滤器的影响。

Tableau 公共桌面应用程序中的九月效果 Tableau 仪表板。图片由作者提供。

将仪表板发布到 Tableau Public

在改进和测试仪表板及其底层工作表后,我将其发布在 Tableau 公共网站上。你可以在这里看到完成的项目并与之互动。

结论

用 Excel 及其 STOCKHISTORY 功能获取纽约证券交易所综合指数数据的项目以及“九月效应”Tableau 仪表板的构建和使用帮助满足了我的好奇心。当我与仪表板互动时,我更好地理解了九月效应。当我投资股票时,这个项目帮助我确认了我和我的“货币与金融”课教授的共识,他说,“股票市场和任何东西都没有关系。”

通过九月效应项目,我获得了新的知识和技能。我还开发了分析投资证券和市场的新方法。当现有的投资分析仪表板不能满足我的分析需求时,我打算继续使用 Excel、其股票历史功能和 Tableau 来增强我的能力。

我希望你也能从这篇文章中获得新的知识和想法。感谢您的阅读。

“对历史有一个好的视角,我们可以更好地理解过去和现在,从而对未来有一个清晰的愿景。” —卡洛斯·斯利姆·埃卢

关于作者的免责声明

虽然我在软件开发、数据工程和数据分析方面有丰富的专业经验,但我是个业余投资者。请不要依赖这里提供的信息来指导你的投资。请依靠自己的决策和专业的投资建议。

了解更多信息

Excel 股票历史函数

纽约证券交易所

纽约证券交易所综合指数

Tableau 公共主页及下载

免费 Tableau 公共培训资源

从准备发布的数据框架中创建完美的表格

原文:https://towardsdatascience.com/create-flawless-tables-from-your-dataframe-ready-for-publication-7e3fe2d63a52?source=collection_archive---------11-----------------------

杰瑞米·泽罗在 Unsplash 上的照片

教程-表格-R

如何创建发布就绪表的分步教程

我是一名数据科学家,大多数时候,我会考虑一种完美的方式来可视化大量数据,以向客户和团队成员传达有趣的发现。老实说,在大多数情况下,如果不是在所有情况下,以简单的表格形式显示数据及其结构是必要的,并将有助于提高整体理解。

然而,在大多数情况下,我使用 PowerPoint 或 Excel 来创建这个表,以使其看起来可展示和/或可发布。这当然打破了自动重现这一结果的可能性。在我最近的一个项目中,我了解并应用了一个软件包,该软件包允许我在不离开我的数据科学平台的情况下创建漂亮的、可供发布的数据表。

1 简介

在本文中,我将向您展示如何使用 Grammar of Tables (gt)包来创建完美的、准备发布的表格,将您的设置转换为主题以便快速重用,以及如何在您的下一个数据科学项目中应用该主题。

标准普尔 500 数据示例表(图片由作者提供)

2 设置

我的大部分客户工作都涉及到 Python 和熊猫。但是,通过训练,我是一个 R 人。我为 R 数据科学平台解决了这个问题,但是在我即将发表的一篇文章中,我将研究如何使用 Python 和 Pandas 来实现这个问题。

然而,以下是我正在使用的软件和软件包列表:

  1. R & RStudio —语音的数据科学平台和 IDE。
  2. tidyverse 包——这个包允许我编写优雅、可读、高效的代码来操作数据帧
  3. gt 包 —表格语法(gt)包,打造完美的表格设计
  4. Gapminder 软件包——Gapminder 按国家分列的预期寿命、人均国内生产总值和人口数据摘录

2.1 表格语法概述(gt)

gt 包遵循一种描述性的方法来创建表格,比如图形的语法。简而言之,它允许我们指定什么应该发生,而不是指定如何应该发生——这是编写代码的一种非常棒且可读的方式。

gt 表的零件(图片来源:https://gt.rstudio.com)

gt 包定义了大量的区域来添加到您的表中,并操纵它们的可视化。在下面的例子中,我将向你解释如何使用这些区域。

还需要注意的是,您可以为 R notebook 创建一个表格,并以多种格式保存该表格,包括 HTML 和 PNG,如果您需要在不同的出版物(如网站或 PowerPoint 文档)中报告表格,这将非常有用。

2.2 包和常量

在开始创建一个表之前,我先分享一下这段代码,它将加载(如果有必要的话,还会安装)必需的包:

我还使用了一些帮助我编写灵活的 R 脚本的常量。请注意,我使用 c_rn 来指定表中包含的最大行数,使用 c_save 来确定是否将表创建过程的每一步都保存为文件(这需要一点时间),使用 c_format 来指定输出格式。

Gapminder 数据集的一般输出如下所示:

标准控制台输出(图片由作者提供)

3 创建一个完美的、准备发布的表格

gt 包最基本的用途只是将过滤后的数据帧传递给 gt 函数。不过,这并不太令人兴奋,也没有给标准控制台输出带来任何好处。

标准 gt 输出(图片由作者提供)

3.1 添加分组列

这可能与您的大多数数据框无关。然而,我想展示这是如何工作的,这将有助于更好地理解你的表。为此,我将列 continental 作为分组列传递,并将 country 列指定为行标签列。

添加分组列(图片由作者提供)

3.2 添加汇总行

下面的代码允许我们添加汇总行。摘要可能包含的内容由你决定,并对你的听众有价值。我决定添加函数 sum、average 和 standard deviation。虽然不是所有的汇总函数对这个数据集都有意义,但我想展示如何实现它们。

添加汇总行(作者图片)

3.3 更改每列的标签

我相信你在你的项目中也经历了这一点。如何给你的栏目贴标签?您的数据框通常使用技术名称(即,不含空格的短名称),但也有对受众有意义的功能名称。Gapminder 数据集中的一个例子是真正代表“预期寿命”的列 lifeExp。gt 包允许我们在不改变数据集的情况下改变结果表的标签。

更改标签名称(图片由作者提供)

3.4 格式化列

格式化列包括几个方面。在这个例子中,我告诉包区分数字和货币列,它们的对齐方式,以及它们应该有多少空间(px)。opt_row_striping()函数创建带状行,以提高表格的可读性。

格式化列(图片由作者提供)

3.5 添加标题、脚注和来源

如果您计划将所有相关的元信息作为表布局的一部分,gt 包将会帮助您。尤其是脚注的可能性是有益的,因为你可以对它应用一个函数。在下面的例子中,将为人口最少的国家添加一个脚注。请注意,可以使用 md 函数使用标记来修改文本布局。

添加标题、脚注和来源(图片由作者提供)

3.6 对表格应用格式

这是一个相当长的问题,但是我希望代码能够解释这里可能会发生什么。请注意,我使用了函数 tab_options() 以及 tab_style() 。tab_options 看起来像是操纵一般的设置,而 tab_style 用于更具体的位置。请分享你的想法来简化下面的代码。非常感谢。

将格式应用于表格(图片由作者提供)

3.7 应用条件单元格着色

gt 包的另一个有用的特性是基于值给单元格着色的能力。在下面的例子中,我将以两种不同的方式使用它。首先,我想为第一个中的“预期寿命”一栏应用蓝色底纹。为此,我将使用名为 c_col 的调色板,它在开始时被指定为常量之一。

我想用第二种方法将人口最少的行涂成蓝色。

应用条件单元格颜色(图片由作者提供)

4 创建可重复使用的 gt 主题

为了创建一个主题,我需要理解如何区分与外观相关的设置和与特定于数据的列相关的设置(这将随着每个数据集而改变)。为了展示这一点,我将使用数据集“每日标准普尔 500 指数数据”,它是 gt 包的一部分。

4.1 从 S & P 数据集创建一个 gt 表

标准 gt 表输出(图片由作者提供)

4.2 创建主题

我创建了一个函数 my_theme() ,它可以快速应用于你的任何 gt 表。

主题 gt 表输出(图片由作者提供)

请注意,这个主题是用我有限的知识构建的。因此,请分享如何改进和简化这段代码的想法。非常感谢。

4.3 应用特定于列的格式

剩下的步骤是格式化特定于 S&P 的列。首先,我用货币格式指定列。

格式化列(图片由作者提供)

最后,我向表中添加汇总行,包括平均值和标准偏差。

添加了汇总行(图片由作者提供)

5 结论

在本文中,我向您介绍了 gt 包。然后,我向您展示了如何格式化表格、包含汇总行以及应用条件单元格格式。此外,我解释了如何创建一个单独的主题,您可以在每个数据项目中重用它。

请注意,我只是触及了 gt 包的表面。此外,我的知识可能有限,有更好的方法用更少的代码实现这些结果。如果你有兴趣,请接触其他教程,进一步教育自己。我很高兴与下面的列表分享伟大的教程:

  • http://www . danieldsjoberg . com/gt-and-gt summary-presentation/# 1
  • https://themockup.blog/static/slides/intro-tables.html#1
  • https://malco . io/2020/05/16/replication-an-nyt-table-of-Swedish-covid-deaths-with-gt/
  • https://themockup . blog/posts/2020-05-16-gt-a-grammer-of-tables/

你怎么看?你有什么反馈给我吗?

如有任何问题和意见,请随时联系我。谢谢你。

为您的时间序列数据创建 GitHub 的风格贡献图

原文:https://towardsdatascience.com/create-githubs-style-contributions-plot-for-your-time-series-data-79df84ec93da?source=collection_archive---------18-----------------------

让您的热图脱颖而出

墙上的另一块砖|作者图片

Github 贡献图显示了您在过去一年中对存储库的贡献。一张填满的贡献图不仅看起来赏心悦目,还表明了你的努力工作(除非你已经黑了它)。图表虽然漂亮,但也显示了关于你的表现的大量信息。然而,如果你仔细观察,它只是一个显示一些时间序列数据的热图。因此,作为一项周末活动,我试图复制一些基本时间序列数据的图表,通过本文与您分享这一过程。

数据集和一些预处理

我将在本文中使用的数据集来自 Kaggle 上的表格游乐场系列(TPS)竞赛。TPS 竞赛为期一个月,于每月 1 日开始。我将使用 TPS — 七月版竞赛 中的数据集。

数据集是基于时间序列的数据,其任务是根据基本天气信息(温度和湿度)和 5 个传感器的输入值,预测空气污染测量值随时间的变化。

让我们导入基本库并在 pandas 中解析数据集。

import pandas as pd
import numpy as np
import datetime as dt
from datetime import datetimedata = pd.read_csv(‘train.csv’, parse_dates=[‘date_time’])
data.head()

时间序列数据集

对于我们的目的来说,这是一个相当不错的数据集。我们开始工作吧。

使用 Seaborn 库创建基本热图

Seaborn 是 Python 中的统计数据可视化库。它基于 matplotlib,但是有一些很棒的默认主题和绘图选项。从技术上讲,创建热图本质上是用颜色替换数字。更准确地说,这意味着将数据绘制成颜色编码的矩阵。让我们看看如何通过代码实现这一点。但在此之前,我们必须将数据转换成所需的格式

#Importing the seaborn library along with other dependenciesimport seaborn as sns
import matplotlib.pyplot as plt
import datetime as dt
from datetime import datetime# Creating new features from the datadata['year'] = data.date_time.dt.year
data['month'] = data.date_time.dt.month
data['Weekday'] = data.date_time.dt.day_name()

对数据进行子集化,只包含year 2010 ,然后丢弃除了monthweekdayanddeg_C.之外的所有列,然后我们将旋转数据集,得到一个类似矩阵的结构

data_2010 = data[data['year'] == 2010]
data_2010 = data_2010[['month','Weekday','deg_C']]pivoted_data = pd.pivot_table(train_2010, values='deg_C', index=['Weekday'] , columns=['month'], aggfunc=np.mean) 

由于我们的数据集已经以矩阵的形式存在,现在用 seaborn 绘制热图只是小菜一碟。

plt.figure(figsize = (16,6))
sns.heatmap(pivoted_data, linewidths=5, cmap='YlGn',linecolor='white', square=True)

使用 Seaborn 库创建的热图|图片由作者提供

热图显示了 2010 年的平均温度(摄氏度)。我们可以清楚地看到,7 月是当年最热的一个月。为了模拟 Github 的贡献图,使用了一些参数:

  • pivoted_data:使用的数据集
  • 线宽:分隔每个单元格的线的宽度。
  • 线条颜色:划分单元格的线条的颜色
  • 方形:确保每个单元格都是方形的

这是一个很好的尝试,但仍有改进的余地。我们还没有接近 Github 的贡献图。让我们用另一个库再试一次。

使用 calmap 创建日历热图

Python 中有一个名为 calmap 的专用库,而不是对 seaborn 进行修补。它根据 Github 贡献图中的时间序列数据创建了漂亮的日历热图,而且只用了一行代码。

#Installing and importing the calmap library
pip install calmap#import the library
import calmap

我们将使用与上一节相同的数据集,并使用yearplot()方法来绘制。

#Setting the date_time column as the index
data = data.set_index('date_time')#plotting the calender heatmap for the year 2010
plt.figure(figsize=(20,10))
calmap.**yearplot**(data['deg_C'], cmap='YlGn', fillcolor='lightgrey',daylabels='MTWTFSS',dayticks=[0, 2, 4, 6],
                linewidth=2)

使用 calmap 库创建的热图|图片由作者提供

上面,我们已经定制了colorlinewidthfillcolor,即在没有数据的日子里使用的颜色。您可以根据需要设置这些值。更多信息可从文档中获得。

也可以使用[**calendarplot()**](https://pythonhosted.org/calmap/#calmap.calendarplot) method.将所有年份作为支线剧情绘制成一个图形

fig_kws=dict(figsize=(20, 10)

带有 calmap 库的 Calenderplots 按作者分类的图像

如你所见,2011 年的数据并不多,但我相信你已经有了想法。

包裹

热图是有用的可视化工具,通过使用颜色提供深度透视来帮助传达模式。它有助于可视化矩阵的两个维度之间的值的集中,这对人眼来说比单纯的数字更明显。这篇文章向你展示了如何让你的热图变得更明亮、更生动,并在创建热图时获得乐趣。

在 R and R 创建交互式地图应用程序,探索地理空间数据

原文:https://towardsdatascience.com/create-interactive-map-applications-in-r-and-r-shiny-for-exploring-geospatial-data-96b0f9692f0f?source=collection_archive---------0-----------------------

使用地图进行输入选择的 Web 应用程序

作者制作的动画

数字所能讲述的重要故事通常与地点有关。地理空间数据(或空间数据,也称为地理数据)是指由地理位置指示或与地理位置相关的任何数据( REF )。地理空间数据将地址、邮政编码或区域等位置信息与和该位置相关联的相应属性信息相结合。

对于大多数人来说,如果不使用地图,很难探索地理空间数据。通过这个应用程序,我们展示了如何使用 R and R Shiny 创建一个免费的开源(FOSS)解决方案,允许用户与地理空间数据进行交互,并使用交互式地图快速找到他们想要看到的内容。

Web 应用程序设计

我们选择使用 运费分析框架【FAF】数据进行本次论证。FAF 是一个公共数据源,提供各州和主要大都市地区之间所有运输方式的货运流量的估计和预测。

与 FAF 数据相关联的地理信息被定义为区域。在美国大陆地区总共有 129 个 FAF 区,每个区都可以是起点区或终点区。换句话说,有 129×129 个可能的始发地-目的地区域对组合。

用户可以浏览他们选择的任何始发地和目的地区域对之间的货运数据。该工具提供了一种直观的方法,用户可以直接从地图上选择一个区域,同时获得区域的位置、大小和边界信息,而不是从 129 个区域的长列表中选择一个区域。

运费分析框架区域(图片由作者提供)

用户可以通过点击区域直接从地图上选择始发地和目的地区域来选择他们想要查看的数据。他们可以放大、缩小或平移地图来查找感兴趣的区域。

如果单击原点,原点区域的质心将显示为绿色。如果单击目标区域,目标区域的质心将显示为红色。我们将在本文后面解释当选择一个区域时,如何确定区域类型(即起点和终点)。

一旦选择了始发地和目的地区域,应用程序后端的 R 脚本将查询 FAF 数据,并将结果显示为所选始发地-目的地区域对的数据表和图表。

我们将一步一步地解释这个 web 应用程序的实现,如下所示:

  1. R and R 闪亮简介
  2. 布局用户界面(UI)
  3. 设置服务器以生成输出
  4. 免费发布闪亮的应用

注:这篇文章的代码和数据可以在this GitHub repo找到。

1.R and R 闪亮简介

r 是一种用于统计计算和图形的语言和环境。R 的优势之一是可以很容易地制作出设计良好的出版物质量的情节。(参考

Shiny 是 R 的一个 web 应用程序框架,它结合了 R 的计算能力和现代 web 的交互性。Shiny 为开发者提供了卓越的能力来创建 web 应用程序,这些应用程序可以使用你自己的服务器或 Shiny 的托管服务来部署。

闪亮应用的结构

Shiny app 是一个目录,包含两个 R 脚本,即ui.Rserver.R 以及其他输入到 app 的文件。

ui.R控制应用程序的布局和外观,并在闪亮的应用程序中创建用户界面。它通过接受用户输入并在屏幕上动态显示生成的输出来为应用程序提供交互性。

server.R包含构建应用程序逻辑的指令,因此它就像是应用程序的大脑。它将用户的输入转换成想要的输出,如表格和图表,显示在屏幕上。

或者,Shiny app 可以由一个名为app.R的文件组成,该文件包含 UI 和服务器组件。一个只有一个文件(即app.R)的闪亮应用的基本结构如下所示:

library(shiny)ui <- fluidPage(
  # front end interface
)server <- function(input, output, session) {
  # back end logic
}shinyApp(ui = ui, server = server)

保持两个独立的 R 文件,即ui.Rserver.R 通常被认为是一个好的实践,特别是对于较大的应用程序,具有独立的ui.Rserver.R文件使得代码更容易管理。

2.布局用户界面(UI)

首先,我们将所有需要的库加载到应用程序中。应用程序界面通常使用fluidPage 创建,这样可以确保页面根据每个设备的分辨率动态布局( REF ),这样应用程序界面可以在不同屏幕分辨率的不同设备上流畅运行。

我们使用fluidRowcolumn从网格系统构建我们的定制布局。行由fluidRow()函数创建,包括由column()函数定义的列( REF )。

我们还使用 Shiny 的 HTML 标签函数为用户界面添加内容,比如br, div, span, HTML等。这些功能与常见的 HTML5 标签相似。

使用span()函数添加的应用程序“运费分析框架 FAF4 vs. FAF5,2017 年”的标题显示在界面顶部,后面是一个fluidRow(),左边是一个名为“Zone”的地图,右边是一组静态(如span("select"))和动态文本输出(如htmlOutput("od_info"))。

闪亮的应用程序包含输入和输出对象。输入允许用户通过修改他们的值与应用程序交互(我们将在后面讨论输入对象)。输出是显示在应用程序中的对象(参考)。输出对象总是与渲染函数配合使用,例如:

ui <- fluidPage(
  leafletOutput("Zone")
)server <- function(input, output, session) {
  output$Zone <- renderLeaflet({
    # generate the map
  })
}

ui中我们使用leafletOutput(),在server()中我们使用renderLeaflet()。在renderLeaflet()中,我们写下返回传单地图的说明。

此应用程序中显示的输出对象类型包括:

活页 用于创建交互式地图,如leafletOutput("Zone")

html 用于将反应输出变量显示为 html,如htmlOutput("od_info")

DT 用于显示交互表格中的数据,如DT:dataTableOutput("od_vol")

plotly 用于创建与数据交互的图形,如plotlyOutput("od_ton_chart”)

3.设置服务器以生成输出

导入数据文件

数据文件与 R 文件位于相同的位置。我们使用read.csv()函数读取 CSV 文件(centroid.csv``od_mode_vol_45.csv),使用 rgdal 包的readOGR()函数读取 FAF 区域的 shape file(faf4_zone2.shp)。

区域 shapefile 中的每个要素都是一个多边形。以下是 shapefile 中属性数据的示例。表中的每一行都用区域 ID、区域名称和几何定义了一个多面要素(即区域)。

来自 faf4_zone2 的数据示例(图片由作者提供)

centroid.csv中的每一行用区域 id、区域名称、经度和纬度定义了一个 FAF 区域质心(即区域的中心位置)。注意centroid.csv中的区域 ID 和区域名称与 shapefile 中的对应。因此,我们可以使用区域 ID 作为从区域多边形到区域质心的关键字,反之亦然。

数据示例来自 centroid.csv(图片由作者提供)

od_mode_vol_45.csv 包含每个始发地-目的地区域对(使用区域 id 定义)按运输方式(如卡车、铁路、水路、航空等)计算的重量和价值的货运数据。此文件中的数据是从原始的 FAF 版本 5 (FAF5)数据和 FAF 版本 4 (FAF4)数据设计而来的。

FAF5 数据提供 2017 年的货运走势预估;而 FAF4 数据提供了 2017 年 的货运预测 。该应用程序比较了每个始发地-目的地对的 FAF5 与 FAF4 的 2017 年数据。

文件od_mode_vol_45.csv中的起点 ID 和终点 ID 对应于centroid.csvfaf4_zone2.shp中的区域 ID 字段。

数据样本来自 od_mode_vol_45.csv(图片由作者提供)

使用全局变量来跟踪区域选择

让我们先解决房间里的大象。应用程序需要判断点击(或选择)的区域应该是起始区域还是目标区域。

我们假设当用户开始使用应用程序时,第一个点击的区域将是源区域,第二个点击的区域将是目标区域。

然而,如果用户希望通过选择另一对始发地和目的地区域来继续使用该应用程序,该怎么办?如果用户在地图上不断点击,不断改变选择怎么办?

为了解决这个问题,我们需要跟踪用户点击地图的总次数。

下面的全局变量用于跟踪用户的区域选择动作。因为我们需要在不同的函数中访问和改变这些变量的值,所以有必要将这些变量定义为全局变量。

*click_count <- 0
type <- 0
origin <- ""
dest <- ""
origin_id <- 0
dest_id <- 0*
  • 变量click_count用于跟踪自会话开始以来地图上的累计点击次数。 注意其初始值设为 0
  • 变量type用于将click_count转换为区域类型,即始发地区域或目的地区域。它的值由模数click_count乘以 2 计算得出:
*# with click_count initiated with value 0type <<- click_count%%2if (type ==0 ){
  # treat as origin zone
}     
if (type == 1){
  # treat as destination zone
}# add one to the accumulative map click counts
click_count <<- click_count+1*

上面的代码将被嵌入到一个函数中,要改变函数内部全局变量的值,我们需要使用全局赋值操作符<<-。当使用赋值运算符<<-时,该变量属于全局范围。

  • 变量origindest用于存储所选始发地和目的地区域的描述性区域名称。
  • 变量origin_iddest_id用于存储所选起点和终点区域的区域 id。

Shiny 中的反应式编程

Shiny 使用一个反应式编程模型来简化 R-powered web 应用程序的开发。Shiny 从用户界面获取输入,用 监听变化,观察无功。

反应源通常是通过浏览器界面的用户输入。我们通过在构建输出的server()中的反应表达式(如render*()reactive()函数)中包含输入input$variable_selected 的值来创建反应。当输入发生变化时,所有依赖于输入的输出都将使用更新后的输入值自动更新(或重建)。

传单 当用户与地图和对象交互时,它们会将输入值(或事件)发送到 Shiny。对象事件名称通常使用这种模式:

输入$MAPID_OBJCATEGORY_EVENTNAME

对于leafletOutput("Zone"),点击其中一个多边形形状(即 FAF 区)将在input$Zone_shape_click更新闪亮的输入。

点击事件被设置为 NULL(如果该事件从未发生过),或者 list()包括:对象的纬度和经度是可用的;否则,鼠标光标;和 layerId,如果有的话。

在我们的例子中,基于区域 Id 的 layerId 字段包含在多边形对象中;因此区域 ID 的值将在input$Zone_shape_click事件的事件$Id* 中返回。*

*addPolygons(data=zone.rg, col="black", weight = 1, **layerId = ~id**, label = zone_labels, highlight = highlightOptions(color = "blue",weight = 2, bringToFront = F, opacity = 0.7))*

我们希望应用程序的服务器端对地图上的点击做出响应,所以我们需要创建反应式表达式,使用reactive()函数来结合用户的选择。使用reactive()函数也有助于减少代码中的重复。

selected_zone()返回点击(或选择)区域的质心。

*selected_zone <- reactive({
      p <- input$Zone_shape_click
      subset(centroid, id==p$id )
    })*

selected_od()返回所选始发地-目的地区域对的信息(包括区域名称和区域 id)。请注意,它会一直等待,直到选择了起始区域和目标区域才返回值。

如果选择了一个新的原点区域,上一轮选择的目的区域将被重置。

*selected_od <- reactive({
      p <- input$Zone_shape_click
      # return selected origin-destination zone pair
    })*

使用带光泽的传单

传单 是最流行的用于交互式地图的开源 JavaScript 库之一。 活页 包装包含强大而方便的功能,可与闪亮的应用程序集成(参考)。可以通过以下基本步骤创建传单地图:

  1. 通过调用 leaflet()创建地图小部件
  2. 通过使用图层功能(例如,添加切片、添加标记、添加多边形)来修改地图微件,将图层(即,要素)添加到地图中。
  3. 根据需要重复步骤 2。
  4. 打印地图微件以显示它。
*output$Zone <- renderLeaflet({
  # create zone labels
  # create map widget called m
  # add base map and the FAF zone polygon layer
})*

观察者使用热切评估策略,即一旦他们的依赖关系改变,他们就调度自己重新执行。

现在我们更新input$Zone_shape_click对应的地图。当input$Zone_shape_click改变时,观察器将自动重新执行。

*observe({
      p <- input$Zone_shape_click # get input value
      if (is.null(p))             
        return()

      m2<-leafletProxy("Zone", session = session) # get map widget

      # create zone labels

      selected <- selected_zone() # get selected zone centroid
      # create selected zone label

      type <<- click_count%%2
      if (type ==0 ){ 
        # clear the centroids displayed
        # add a marker, the centroid of the new origin zone
      }

      if (type == 1){
        # add a marker, the centroid of the new destination zone
      }
      click_count <<- click_count+1    # keep track of map clicks
    })*

首先获取所选区域,并使用前面解释的逻辑确定所选区域是源区域还是目标区域。通过显示所选区域的质心来更新地图,并对起点和终点使用不同的颜色。

为了修改页面中已经运行的地图,我们使用了leafletProxy()函数来代替*leaflet()*调用。

通常我们使用leaflet来创建地图的静态方面,使用leafletProxy来管理动态元素,这样就可以在点击时更新地图,而不用重新绘制整个地图。关于如何使用该功能的详细信息,请参见 RStudio 网站。

添加输出

现在,我们在 Shiny 应用程序中显示数据,包括几个用于交互式可视化的输出。

output$od_info 对象是无功端点,它使用无功源input$Zone_shape_click。每当input$Zone_shape_click改变时,output$od_info被通知需要重新执行。此输出动态显示选定的源区域和目标区域的名称。

od_info 的输出(图片由作者提供)

我们使用 R package DT 将数据对象(矩阵或数据框)显示为 HTML 页面上的表格。在output$od_vol中,我们首先通过selected_od()获取所选始发地和目的地区域的信息,然后过滤od_mode_vol中存储的 FAF 数据,以获取所选始发地和目的地区域对的结果。

所选始发地和目的地区域对的 FAF 数据比较(图片由作者提供)

除了将查询结果显示为数据表之外,我们还使用条形图和圆环图来显示结果。

作者图片

我们使用renderPlotly()函数来渲染一个反应式表达式,该表达式根据输入值input$Zone_shape_clickselected_od() 生成**图形。**

要制作一个圆环图,使用add_pie()函数的hole= 参数设置要从饼图中切掉的半径的分数。该值可以在0.010.99之间。

4.免费发布闪亮的应用

Shinyapps.io 是一款软件即服务(SaaS)产品,用于在云中托管闪亮的应用。RStudio 负责托管应用程序和维护服务器的所有细节,因此我们可以专注于编写应用程序。

一个闪亮的应用程序可以在几分钟内部署到 shinyapps.io 上。只要按照这个详细的一步一步的指示就可以了。

Shinyapps.io 提供免费和付费计划。通过免费计划,您可以同时部署多达 5 个闪亮的应用程序,并且每月有多达 25 个小时的活动时间由该帐户下托管的所有应用程序共享。

***https://huajing-shi.medium.com/membership

r 代码和输入数据可从 my GitHub repo 获得。***

参考

  1. 闪亮应用的基本组成部分
  2. shiny apps . io 入门
  3. 在 R 中使用闪亮的应用程序创建交互式数据可视化(带示例)

使用小部件在 Google Colab 中创建交互式工具

原文:https://towardsdatascience.com/create-interactive-tools-in-google-colab-using-widgets-8a1a504d3b7e?source=collection_archive---------10-----------------------

一个 Python 应用程序,可以读取你的每日星象

作者制作的动画

在充满不确定性的时代,你不会想知道未来会怎样吗?让我们在学习如何用 Python 创建一个用户友好的工具来阅读你的每日星座运势的同时,停止担心,找点乐子吧。

作为编码练习,我设想在 Python 笔记本中创建一个交互式工具,如上面的动画所示。用户只需点击按钮,就可以很容易地看到不同的程序输入如何改变输出。

该程序将使用 Google Colab 来实现,以便更容易与最终用户共享,特别是那些没有编码和没有在他们的计算机上安装 Python 的用户。在我的上一篇文章中,我解释了为什么我选择 Google Colab 进行 Python 编程。

程序设计

通过的交互式图形用户界面为用户创造一种身临其境的、有趣的体验,我们可以将静态代码转化为探索的工具,让 Python 笔记本变得生动起来。

Python 中有一个有趣的库叫做 PyAztro ,它提供了太阳星座的星座信息。一旦指定一个标志名称,以及日期类型("昨天"、"今天"或"明天"),则 pyaztro。Aztro() 函数返回当天所选星座的相关信息,包括幸运数字、幸运颜色、心情、与其他太阳星座的兼容性以及描述等。每日占星读数每天在格林威治时间午夜(格林威治标准时间)更新,所以你每天都有新读数!

用户可以从日期范围标记的星座图像列表中选择一个太阳星座(或星星星座),然后单击与该星座相关的按钮来获得星座读数。

该计划的实施可分为以下几个步骤:

  1. 安装缺失的 Python 库
  2. 从网上抓取星座图像
  3. 创建一个变量来保存星座图像和相应的日期范围
  4. 生成星座阅读工具的用户界面

这里可以下载笔记本。

程序实现

第一步。在 Google Colab 中安装 Python 库

*!pip install pyaztro*

PyAztro 库默认不安装在 Colab 中,我们需要先安装。要在 Colab 中运行任何命令行脚本,您需要添加一个!在行首。

第二步。从网上抓取星座图像

为了获得标牌图像,我们从 Python 图像库(PIL) 中导入图像,并调用 Image.open() 来创建来自网站的图像文件的图像对象。使用 Image.open() 接收的图像对象,以后可以应用调整大小、裁剪、绘制或其他图像操作方法调用。**

第三步。创建一个变量来保存星座图像和相应的日期范围

创建一个列表变量来保存每个标志的数据,包括标志名称、图像对象和日期范围。

第四步。生成星座阅读工具的用户界面

为十二个太阳星座创建了十二个按钮的列表。来自 ipywidgets 的 按钮小部件(也称为 jupyter-widgets 或简称为小部件)用于处理鼠标点击。按钮的 on_click 方法可以用来注册点击按钮时要调用的函数。****

点击按钮时,将调用 on_button_clicked() 函数,从 pyaztro 中生成所选星座的星座读数。Aztro() 。循环的用于返回三天中每一天的符号读数,即昨天、今天和明天。**

输出小部件 可以捕获并显示 IPython 生成的 stdout、stderr 和 rich 输出。输出可以直接追加从输出小工具中清除为了避免在一系列按钮点击后累积输出,我们需要在显示新输出前清除先前的输出。输出小部件是 interact 的基础,因为它构成了如何实现 interact 和相关方法的基础。****

为了让应用程序看起来对用户有吸引力,应用程序的组件(即图像、按钮和文本)的布局是一个需要考虑的重要因素。为了排列十二个标志图像、相应的日期范围和按钮,我们使用Colab 的布局小部件中的 网格 ,这些小部件使能够将未来的输出重定向到布局中的特定位置。图像对象的大小被调整为适合布局。**

这是这个占星阅读程序的界面:

作者图片

****https://huajing-shi.medium.com/membership

源代码:GitHub 上的谷歌可乐笔记本****

本文的灵感来自“蟒蛇的隐藏宝藏”

**** ****

如何基于 Pandas 中其他列的值创建新列

原文:https://towardsdatascience.com/create-new-column-based-on-other-columns-pandas-5586d87de73d?source=collection_archive---------0-----------------------

讨论如何从 pandas 数据框架中的现有列创建新列

照片由张秀坤镰刀在 Unsplash

介绍

作为数据处理或特征工程的一部分,我们通常需要在现有列的基础上创建额外的列。在今天的简短指南中,我们将探索如何在熊猫身上进行这样的操作。

具体来说,我们将探索如何以几种不同的方式实现这一点,使用

  • apply()方法
  • numpy.select()方法(对于矢量化方法)
  • loc地产

首先,让我们创建一个示例 DataFrame,我们将在整篇文章中引用它来演示一些概念,并展示如何基于现有列的值创建新列。

import pandas as pd

df = pd.DataFrame(
    [
        (1, 'Hello', 158, True, 12.8),
        (2, 'Hey', 567, False, 74.2),
        (3, 'Hi', 123, False, 1.1),
        (4, 'Howdy', 578, True, 45.8),
        (5, 'Hello', 418, True, 21.1),
        (6, 'Hi', 98, False, 98.1),
    ],
    columns=['colA', 'colB', 'colC', 'colD', 'colE']
)
print(df)
   colA   colB  colC   colD  colE
0     1  Hello   158   True  12.8
1     2    Hey   567  False  74.2
2     3     Hi   123  False   1.1
3     4  Howdy   578   True  45.8
4     5  Hello   418   True  21.1
5     6     Hi    98  False  98.1

使用 apply()方法

如果您需要在现有列上应用一个方法,以便计算一些最终将作为新列添加到现有数据框架中的值,那么[pandas.DataFrame.apply()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.apply.html)方法应该可以做到。

例如,您可以定义自己的方法,然后将其传递给apply()方法。假设我们想要创建一个名为colF的新列,它将基于列colC的值使用下面定义的categorise()方法创建:

def categorise(row):  
    if row['colC'] > 0 and row['colC'] <= 99:
        return 'A'
    elif row['colC'] > 100 and row['colC'] <= 199:
        return 'B'
    elif row['colC'] > 200  and row['colC'] <= 299:
        return 'C'
    return 'D'

你需要做的就是将上述方法作为 lambda 表达式传递给apply():

df['colF'] = df.apply(lambda row: categorise(row), axis=1)

print(df)
   colA   colB  colC   colD  colE colF
0     1  Hello   158   True  12.8    B
1     2    Hey   567  False  74.2    D
2     3     Hi   123  False   1.1    B
3     4  Howdy   578   True  45.8    D
4     5  Hello   418   True  21.1    D
5     6     Hi    98  False  98.1    A

对于更简单的操作,您可以将 lambda 表达式直接指定给apply()方法。例如,假设我们想要创建另一个名为colG的列,它将把列colCcolE的值加在一起。以下内容应该可以解决问题:

df['colG'] = df.apply(lambda row: row.colC + row.colE, axis=1)

print(df)
   colA   colB  colC   colD  colE colF   colG
0     1  Hello   158   True  12.8    B  170.8
1     2    Hey   567  False  74.2    D  641.2
2     3     Hi   123  False   1.1    B  124.1
3     4  Howdy   578   True  45.8    D  623.8
4     5  Hello   418   True  21.1    D  439.1
5     6     Hi    98  False  98.1    A  196.1

使用 NumPy 的 select()方法

现在,一种更矢量化的方法(在性能方面可能更好)是使用 NumPy 的select()方法,如下所述。

同样,假设我们想要创建一个名为colF的新列,它将基于列colC的值来创建。这一次,我们将创建一个包含所需条件的列表,而不是定义一个函数。

import numpy as np
conditions = [
  np.logical_and(df['colC'].gt(0), np.less_equal(df['colC'], 99)),
  np.logical_and(df['colC'].gt(100), np.less_equal(df['colC'],199)),
  np.logical_and(df['colC'].gt(200), np.less_equal(df['colC'],299)),
]

然后,我们定义一个额外的列表,其中包含新列将包含的相应值。注意,在下面的列表中,我们不包括默认值D

outputs = ['A', 'B', 'C']

最后,我们使用select()方法来应用条件,并指定当指定的条件都不满足时将使用的默认值。

df['colF'] = pd.Series(np.select(conditions, outputs, 'D'))

print(df)
    colA   colB  colC   colD  colE colF
0     1  Hello   158   True  12.8    B
1     2    Hey   567  False  74.2    D
2     3     Hi   123  False   1.1    B
3     4  Howdy   578   True  45.8    D
4     5  Hello   418   True  21.1    D
5     6     Hi    98  False  98.1    A

使用 loc 属性

最后,另一个选择是loc属性,在某些情况下,它可能比apply()方法更有效。请注意,与我们之前讨论过的解决方案相比,这种方法可能会更加冗长。

df.loc[
  np.logical_and(df['colC'].gt(0), np.less_equal(df['colC'], 99)), 
  'colF'
] = 'A'
df.loc[
  np.logical_and(df['colC'].gt(100), np.less_equal(df['colC'], 199)),'colF'
] = 'B'
df.loc[
  np.logical_and(df['colC'].gt(200), np.less_equal(df['colC'], 299)),'colF'
] = 'C'
df['colF'].fillna('D', inplace=True)

print(df)
   colA   colB  colC   colD  colE colF
0     1  Hello   158   True  12.8    B
1     2    Hey   567  False  74.2    D
2     3     Hi   123  False   1.1    B
3     4  Howdy   578   True  45.8    D
4     5  Hello   418   True  21.1    D
5     6     Hi    98  False  98.1    A

最后的想法

在今天的简短指南中,我们讨论了根据现有列的值在 pandas 数据框架中添加新列。具体来说,我们展示了如何在 pandas 中使用apply()方法和loc[]属性来实现这一点,如果您对更加矢量化的方法感兴趣,还可以使用 NumPy 的select()方法。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

你可能也会喜欢

https://medium.com/geekculture/how-to-refine-your-google-search-and-get-better-results-c774cde9901c

用几行代码创建组织图(5 分钟学习)

原文:https://towardsdatascience.com/create-organization-diagrams-in-a-few-lines-of-code-the-5-minute-learn-dcca81dac3a2?source=collection_archive---------8-----------------------

如何用 R 和 Python 来实现

作者生成

组织结构图非常受欢迎,但创建起来确实令人头疼。创建它们的手动软件既烦人又费时。如果我们只用几行代码就能把它们组装起来,那不是很好吗?

好消息是,只要有正确的数据,你就可以做到,因为组织图是一种特殊类型的图表,称为树或树状图。树是一个图,其中任意两个顶点之间只有一条路径。因为我们拥有使用数据科学语言处理和可视化图表的工具,所以我们可以使用这些工具来创建组织图。在本文中,我将向您展示如何操作,首先使用 R,然后使用 Python。r 有更好的 viz 选项,但是你也可以用 Python 生成一个基本的组织结构图。

为了举例说明,我们将使用 Chinook 开源数据库,您可以在这里下载。下载后解压找到一个叫chinook.db的文件。这是一个示例数据库,与您在任何组织中找到的数据库没有什么不同,但显然为了演示的目的,它更小更简单。

R 里怎么做

在 R 中,在我们做了一些数据操作之后,我们将通过从数据中创建一个igraph对象,然后使用令人敬畏的ggraph包来可视化它。

首先让我们使用RSQLite包连接到我们的数据库,并查看表格:

library(RSQLite)con <- dbConnect(
  drv = RSQLite::SQLite(),
  "chinook.db"
)RSQLite::dbListTables(con)## [1] "albums"          "artists"         "customers"       "employees"       "genres"          "invoice_items"  
 ## [7] "invoices"        "media_types"     "playlist_track"  "playlists"       "sqlite_sequence" "sqlite_stat1"   
## [13] "tracks"

让我们下载并快速浏览一下employees表的字段名:

employees <- dbGetQuery(con, "SELECT * FROM employees")
colnames(employees)## [1] "EmployeeId" "LastName"   "FirstName"  "Title"      "ReportsTo"  "BirthDate"  "HireDate"   "Address"    "City"      
## [10] "State"      "Country"    "PostalCode" "Phone"      "Fax"        "Email"

您能看到我们如何使用ReportsTo列来形成组织图的基础吗?事实上,我们从这个数据库中需要做的就是EmployeeIdReportsTo字段,但是我们也将使用FirstName使它更友好(假设它们都是唯一的)。

library(dplyr)
(emps <- employees |> 
  dplyr::select(EmployeeId, FirstName, ReportsTo))##   EmployeeId FirstName ReportsTo
## 1          1    Andrew        NA
## 2          2     Nancy         1
## 3          3      Jane         2
## 4          4  Margaret         2
## 5          5     Steve         2
## 6          6   Michael         1
## 7          7    Robert         6
## 8          8     Laura         6 

现在,我们可以使用EmployeeIdReportsTo对表本身进行连接,以创建一个在图表中使用的报告关系边列表:

(edgelist <- emps |> 
  dplyr::inner_join(
    emps, 
    by = c("EmployeeId" = "ReportsTo")
  ) |> 
  dplyr::select(from = FirstName.x, to = FirstName.y))##      from       to
## 1  Andrew    Nancy
## 2  Andrew  Michael
## 3   Nancy     Jane
## 4   Nancy Margaret
## 5   Nancy    Steve
## 6 Michael   Robert
## 7 Michael    Laura

现在我们已经拥有了在igraph中创建图形对象所需的一切:

library(igraph)
(orgchart <- igraph::graph_from_data_frame(
  edgelist
))## IGRAPH e155618 DN-- 8 7 -- 
## + attr: name (v/c)
## + edges from e155618 (vertex names):
## [1] Andrew ->Nancy    Andrew ->Michael  Nancy  ->Jane     Nancy  ## ->Margaret Nancy  ->Steve    Michael->Robert  
## [7] Michael->Laura

不错!最后一步是想象它。您可以使用树状图布局、肘形边和节点标签用ggraph创建一个漂亮的可视化:

library(ggraph)
ggraph(orgchart, layout = "dendrogram") +
  geom_edge_elbow() +
  geom_node_label(aes(label = name), fill = "lightblue") +
  theme_void()

作者生成的图像

用 Python 怎么做

要连接到chinook并获取员工详细信息:

import sqlite3, pandas as pd
con=sqlite3.connect('chinook.db')qry="""
SELECT EmployeeId, FirstName, ReportsTo
FROM employees
"""emps=pd.read_sql(qry, con)##    EmployeeId FirstName  ReportsTo
## 0           1    Andrew        NaN
## 1           2     Nancy        1.0
## 2           3      Jane        2.0
## 3           4  Margaret        2.0
## 4           5     Steve        2.0
## 5           6   Michael        1.0
## 6           7    Robert        6.0
## 7           8     Laura        6.0

要生成边列表:

edgelist=pd.merge(emps, emps, left_on='EmployeeId', right_on='ReportsTo')edgelist.rename(
  columns={'FirstName_x' :'from', 'FirstName_y' :'to'},
  inplace=True
)edgelist=edgelist[['from', 'to']]##       from        to
## 0   Andrew     Nancy
## 1   Andrew   Michael
## 2    Nancy      Jane
## 3    Nancy  Margaret
## 4    Nancy     Steve
## 5  Michael    Robert
## 6  Michael     Laura

创建一个networkx图形对象:

import networkx as nxorgchart=nx.from_pandas_edgelist(edgelist, 
source='from', target='to')

Python 对图形可视化的支持肯定比 R 更基本。然而,如果你已经在你的系统上安装了 graphviz(例如brew install graphvizsudo apt-get install graphviz)并且安装了pydot包,你可以用它来获得一个基本的可视化:

p=nx.drawing.nx_pydot.to_pydot(orgchart)
p.write_png('orgchart.png')

作者生成

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn Twitter上找我。也可以看看我的博客上的drkeithmcnulty.com或者我的 教科书上的人物分析

使用 Gridspec 在 Matplotlib 中创建面板图形布局

原文:https://towardsdatascience.com/create-panel-figure-layouts-in-matplotlib-with-gridspec-7ec79c218df0?source=collection_archive---------21-----------------------

Python 科学绘图

使用 gridspec 布局您的图形,而不需要导出多个图形,并使用另一个程序将它们组合在一起

丹尼尔·麦卡洛在unplash拍摄的照片

出版物人物通常需要将多个情节放入镶板布局中来讲述一个故事。一种简单的拖放方法是单独创建每个绘图,然后使用图像编辑程序甚至 Powerpoint 将绘图排列成完整的图形并保存为一个图像。这种方法的问题;然而,字体之间大小一致性等。如果您必须继续编辑单个绘图、调整大小和移动以适应您的图形布局,这是很困难的。确保所有单个图形格式一致的一种方法是直接在matplotlib中创建面板图形,并导出为一个图像。对我们来说幸运的是,有一个强大的工具叫做gridspec,我们可以用它让matplotlib为我们做大部分的工作。让我们从创建一个 10 x 10 英寸大小的空白图形开始:

**# Import Libraries** import matplotlib.pyplot as plt
import numpy as np**# Create Blank Figure** fig = plt.figure(figsize=(10, 10))

假设这是我们希望最终从脚本中生成的布局:

我们镶板图形的理想布局

如果我们想利用gridspec的优势,我们需要将我们的布局简化成一个网格。因此,为了设计布局,我们可以把上面的图想象成一个 4×4 的网格,其中Plot 3占据了底部的两个正方形。我们可以如下创建这个初始网格:

**# Create 4x4 Grid** gs = fig.add_gridspec(nrows=2, ncols=2)

现在我们有了网格,我们可以创建三个轴对象,对应于上面布局中的三个图。我们可以像索引任何二维数组或列表一样索引gridspec。注意对于ax3我们索引gs[1, :],这意味着轴对象将跨越第二行和两列。

**# Create Three Axes Objects** ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, :])

基本 gridspec 布局

在那里!我们有了最初尝试创建的基本布局。当前的布局是使用 4 个大小相等的正方形,它们之间有默认的间距。假设我们想要对布局有更多的控制——我们可以从图中各个图之间的水平和垂直间隙开始,我们可以通过hspace(高度空间)和wspace(宽度空间)作为参数。这些关键字参数采用对应于平均轴高度和宽度的一部分的浮点值。

**# Edit gridspec to change hspace and wspace** gs = fig.add_gridspec(nrows=2, ncols=2, hspace=0.5, wspace=0.5)

hspace 和 wspace 值为 0.5 的 Gridspec 布局

如您所见,这些图现在间隔得更远了,因为空间是按平均轴宽和高度的一半来计算的。现在,假设我们实际上希望Plot 1的宽度是Plot 2的两倍,而Plot 3的高度是Plot 1Plot 2的一半。我们可以使用关键字参数height_ratioswidth_ratios对此进行调整。这两个参数都接受一个浮点数列表,分别描述轴的高度和宽度的比率。

**# Edit gridspec to change height_ratios and width_ratios** gs = fig.add_gridspec(nrows=2, ncols=2, height_ratios=[2, 1], width_ratios=[2, 1])

height_ratios 和 width_ratios 已更改的 Gridspec 布局

在这里,我们非常简单地创建了具有不同高度和宽度的更复杂的网格布局。现在,让我们使用最后的布局来创建最终的面板图:

**# Styling** plt.style.use("seaborn-darkgrid")
plt.rcParams["font.family"] = "Avenir"
plt.rcParams["font.size"] = 16**# Create Blank Figure** fig = plt.figure(figsize=(10, 10))**# Create 4x4 Grid**
gs = fig.add_gridspec(nrows=2, ncols=2, height_ratios=[2, 1], width_ratios=[2, 1])**# Create Three Axes Objects** ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, :])**# Dummy Data** x = np.linspace(0, 2*np.pi, 1000)**# Plot Data** ax1.plot(x, np.sin(x))
ax2.plot(x, np.sin(x)**2)
ax3.plot(x, np.sin(x) + np.cos(3*x))**# Set axis labels** ax1.set_ylabel("y", size=20)
ax3.set_xlabel("x", size=20)
ax3.set_ylabel("y", size=20)

最终面板图

我们做到了!我们能够非常简单地使用matplotlib中的gridspec来创建我们的面板图形。

结论

这是一个非常基本的介绍,介绍如何使用gridspec创建带有多个图的面板图形。您可以使用本文中显示的设置来创建一些非常复杂的布局,甚至可以利用在一些网格元素中使用空白地块来创建空间区域。本文中的gridspec.ipynb笔记本将在这个 Github 资源库中提供。

感谢您的阅读!我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系,以获取更多更新和文章。

使用 Altair 创建令人惊叹的可视化效果

原文:https://towardsdatascience.com/create-stunning-visualizations-with-altair-f9af7ad5e9b?source=collection_archive---------13-----------------------

提高在 Python 中可视化数据的效率

“美将拯救世界。”

  • F .陀思妥耶夫斯基

在 Unsplash 上由 corina ardeleanu 拍摄的照片

介绍

你是否曾经在看了 Python 中的可视化后感到沮丧?你有没有想过用更少的努力和时间可以做得更好?如果是这样,这篇文章非常适合你,因为我想分享一下 Altair 库,它会提高你的工作效率,让你的视觉效果更吸引人。

我想你已经知道可视化对于任何分析是多么重要,以及它如何帮助向更广泛的受众传达和翻译一个想法。此外,可视化数据是探索数据并了解从哪里深入挖掘的第一步。因此,我将使用散点图 重点介绍牛郎星的 基本语法,然后 与您分享一些各种图形 的示例。在此之前,我们先来说说牛郎星,了解一下它为什么这么厉害。

为什么是牛郎星?

牛郎星示例图库(来源于作者)

Altair 是一个声明性的统计可视化库,它使用 Vega 和 Vega-Lite 语法来帮助描述 JSON 格式的可视化的视觉外观和交互行为。

Altair 背后的关键思想是,你声明数据列和可视编码通道之间的链接(例如,x 和 y 轴、颜色、大小等。)并且可视化过程的其余部分由库来处理。因此,它让你有更多的时间关注数据和分析,而不是解释如何可视化数据[1]。

牛郎星的组件

  1. 数据: 用于可视化的数据帧

  2. 标记: 您希望数据以何种方式显示(线条、条形、刻度、点)?

  3. 编码: 数据将如何表示(x 和 y 的位置,颜色,大小)?

  4. 转换: 在应用可视化之前,您希望如何转换数据(聚集、折叠、过滤等)。)?

  5. Scale: 用于在屏幕上输入和渲染数据的功能

  6. 引导: 图例、x 轴和 y 轴上的记号等视觉辅助。

对于 标记 组件,可以使用以下基本标记属性:

Altair 的文档截图

用散点图理解牛郎星的语法

让我们把我们的手脏,并学习阿尔泰的语法使用散点图。

装置

$ pip install altair vega_datasets

conda 的等效值为

$ conda install -c conda-forge altair vega_datasets

数据

我将使用以下 Vega 数据集:

  1. data.gapminder()
  2. 投资数据.股票()
  3. data.movies()

让我们导入包并查看数据

import pandas as pd
import altair as alt
from vega_datasets import data

Gapminder 数据集

股票数据集

电影数据集

步骤 1:简单散点图

Chart()。让我们使用 Chart()mark_point()。

alt.Chart(df_gm_2005).mark_point().encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’))

简单散点图

第二步:增加互动性

通过在散点图中添加 interactive()。此外,让我们用 alt 来定义泡沫的大小。大小)(为地块添加更多信息。

alt.Chart(df_gm_2005).mark_point(filled=True).encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’),
 alt.Size(‘pop’)
).interactive()

简单交互散点图

第三步:添加颜色

我们可以通过添加 alt 来改变气泡的颜色。中的颜色()编码为对象。这是伟大的,我们不需要担心每一个国家的每一种颜色,因为牛郎星为你这样做。

alt.Chart(df_gm_2005).mark_point(filled=True).encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’),
 alt.Size(‘pop’),
 alt.Color(‘country’),
 alt.OpacityValue(0.7)
).interactive()

带有彩色气泡的交互式散点图

第 4 步:添加更多信息

我们可以通过在 encode()。

alt.Chart(df_gm_2005).mark_point(filled=True).encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’),
 alt.Size(‘pop’),
 alt.Color(‘country’),
 alt.OpacityValue(0.7),
 tooltip = [alt.Tooltip(‘country’),
 alt.Tooltip(‘fertility’),
 alt.Tooltip(‘life_expect’),
 alt.Tooltip(‘pop’),
 alt.Tooltip(‘year’)]
).interactive()

现在显示每个国家/地区的信息

第五步:让情节充满活力

对于 2005 年的数据来说已经显得惊人了。让我们添加一个酒吧,以改变数据,使绘图动态。

select_year = alt.selection_single(
 name=’Select’, fields=[‘year’], init={‘year’: 1955},
 bind=alt.binding_range(min=1955, max=2005, step=5)
)alt.Chart(df_gm).mark_point(filled=True).encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’),
 alt.Size(‘pop’),
 alt.Color(‘country’),
 alt.OpacityValue(0.7),
 tooltip = [alt.Tooltip(‘country’),
 alt.Tooltip(‘fertility’),
 alt.Tooltip(‘life_expect’),
 alt.Tooltip(‘pop’),
 alt.Tooltip(‘year’)]
).add_selection(select_year).transform_filter(select_year).interactive()

选择年度的动态可视化

步骤 6:更改大小并添加标题

最后,让我们更改情节的大小并添加一个标题

select_year = alt.selection_single(
 name=’Select’, fields=[‘year’], init={‘year’: 1955},
 bind=alt.binding_range(min=1955, max=2005, step=5)
)scatter_plot = alt.Chart(df_gm).mark_point(filled=True).encode(
 alt.X(‘life_expect’),
 alt.Y(‘fertility’),
 alt.Size(‘pop’),
 alt.Color(‘country’),
 alt.OpacityValue(0.7),
 tooltip = [alt.Tooltip(‘country’),
 alt.Tooltip(‘fertility’),
 alt.Tooltip(‘life_expect’),
 alt.Tooltip(‘pop’),
 alt.Tooltip(‘year’)]
).properties(
 width=500,
 height=500,
 title=”Relationship between fertility and life expectancy for various countries by year”
).add_selection(select_year).transform_filter(select_year).interactive()scatter_plot.configure_title(
 fontSize=16,
 font=”Arial”,
 anchor=”middle”,
 color=”gray”)

散点图的最终结果

最终的输出看起来很棒,我们可以从这样一个复杂的可视化中得到各种见解。

其他有用的地块与牵牛星

现在,了解了基本的牵牛星的语法,让我们看看其他一些情节。

方框图

box_plot = alt.Chart(df_gm_2005).mark_boxplot(size=100, extent=0.5).encode(
 y=alt.Y(‘life_expect’, scale=alt.Scale(zero=False))
).properties(
 width=400,
 height=400,
 title=”Distribution of life expectancy for various countries in 2005 year”
).configure_axis(
 labelFontSize=14,
 titleFontSize=14
).configure_mark(
 opacity=0.6,
 color=’darkmagenta’
)box_plot.configure_title(
 fontSize=16,
 font=”Arial”,
 anchor=”middle”,
 color=”gray”)

方框图

柱状图

histogram = alt.Chart(df_gm_2005).mark_bar().encode(
 alt.X(“life_expect”, bin=alt.Bin(extent=[0, 100], step=10)),
 y=”count()”
).properties(
 width=400,
 height=300,
 title=”Distribution of population for various countries in 2005 year”
).configure_axis(
 labelFontSize=14,
 titleFontSize=14
).configure_mark(
 opacity=0.5,
 color=’royalblue’
)histogram.configure_title(
 fontSize=16,
 font=”Arial”,
 anchor=”middle”,
 color=”gray”)

柱状图

条形图

bar_chart = alt.Chart(df_gm_ir).mark_bar(color=’seagreen’,
 opacity=0.6
).encode(
 x=’pop:Q’,
 y=”year:O”
).properties(
 width=400,
 height=400,
 title=”Population of Ireland”
)text = bar_chart.mark_text(
 align=’left’,
 baseline=’middle’,
 dx=3
).encode(
 text=’pop:Q’
)bar_chart + text

条形图

折线图

line_chart = alt.Chart(df_stocks).mark_line().encode(
 x=’date’,
 y=’price’,
 color=’symbol’
).properties(
 width=400,
 height=300,
 title=”Daily closing stock prices”
)line_chart.configure_title(
 fontSize=16,
 font=”Arial”,
 anchor=”middle”,
 color=”gray”)

折线图

多个散点图

mult_scatter_plots = alt.Chart(df_movies).mark_circle().encode(
 alt.X(alt.repeat(“column”), type=’quantitative’),
 alt.Y(alt.repeat(“row”), type=’quantitative’),
 color=’Major_Genre:N’
).properties(
 width=150,
 height=150
).repeat(
 row=[‘US_Gross’, ‘Worldwide_Gross’, ‘IMDB_Rating’],
 column=[‘US_Gross’, ‘Worldwide_Gross’, ‘IMDB_Rating’]
).interactive()mult_scatter_plots

多个散点图

最后的想法

牛郎星是一个伟大的工具,以提高你的生产力可视化数据,在那里你只需要指定数据和可视化编码通道之间的链接。这样你就可以把你的思想直接放在一个情节上,而不用担心耗时的“如何”部分。

有关详细信息,请参阅

  • 我的 Jupyter 笔记本用于博客帖子
  • 官方文件附有各种地块的示例画廊。

感谢您的阅读,请在下面评论您对使用 Altair 可视化数据的想法。要查看我的更多帖子,请订阅 Medium 和 LinkedIn 。

参考

  1. 总览页面。概述— Altair 4.1.0 文档。(未注明)。https://altair-viz.github.io/getting_started/overview.html.

用 Python 创建具有异常特征的合成时间序列

原文:https://towardsdatascience.com/create-synthetic-time-series-with-anomaly-signatures-in-python-c0b80a6c093c?source=collection_archive---------20-----------------------

行业笔记

一种简单而直观的方式来创建带有定制异常的合成(人工)时间序列数据,特别适合工业应用。

图片来源:作者用 Pixabay (免费使用)图片创作

为什么要合成时间序列?

正如我在被大量引用的文章中所写的,合成数据集是以编程方式生成的数据的存储库。所以,它没有被任何现实生活中的调查或实验所收集。因此,它的主要目的是足够灵活和丰富,以帮助 ML 从业者用各种分类、回归和聚类算法进行有趣的实验。

合成时间序列也不例外,它可以帮助数据科学家试验各种算法方法,并为现实生活中的部署做准备,而这种部署方式仅使用真实数据集是不可能的。

工业环境中的时间序列数据

在现代工业环境中,时间序列分析有各种丰富的应用,大量的传感器正在从机器、工厂、操作员和业务流程中创建永无止境的数字数据流。

压力。温度。电动部件的振动和加速度。质检数据。操作员操作日志。

数字从未停止过。这是工业 4.0 或智能工厂时代的新规范。虽然结构化和半结构化数据都在增加,但其中许多仍然是来自现代工厂中嵌入的所有测量抽头的各种各样的时间序列(或类时间序列)数据。

https://metrology.news/factory-2030-the-coming-of-age-of-the-smart-factory/

图片来源 : Pixabay (免费使用)

异常检测至关重要

大多数时候,它们是“正常”、“在范围内”、“符合预期”。但在极少数情况下,他们不是。这就是你需要注意的地方。这些是正常数据流中的“异常”,它们需要被捕获、分析并采取行动——几乎总是实时的。

这些数据流中的异常检测是所有现代数据分析产品、服务和初创公司的面包和黄油。他们正在使用各种方法,从经过试验和测试的时间序列算法到最新的基于神经网络的序列模型,来检测这些异常信号,并根据业务逻辑的要求发出警报或采取行动。

在现代工业环境中,时间序列分析有各种丰富的应用,大量的传感器正在创建一个永无止境的数字数据流…

合成数据生成是一个强大的辅助工具

关于这些工业数据流,有几点值得重复,以理解为什么合成时间序列的生成可能会非常有用。

  • 现实生活中的异常是罕见的,人们需要监控和处理大量数据来检测各种有趣的异常。对于想要在短时间内测试和重新测试一系列算法的数据科学家来说,这不是一个好消息。
  • 异常的出现是如此不可预测,以至于它们的模式很难在任何全面的统计分布中被捕捉到。对大量异常类型进行快速实验对于生产健壮可靠的异常检测系统至关重要。在缺乏常规、可靠的异常数据来源的情况下,合成方法提供了实现某种受控实验的唯一希望。
  • 许多工业传感器生成的数据被认为是高度保密的,不允许超出本地私有云或现有的边缘分析系统。为了再现异常特征而不损害数据安全性,合成方法是显而易见的选择。

这些是正常数据流中的“异常”,它们需要被捕获、分析并采取行动——几乎总是实时的。

在本文中,我们展示了一种简单而直观的方法,在模拟工业过程的一维合成时间序列数据中创建一些常见类型的异常特征。我们会为此使用大家最喜欢的 Python 语言。

注意:这不是一篇关于异常检测算法的文章。我只讨论与合成生成注入异常的时间序列数据相关的思想和方法(集中在一个特定的应用领域)。

有异常的合成时间序列

这里是 Jupyter 笔记本 这里是带主类对象的 Python 模块供你玩。

工业过程和“单位过程时间”的概念

图片来源:作者创作

上面,我们展示了一个典型的工业过程和“单位加工时间”的图解。假设一些原材料(图中的 流程 I/P )正在进入一台复杂的机器,而成品(图中的 流程 O/P )正在从另一端出来。

我们不需要知道机器内部到底发生了什么,只需要知道它会定期生成一些数据,也就是说,我们可以以时间序列的方式测量过程的状态(也许使用一些传感器)。我们想看看这个数据流,发现异常。

因此,要定义我们的合成时间序列模块,我们至少需要以下内容:

  • 流程开始时间
  • 流程结束时间
  • 单位处理时间(我们接收数据的时间间隔)

因此,基类SyntheticTS的定义就是这样开始的,

“正常”过程

要产生异常,我们需要一个正常的基线。我们可以用“正态分布”来解释这一点。您可以根据您的具体过程类型和情况随时更改它,但绝大多数工业过程的传感器测量值确实遵循正态分布。

假设我们有一个工业流程/机器,从 2021 年 5 月 1 日开始运行,一直运行到 2021 年 5 月 6 日(在每周维护之前,在许多情况下通常运行 6 天)。单位处理时间为 15 分钟。我们选择过程的平均值为 100,标准偏差为 5。

基本的“异常化”方法

作为一种合成数据生成方法,您希望控制异常的以下特征:

  • 需要异常的数据部分
  • 异常的规模(它们离正常有多远)
  • 单边或双边(在数量上高于或低于正常数据)

我们不会为精确的代码而烦恼,而是向您展示一些关键的结果。

单边异常

这里有一个例子,

改变异常尺度

我们可以通过简单地改变anomaly_scale参数将异常放置在不同的距离。

这是结果图。请注意图的垂直比例是如何变化的,以适应越来越大的异常。

异常的变化部分

接下来,我们更改异常的分数(保持比例不变,为 2.0)。

引入“积极转变”

这在工业过程中是相当常见的情况,其中由于过程/机器设置的突然变化或一些其他原因,在过程中引入了可见的偏移。有时是计划好的,有时是无意的。根据具体情况,异常检测算法可能需要对其进行不同的分析和处理。无论如何,我们需要一种方法在合成数据中引入这样的变化。

在这种情况下,我们选择了 10%的数据偏移,即带有pct_drift_mean=10参数的平均值。注意,如果我们没有在方法中指定参数time_drift,那么代码会自动在整个过程的开始和结束时间的中间点引入漂移。

特定位置的负偏移

在下面的例子中,我们展示了一种情况,

  • 数据向负方向漂移
  • 数据的分布(方差)随着平均值而变化
  • 漂移从用户可以选择的特定位置开始

这是比较现实的情况。

块状异常

在许多情况下,异常会成批出现,然后消失。我们也可以综合这种情况。请注意,这里我们创建了“双侧异常”,但与所有其他选项类似,我们也可以创建“单侧”变异。

现在,代码创建了在整个时间段内均匀分布的分块异常。但是这可以在下一次代码更新中用单独的时间点和异常特征来定制。

摘要

我们展示了一种简单直观的方法来创建具有各种异常特征的合成一维时间序列数据,这些异常特征在工业用例中很常见。这种合成数据生成技术对于算法迭代和模型测试非常有用。

保持简单

为了专注于工业用例,我们没有在基线数据生成中添加传统的时间序列模式(如季节性、上升/下降趋势),而是将其保持为极其简单的高斯过程。数据也没有自动回归的性质。尽管 ARIMA 等算法非常受欢迎,对金融和商业数据分析很有帮助,但工业环境中独立传感器生成的数据通常呈正态分布,我们坚持这一原则。

进一步的改进

有很多方法可以在此基础上添加额外的功能。有些可能是,

  • 增加了各种统计分布的选择作为基线数据生成过程
  • 分块异常的任意位置和特征
  • 多个合成数据类/对象的合成方法
  • 更好的可视化方法

同样,示例 Jupyter 笔记本在这里。请随意叉和实验。

Y ou 可以查看作者的 GitHub 知识库获取机器学习和数据科学方面的代码、思想和资源。如果你和我一样,对人工智能/机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我或在 Twitter 上关注我。

https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/

用您的能源数据创造价值

原文:https://towardsdatascience.com/create-value-with-your-energy-data-26feaa723c07?source=collection_archive---------28-----------------------

提高数据分析和创造价值的五个步骤

约翰尼·多宾斯通过 Canva.com 获得授权。

最近,我坐在那里惊恐地看着一名控制室性能工程师目测风力涡轮机的数千条功率曲线,以确定性能不佳。她的 tableau 仪表板是她最好的,毫无疑问,她能够做出/一些/影响,但一个 30x30 像素乘以数千的情节只是融入无关紧要的,可能会错过很多机会。

另一次,一名太阳能性能工程师与一名数据科学家合作开发逆变器的可用性分析。这是一种基于“黑盒”机器学习的分析,实际上导致每个逆变器都有问题。一位英国朋友把它描述为“血腥的红色仪表板”,我相信对一个美国人来说,这意味着“疯狂的红色仪表板”,所有的东西都在发出警报;我认为这是血淋淋的,散发着失去机会的恶臭。

这两个轶事代表了我每天从资产经理、运营商和性能工程师那里看到的试图用他们的数据创造价值的大约 80%。

提高精力的五件事数据分析

我想分享我在与能源行业客户合作时学到的五件事:

  1. 能源生产中的大多数见解都来自数量少得惊人的简单时间序列数据源,包括:状态、警报和传感器数据。大多数人在创造任何价值方面都差得惊人。
  2. 通常,洞察力是在这些来源的筒仓中形成的。
  3. 不费吹灰之力,通过打破这些数据孤岛就可以开发出更全面的见解。
  4. 通过将与资产相关的人类活动产生的额外结构化和非结构化数据纳入其中,洞察价值将远远超过通过简单的传感器观察所产生的价值。
  5. 最后,理解什么是部落知识以及如何应用它将会增强即使是最基本的分析的洞察力。

让我们更深入地了解一下我在这些问题背后的想法。

来自简单时间序列数据来源的见解缺乏价值

在过去的五年里,我一次又一次地直接接触到从有限的时间序列数据集发展而来的天真见解,这些数据集来自对能源生产资产的传感器观察。

我们通常会看到 SCADA 数据或传感器观测数据,以及状态和运行数据,其处理方式与我在开头描述的类似。这三种结构良好且通常干净的数据类型经过适当分析后可以提供丰富的见解。但是我们怎么做呢?

从识别对组织重要的事情开始;很明显,对吧?你会惊讶于那些实现这些分析的人常常不清楚这些价值。对组织的财务影响可以通过因长期表现不佳、缺乏对可用性损失的了解以及最终完全不了解资产健康和维护需求而导致的能源生产损失来衡量。

通过开发专注于这三个特定领域的分析,然后将其与特定原因相关联,您可以将“血腥的红色仪表板”转化为可操作的见解的明确列表,这些见解通常具有硬价值。

即使使用警报和状态数据,应用一个简单的帕累托方法,您也可以很容易地找出导致组织在运营和财务上最混乱的事情。然而,通常情况下,运营商无法告诉您他们资产上的哪些类型的事件正在影响该资产对组织的价值;这种可见性的缺乏导致了在提供很少价值的领域中的分析开发工作。双重错失的机会。

我发现,通过确定对一个组织影响最大的 5 件事,然后从这 5 件事开始逆向工作以开发分析和见解,会导致彻底的采用和价值。

认识数据孤岛及其对洞察力的影响

当单个资产存在两个或更多数据源并且它们没有被一起分析时,就存在数据竖井。

在能源领域,使用单一时间序列数据源进行分析已经变得司空见惯。数据科学家如此专注于从多年的数据深度中创建模型,以至于他们经常忘记在他们正在处理的单一来源之外进行发现。或者,很有可能,他们甚至不知道其他可用的来源。

由此产生的孤立分析通常不太可行,因此缺乏价值。

想象一下,在对风力涡轮机进行性能分析时,您考虑了环境因素以及发电量,还可能考虑了涡轮机的一些其他传感器观测结果;有了这个,你就可以为涡轮机的性能开发一个有趣的模型。事实上,甚至有关于如何最好地做到这一点的 IEC 标准文件。然而,最终,它只会告诉您,您有一个性能问题,您可能已经知道了,或者至少像我前面描述的工程一样关注了。

类似地,您可能已经对您的涡轮机组中发生的故障进行了帕累托分析,并了解了由于这些故障您在哪些地方失去了最大的可用性。

通过这两个简单的分析,您最终会意识到性能不佳以及特定警报对可用性的影响;这是一个不错的起点,但是,想象一下,如果你结合这两种分析?

打破孤岛,从数据中形成更完整的见解

打破数据孤岛将立即丰富您正在产生的见解,并从数据中创造更多价值。

什么意思?超越单一数据源方法,包括任何可用的额外时间序列数据。将这些传感器观察结果与状态和警报数据合并。

在水平扩展数据的同时保持分析的简单性,这使您能够快速迭代,同时获得更丰富的洞察力,因此在开始时,请坚持使用简单的基于统计的分析。机器学习有它的位置,只是避免它开始。

以上一节的例子为例;您可以运行基于 IEC 的功率曲线分析,同时对故障数据进行帕累托分析。通过结合这两种方法和数据源,您可以立即将损失值分配给警报和警告。此外,你可以开始对不同类型的表现不佳进行分类;有些您可能无法通过维护来影响,而有些您可以。

当你把你的视野缩小到那些你实际上可以影响创造价值的事情上时,那个“血腥的红色仪表板”立刻变成了暗红色。

通过扩展该示例以包括额外的传感器数据,您还将能够识别暗示特定故障的资产数据模式。这使您能够为错过的维护机会甚至由此导致的可用性损失分配价值。

打破你的数据孤岛,摆脱原始设备制造商的“警告”和花哨的软件升级;这两种情况都会阻碍您利用时间序列数据源创造真正的、可能的转换价值。

在未来的帖子中,我将分享数据和 python 的实际例子来演示我所描述的内容。请记住,这是一种纯粹基于统计的方法,您不需要数据科学家或机器学习来完成这一点。

开始包括与资产相关联的人类活动所创建的数据

由人类活动创建的数据通常属于以下类型之一:工作订单、工作日志或检查数据。它也是时间序列,与您的资产生成的传感器、状态和故障数据惊人地吻合。

在您的分析中使用这些数据的挑战通常在于 IT 部门不希望在用于生成数据的应用程序之外提供这些数据。正如 OEM 的情况一样,我发现 it 团队经常因为允许他们管理的数据在他们的组织之外使用而感到威胁。这是一个可悲的事实,数据囤积和保护主义的发生。

然而,一旦您解放了这些数据,它可以为组织增加的价值是巨大的。

以前面的例子为例,您可能已经确定了影响组织底线的 5 大事件。这样,您就可以确定这些事件何时发生,发生在哪些资产上;开始把它和特定的人类活动联系起来。

现在,您可以开始通过改进维护计划来识别价值机会;此外,您可以冲洗相反的地方,在那里维护是低于标准的。想象一下,能够识别重复访问以解决一个持续存在的问题,然后为该问题建立一个更好的维护操作手册?您甚至可以更好地让 OEM 或合同维护团队对他们的工作更加负责。

能源数据分析中包含的群体知识是开发真正洞察力的圣杯

“当我看到这种情况发生时,我通常会这样做,问题就会消失。”

再多的流程图也不能真正抓住维护者在解决问题时使用的逻辑。

我记得我是一名年轻的飞行员,曾多次在美国空军 KC-10A 飞机上担任乘务长,当时的“技术指令”或“流程”文件缺少有效完成维修所需的细节。有一次,我按照文档中的说明一步一步地密封一个灯罩。我设法把这种军用规格的密封剂涂在我和飞机上,弄得一团糟。清理一个 15 分钟的任务需要几个小时。后来,一个长着灰胡子的乘务长把我拉到一边,向我解释了他完成任务的更简单、更干净的方法。他的方法遵循流程,但包括一些来之不易的知识。下一次我必须执行这项任务时,我听从了他的建议,在大约 15 分钟内进出。

这是部落知识。通常通过完成任务的经验学习,并通过口头或工作日志传递。

通过高级自然语言处理(NLP),熟练的分析开发人员与主题专家一起工作,可以开发必要的代码和逻辑来提取这些部落见解。

这有什么用?您已经确定了导致组织价值损失最大的前 5 个事件,现在您可以通过在以前的工作日志中确定具体的事情并将其包括在现有的时间序列数据分析中,将此 NLP 值乘数添加到该事件中。这可能演变成特定的数据模式,需要特定的工具或部件来进行预先调度,或者在已经安排好的停机时间内进行更高效的修复。

我真的做不了 NLP 部落知识提取正义这个通用帖子;在不久的将来,我将回到这一点,并包括一些实际的数据和工作的 python 来做我所描述的事情。

我在职业工程生涯中花了很多时间开发应用程序,帮助人们从他们的数据和内容中获得更多价值。

这方面的经验包括为佛罗里达州的 TBO.com 构建“防飓风”的新闻编辑室应用程序,为国家地理杂志构建“摄影比赛”应用程序,以及在过去的五年中,为运营商开发工具,帮助他们提高能源行业资产的性能和影响力。

导入本

为您的时间序列预测模型创建“不受天气影响”的验证

原文:https://towardsdatascience.com/create-weather-proof-validations-for-your-time-series-forecasting-model-d456a1037c4f?source=collection_archive---------20-----------------------

使用 Python 构建最终时间预测的指南

马尔科·布里托在 Unsplash 上的照片

时间旅行!!—是时候让我们的探索更上一层楼,致力于预测依赖于时间的结果了。时间序列是以时间间隔出现的一系列数据。这些时间间隔可以是每小时、每天、每周或任何可量化的重复持续时间。在一定时间间隔内进行的一系列观察称为时间序列。

预测时间序列处理的是预测下一个周期或在未来参考时间框架内发生的事件观察。

在整个故事中,我们的目标是建立一个对所有问题都理想的时间序列预测。这里的想法是不要为一个问题建立最佳解决方案,而是为大多数问题建立一个可以接近的解决方案。

成功的时间序列所需的重要结构和测试

  1. 重采样
  2. 时间序列的平稳性
  3. ARIMA 和皮拉明德·ARIMA 造型
  4. 季节性和缺失值插补
  5. Ad-Fuller (ADF)测试
  6. 自相关和偏相关
  7. 格兰杰因果检验

了解时间序列预测的流程

时序预测和分析的逐步流程|作者图片

Panel Data: Panel 是一个基于时间的数据集,除了序列数据之外,还包含一个或多个在某些时间段量化的关联变量。这些因变量有助于为预测“Y”的值提供有价值的见解。

时间序列中的滞后: Lag,作为一个通用的英文术语,指的是较慢的响应时间,通常称为潜伏期。在时间序列预测或分析中,1 到 8 范围内的滞后被认为适用于季度定时数据。对于以月为间隔的时间序列,6、12 或 24 的滞后被认为是合适的。为了更好地理解滞后,让我们看一下这个场景。对于属于时间序列的一组离散值,对于滞后 1,此时间序列将与当前时间序列之前的同一时间序列进行比较。换句话说,时间序列被移动到过去的一个时间段。

了解数据集是时间序列还是面板的一种方法是了解时间列是否是影响预测结果的唯一数据部分。

从下一节开始,我们开始动手(我们编码!!)而且为了简单起见,我在这个故事里只加伪代码。但是,为了能够遍历整个代码,我链接了下面的代码库。这只是一个 Python 笔记本,我建议您跟随这个故事。

https://github.com/rjrahul24/ai-with-python-series/tree/main/05. Build Concrete Time Series Forecasts

1.对时间序列进行重采样

重采样是一种用于改变时间序列观测频率的技术。在 pandas 的数据帧中,重采样方法使这种频率转换变得很方便。所需的先决条件是,对象必须具有 DateTime 数据类型格式(DateTime、DateTimeIndex、PeriodIndex、TimeDeltaIndex 等。).如下所述,存在两种重采样类型。 虽然,在这两种情况下,都必须发明数据。

  1. 上采样:增加采样数据的频率。例如,将基于分钟的频率更改为秒。
  2. 下采样:上采样的反过程。例如,将基于天的频率更改为月。

当数据可用的频率与您进行分析的频率不同时,需要进行重采样。

但在最常见的情况下,重采样用于为监督学习算法提供某种程度的附加结构和对机器学习问题的洞察。

# The series module from Pandas will help in creating a time series
from pandas import Series,DataFrame
import seaborn as sns# Before resampling
timeseries_mm = time_series['wind_speed']
timeseries_mm.plot(style='g--')
plt.show()# Resampling the dataset using the Mean() resample method
timeseries_mm = time_series['wind_speed'].resample("A").mean()
timeseries_mm.plot(style='g--')
plt.show()

时间序列重采样前后记录的风速变化|作者提供的图像

2.平稳和非平稳时间序列

平稳性被认为是每个时间序列的一个特征。在平稳序列的情况下,时间序列的值不是时间的函数。

这意味着当前值与过去值的均值、方差和自相关等测量值都是恒定的。平稳的时间序列也不受季节变化的影响。

几乎每一个时间序列都可以通过适当的变换变得平稳。

使时间序列平稳

使用以下提到的任何一种方法都可以使时间序列数据变得平稳:

  1. 对序列进行一次或多次差分:差分的概念是用当前时间中的序列值减去前一时间单位中同一序列的值,将使其保持不变。也就是说,用当前值减去下一个值叫做差分。
    比如考虑以下数列:[1,5,2,12,20]。一阶差分给出:[5–1,2–5,12–2,20–12]=[4,-3,10,8]。第二次求差得到:[-3–4,-10–3,8–10]=[-7,-13,-2]
  2. 获取现有时间序列的日志
  3. 取当前数列的第 n 个根。
  4. 结合一种或多种上述技术。

为什么平稳时间序列很重要?

平稳的时间序列比较容易预测,也比较可靠。

原因是,预测模型基本上是线性回归算法,利用这些系列数据的滞后来形成预测值。

我们还知道,线性回归算法在预测值(X)彼此不相关的情况下效果最好。使时间序列平稳可消除预测值之间的所有和任何持续的自相关,从而使序列更适合回归分析。一旦序列的滞后或预测因子是独立的,预测就有望给出可靠的预测。

*** 下节中的 Ad-Fuller 测试将测试系列的稳定性。*

3.ARIMA 和皮拉明德·ARIMA 造型

统计学和经济学领域的通用术语,【自回归综合移动平均线(ARIMA)】用于描述移动平均线构造。他们对建立时间序列预测模型产生了浓厚的兴趣。

ARIMA 模型适用于输入数据在均值意义上显示非平稳性的证据,但没有观察到显著差异的情况。

我们可以将 ARIMA 的定义分解如下,ARIMA 的 AR 部分代表一个进化变量,它根据自身滞后(旧值)进行回归。MA 部分显示回归误差,它是过去不同时间出现的误差项的线性组合。剩下的“I”(积分)表示数据被当前值和先前值之间的差异所取代。这些单独的过程可能需要执行多次。每个功能的目的都是使模型尽可能符合数据。

来自 Python 文档 — Pyramid 是一个严肃的统计 Python 库,只有一个目标:将 R 的 auto.arima 功能引入 Python。金字塔的运作方式是将 statsmodels.tsa.ARIMAstats models . TSA . statespace . sarimax包装到一个估算器类中,并为熟悉 scikit-learn 的程序员创建一个更加用户友好的估算器界面。

pmdarima 最初被称为 pyramid-arima,是一个统计库,有助于填补 Python 时间序列中的数据空白。它包含一组用于检查平稳性和季节性的统计测试。还包括时间序列差分和逆差分等功能。

# Predicting Wind Speeds using "pmdarima" package in Pythonfrom pmdarima.arima import auto_arima
from pmdarima.arima import ADFTesttrain=df[:1300]
test=df[-250:]
plt.figure(figsize=(15,10))adf_test=ADFTest(alpha=0.05)
adf_test.should_diff(time_series_train["wind_speed"])
df = time_series_train["wind_speed"]model = auto_arima(train,start_p=0,d=1,start_q=0,max_p=5,max_d=5,max_q=5, start_P=0,D=1, start_Q=0, max_P=5,max_D=5,max_Q=5, m=12,seasonal=True,error_action='warn',trace=True,supress_warnings=True,stepwise=True,random_state=20,n_fits=50)plt.plot(train)
plt.plot(test)
plt.autoscale()

使用 pmdarima 风速模型预测的数据部分(橙色)|图片由作者提供

4.季节性和缺失值插补

时间序列数据的季节性是指在小于一年的特定时间间隔内出现的变化。这些时间间隔可以是每小时、每月、每周或每季度。天气或气候变化等各种因素会导致季节性。

造成季节性的模式总是循环的,并以周期性模式出现。

对于工作依赖于这些变化的企业来说,如股票市场、劳工组织等,理解季节性是很重要的。季节性变化有几个研究的理由和意义:

  • 对数据集季节性影响的解释提供了对季节性变化对数据影响的详细理解。
  • 一旦一个季节模式被建立,重要的方法可以被用来从时间序列中消除它。这将有助于研究数据集其他不规则成分的影响。去季节性是消除季节性的概念。
  • 季节性和规律性变化的历史模式有助于预测类似数据的未来趋势。例如,气候模式的预测。

处理时间序列内的缺失值

在任何数据集中观察到缺失数据是很常见的。类似地,对于表示时间序列的数据,可以观察到缺少日期或时间的序列。数据总是有可能被捕获并且为零。在这种情况下,需要忽略假阴性。

此外,需要注意的重要一点是,对于时间序列数据,均值或中值插补不是一个好的做法。特别是,如果时间序列没有表现出平稳性。更好、更明智的方法是用该时间段的历史值填充远期数据。

但是,基于对数据的研究和序列的前景,可以尝试多种方法来估算缺失值。以下是一些值得注意的输入缺失时间序列值的常用技术:

  • 反向填充
  • 线性内插法
  • 二次插值法
  • 最近邻居的平均值
  • 季节性对应平均值

将新值引入数据集后,测量时间序列的性能也很重要。

使用两种或多种方法输入值,然后使用均方根(RMSE)等方法计算模型的精度,这被认为是一种良好的做法。这有助于决定哪种插补技术最适合数据。

5.Ad-Fuller (ADF)测试

扩展的 Dickey-Fuller 检验(ADF),也称为 Ad-Fuller 检验,是时间序列分析的一种重要检验机制。它测试一个基本的零假设,即给定的输入单位根存在于整个时间序列样本中。另一个假设通常是序列的平稳性或趋势平稳性。

在这个测试中主要使用的增强的 Dickey-Fuller(ADF)统计是一个负数。越是否定,对某个置信水平下存在单位根的假设的否定越强。

Ad-Fuller 测试背后的启示是,如果时间序列以单位根过程为特征,那么在这种情况下,序列(y-1)的滞后水平将不会产生任何预测(y)未来变化的相关信息,除了在(y-1)的 delta 中观察到的那些变化。在这种情况下,零假设不被拒绝。另一方面,如果现有过程没有单位根,则表明它是稳定的,因此显示出向均值的回归。这里,滞后水平将提供预测未来变化的相关信息。

# Statsmodel and Adfuller will help in testing the stationarity of the time series
import statsmodels
from statsmodels.tsa.stattools import adfuller# Decomposing the time series with Statsmodels Decompose Method
from statsmodels.tsa.seasonal import seasonal_decompose
sd_1 = seasonal_decompose(time_series_train["meantemp"])
sd_2 = seasonal_decompose(time_series_train["humidity"])
sd_3 = seasonal_decompose(time_series_train["wind_speed"])
sd_4 = seasonal_decompose(time_series_train["meanpressure"])
sd_1.plot()
sd_2.plot()
sd_3.plot()
sd_4.plot()

所有列的季节性分解|按作者分类的图像

# From the above graph’s observations, it looks like everything other than meanpressure is already stationary
# To re-confirm stationarity, we will run all columns through the ad-fuller testadfuller(time_series_train["meantemp"])
adfuller(time_series_train["humidity"])
adfuller(time_series_train["wind_speed"])
adfuller(time_series_train["meanpressure"])# Consolidate the ad-fuller tests to test from static data
temp_var = time_series_train.columns
print('significance level : 0.05')
for var in temp_var:
  ad_full = adfuller(time_series_train[var])
  print(f'For {var}')
  print(f'Test static {ad_full[1]}',end='\n \n')***>>> significance level : 0.05 
>>> For meantemp Test static 0.2774121372301611   
>>> For humidity Test static 0.004470100478130758   
>>> For wind_speed Test static 0.0025407221531464   
>>> For meanpressure Test static 0.0***

通过 ad-fuller 检验,我们现在可以得出结论,所有数据都是静态的,因为静态检验低于显著性水平。这也否定了平均压力不是静态的假设。

6.自相关和偏相关

自相关:序列与其滞后时间的相关性称为自相关。就像相关性测量两个变量之间线性关系的大小一样,自相关在时间序列的滞后值之间也是如此。如果时间序列有很大的自相关性,这意味着滞后对时间序列预测的影响很大。更一般地说,相关因子 1(滞后= 1)表示彼此相隔一个周期的值之间的相关性。同样,滞后“k”自相关显示了彼此独立的“k”个时间段的值之间的关联。

偏相关:偏相关的目的也类似于自相关,因为它传达了关于变量及其滞后之间关系的信息。但是部分自相关仅提供滞后之间的纯关联的细节,而忽略了中间滞后产生的相关性。

# Plotting the test data with auto correlation
from statsmodels.graphics.tsaplots import plot_acf# The next 6 periods of mean temperature (graph 1) and wind_speed (graph 2)
plot_acf(df_forecast["meantemp"])
plot_acf(df_forecast["wind_speed"])

平均温度和风速的自相关|图片作者

7.格兰杰因果检验

格兰杰因果关系检验有助于通过分析相似的时间序列来理解时间序列的行为。

该测试假设,如果一个事件 X 导致另一个事件 Y 的发生,那么基于前面的 Y 和 X 的组合值的 Y 的未来预测应该超过单独基于 Y 的 Y 的预测。

因此,这里需要注意的是,格兰杰因果关系不应该在事件 Y 的滞后导致 Y 的情况下使用。

带有 PyPi 的 statsmodel 包实现了格兰杰因果关系检验。该方法接受一个有两列的二维数组作为其主参数。第一列包含值,第二列包含预测值(X)。这里的零假设是,属于第二列的序列不会导致属于第一列的序列出现。 如果 P 值小于预定义的显著性水平 0.05,则拒绝零假设。这也得出结论,X 的滞后是有用的。 第二个参数“maxlag”允许您输入 Y 需要包含在测试中的最大滞后数。

# Import Granger Causality module from the statsmodels package and use the Chi-Squared test metric
from statsmodels.tsa.stattools import grangercausalitytests
test_var = time_series.columns
lag_max = 12
test_type = 'ssr_chi2test'causal_val = DataFrame(np.zeros((len(test_var),len(test_var))),columns=test_var,index=test_var)
for a in test_var:
  for b in test_var:
    c = grangercausalitytests ( time_series [ [b,a] ], maxlag = lag_max, verbose = False)
    pred_val = [round ( c [ i +1 ] [0] [test_type] [1], 5 ) for i in range (lag_max) ]
    min_value = np.min (pred_val)
    causal_val.loc[b,a] = min_value
causal_val

作者图片

格兰杰因果关系的结果证明了这些特征之间的密切相关性。

结论

时间序列是一个巨大的主题,包括本章没有讨论的各种其他奇点,这应该被认为是这一领域研究的开始。分析从研究时间序列数据开始,了解平稳性,测试季节性,建立预测模型,最后进行时间预测。这个故事的目的是强调可以建立一个可持续的和健壮的时间序列预测模型的关键结构。如果需要的话,请随意浏览下面的参考资料部分,以获得各个主题的详细解释。另外提醒一下,我建议您在阅读本文的同时阅读上面链接的代码库。

由瓦尔德马尔·布兰德在 Unsplash 上拍摄的照片

通读几个比较有趣的机器学习教程

关于我

我是 Rahul,目前在研究人工智能,在 Xbox 游戏上实现大数据分析。我在微软工作。除了专业工作之外,我还试图制定一个程序,来理解如何通过使用人工智能来改善世界上发展中国家的经济状况。

我现在在纽约的哥伦比亚大学,你可以通过 LinkedIn 和 Twitter 与我联系。

[参考文献]

  1. https://www . statistics solutions . com/free-resources/directory-of-statistical-analyses/time-series-analysis/
  2. https://towards data science . com/the-complete-guide-to-time-series-analysis-and-forecasting-70d 476 bfe 775
  3. https://en . Wikipedia . org/wiki/auto regressive _ integrated _ moving _ average
  4. https://machine learning mastery . com/ARIMA-for-time-series-forecasting-with-python/
  5. https://otexts.com/fpp2/arima.html
  6. https://towards data science . com/taking-consideration-for-time-series-analysis-4 E1 F4 fbb 768 f
  7. https://www . first intuition . co . uk/fihub/time-series-analysis/

创建您的自定义私有 Python 包,您可以从您的 Git 存储库中 PIP 安装该包

原文:https://towardsdatascience.com/create-your-custom-python-package-that-you-can-pip-install-from-your-git-repository-f90465867893?source=collection_archive---------1-----------------------

实践教程

使用您的 git repo 共享您的自建 Python 包。

像蜜蜂传播花粉一样传播你的代码(图片由迪米特里·格里戈列夫在 Unsplash 上提供)

您已经创建了一些方便的脚本,希望您的同事或其他人使用。在许多公司,像这样的代码被复制并通过电子邮件互相发送。尽管电子邮件是一种非常容易使用的共享代码的工具,但是我们已经不是生活在 90 年代了,所以让我们以一种聪明的方式来分发你的代码。

本文分两步解决上述问题:打包和分发。首先,我们将着重于将您的代码转换成 python 包,以便人们可以轻松地安装它。然后我们将把这个包放到一个存储库中(比如在 Github 或 Bitbucket 上),这样人们就可以访问它了。在本文结束时,您将:

  • 了解 Python 包的要求
  • 能够构建 Python 包或将现有项目转换成包
  • 能够从存储库中 pip 安装自建包
  • 能够更新您的软件包

我们来编码吧!

目标和准备工作

我们在一家为餐馆进行分析的公司工作。餐馆的老板收集关于客人、饭菜和价格的数据。他们给我们发送了一个数据文件,里面有一个具体的问题,比如“什么样的客人会吃鸭肉橙子?”,“我们的南瓜汤是不是定价过高?”,以及“自从我们降低了甜点的价格后,我们看到顾客增加了吗?”

在我多年的工作中,我注意到我使用了很多相同的代码,只是从以前的任务中复制过来。我们的目标是创建一个“工具箱”包,其中包含一些非常通用的代码,我和我的同事可以很容易地用 pip 安装这些代码。然后,每当我们中的一个人想到另一个方便的功能时,我们可以添加它并更新我们的包。

为了实现这一点,我们将首先打包我们现有的代码到一个 Python 包中。然后我们将关注分发这个包,这样我的同事就可以得到它。

包装我们的代码

首先,我们将使用我们的函数并创建一个 Python 包。如果您想使用 pip 进行安装,这是必要的。您可以在 这个资源库 中查看我的所有文件夹和文件。

我们将在下面的步骤中创建一个。查看上面关于如何创建公共 Python 包的文章

1。创建一个 venv

创建一个虚拟环境并添加一个 gitignore,否则,我们将创建一个不必要的大包。

2。创建包文件夹

用您的包的名称创建一个文件夹。对我来说,这就是“工具箱”。这将是我们正在安装的软件包。我们将在包文件夹中创建一些文件:

  • toolbox/functions.py
    这个文件将保存一些我们想要共享的函数。我已经包含了三个函数:listChunkerweirdCasereport
  • 工具箱/init。py
    这将告诉 python 工具箱文件夹是一个 Python 包。这个文件也可以用来导入函数,这样我们除了from toolbox.functions import listChunker还可以import listChunker from toolbox。创建该文件是必需的,但内容是可选的

3。创建 setup.py

这个文件是告诉 pip 你的软件包需要什么来安装它所必需的。让我们来看看我用过的 setup.py。

下面我们将浏览需要更多解释的安装文件行。

  • 第 3 行:在一个名为 long_description 的变量中加载 README.md。这是可选的。
  • 第 7 行:给我们的包命名。必须与您的包文件夹名称匹配
  • 第八行。这是我们软件包的版本。Pip 使用这个版本来查看软件包是否需要更新,因此如果您希望用户能够更新,请确保增加这个版本
  • 第 12 行和第 13 行:从第 3 行加载 README.md 第 13 行指出了自述文件的格式。
  • 第 14 行:您的回购协议的 URL
  • 第 15 行:可选地列出一些方便的 URL
  • 第 18 行:用户如何使用你的套餐?检查choosealicense.com
  • 第 19 行:需要构建的所有包的列表:确保这与您的包文件夹名匹配
  • 第 20 行:您的包所依赖的包的列表。尽管我的函数都不使用请求,但出于演示的目的,我还是决定包含它。在这里包含一个包可以确保当 pip 安装工具箱包时,首先安装 requests,以便工具箱可以使用它。

4。其他可选文件

我决定包含一个 README.md 和一个许可文件。这些是简单的文本文件,并不是真正需要的,但却是一个很好的补充。

我们的仓库是完整的!大家来了解一下怎么分配吧!

通过 GitHub 发布我们的代码

现在我们的包已经创建好了,我们可以使用一个存储库来进行分发。首先,我们将创建存储库并使用它来 pip 安装我们的包。最后,我们将在修改源代码后更新我们的包。

首先,创建一个存储库。你可以在任何使用 Git (GitHub、BitBucket 等)的平台上做到这一点。然后添加你所有的文件,确保忽略不必要的文件,并推送至 repo。

Pip 安装

复制您的存储库的 URL。您可以使用以下 URL pip 安装您的软件包:

pip install git+[https://github.com/mike-huls/toolbox.git](https://github.com/Muls/toolbox.git)

就是这样!很容易不是吗?另请注意,您可以从公共(如工具箱)和私有存储库安装!

更新您的包

假设我的同事提出了一个新功能,并决定将其提交给存储库。我可以使用 pip 来更新我的软件包。每次我调用pip install git+[https://github.com/mike-huls/toolbox.git](https://github.com/Muls/toolbox.git) pip 都会检查 setup.py 文件中的版本号。如果我的同事记得增加版本,那么我的包就会更新。轻松点。

将我们的包裹放入码头集装箱

在 Docker 中使用你的包有一个非常简单的技巧:

其他优势

GitHub 提供了一个记录问题的地方,在“首页”有一个很好的自述文件,甚至在你的包需要更多解释时提供一个 wiki。

结论

正如我们在本文中看到的,结合 Python 打包和 Git 的能力提供了很多优势:

  1. 从一个中心来源(一个真实的来源)轻松分发、安装和更新
  2. 我们包的版本控制和协作能力
  3. 能够在修改后更新软件包
  4. 能够从私有存储库 pip 安装和更新软件包

我希望我已经阐明了很多创建和分发 Python 包的过程。如果你有建议/澄清,请评论,以便我可以改进这篇文章。与此同时,请查看我的其他文章关于各种与编程相关的主题,例如:

  • Python 中的多任务处理:通过同时执行多个任务,将程序速度提高 10 倍
  • 用 FastAPI 用 5 行代码创建一个快速自动归档、可维护且易于使用的 Python API
  • 从 Python 到 SQL —安全、轻松、快速地升级
  • 创建并发布你自己的 Python 包
  • 创建您的定制私有 Python 包,您可以从您的 Git 库 PIP 安装该包
  • 面向绝对初学者的虚拟环境——什么是虚拟环境以及如何创建虚拟环境(+示例)
  • 通过简单的升级大大提高您的数据库插入速度

编码快乐!

—迈克

页(page 的缩写)学生:比如我正在做的事情?跟着我!

https://mikehuls.medium.com/membership

与 Jenkins 和 GitHub 一起创建您的第一个 CI/CD 渠道

原文:https://towardsdatascience.com/create-your-first-ci-cd-pipeline-with-jenkins-and-github-6aefe21c9240?source=collection_archive---------2-----------------------

创建和部署自由式 Jenkins 项目的指南

在 Unsplash 上由 Samuel Sianipar 拍照

因此,快速想象一下,您的团队每天都非常努力地工作,试图尽快推出新功能,但要将更新代码的项目带入测试和生产阶段,我们必须更新服务器,并确保在此过程中不出错。这里显而易见但费力的解决方案是手动将代码从版本控制中拉入服务器,运行测试并给它一个绿色标志,一切都好吗?可悲的是,没有!随着提交频率的增加,开发人员不得不一次又一次地进行整个服务器更新过程。

以下是手动更新服务器的方法:

  1. SSH 进入服务器。
  2. 从 VCS 拉过来。
  3. 启动应用程序之前,请检查配置。
  4. 在容器中启动应用程序。
  5. 检查日志并确保应用程序正在运行。
  6. 结束 SSH 会话。

那么,如何自动化这个过程呢?进入开发运营模式,开发运营侧重于使开发和运营周期相互兼容,它试图将两者结合在一起。 Jenkins 是一个用 Java 构建的 CI/CD 开发运营工具。

正如标题中所提到的,我们将看到 Jenkins 如何帮助我们消除这一手动流程并实现整个流程的自动化。

先决条件

在开始我们的食谱之前,让我们先弄清楚我们的配料。

本教程将使用安装在本地机器上的 Jenkins,以防您在远程计算机上使用它,用您的计算机 IP 替换 localhost

首先,需要将 Jenkins 安装在您尝试部署的计算机上,安装说明如下:https://www.jenkins.io/doc/book/installing/。其次,这个演示将使用 docker,所以如果你想在你的系统上安装 docker,请参考:https://docs.docker.com/engine/install/。

如果你想学习 docker,我创建了一个 GitHub 库来解释 docker 的基础和中间概念。解释用简单的英语组织在降价文件中,每节课后都会提到一些资源。

https://github.com/pratik-choudhari/docker-guide

最后,我们需要在 GitHub 这样的 VCS 上建立一个项目存储库。

安装后步骤

一旦 Jenkins 安装完成,进入 http://localhost:8080 ,会出现一个屏幕要求你解锁 Jenkins。要设置您的用户,这是一个强制性的过程,请遵循以下指南:https://www . Jenkins . io/doc/book/installing/Linux/# setup-wizard

创建詹金斯项目

詹金斯有两种类型的项目,自由式和管道。两者的主要区别在于,管道项目遵循特定的流程,可以有多个代理和阶段来构建、测试和部署项目。自由式项目很容易设置和开始。现在让我们从项目配置开始。

登录后,您会看到这样的屏幕。这是 Jenkins 主页或仪表板,用户可以在这里看到所有创建的管道和管道摘要。

詹金斯仪表板

在这里,我们必须点击左上方的新项目,然后输入项目名称,点击自由式项目,点击确定

下一步是用 VCS 信息配置我们的项目,我将使用 GitHub 作为 VCS。勾选 GitHub 项目并输入资源库 URL。

向下滚动一点,我们可以看到一个源代码管理表单,要求提供登录 VCS 和要使用的分支的凭证。在全新安装的情况下,需要向 Jenkins 添加凭证,为此,请单击添加按钮,输入您的用户名和密码,然后单击添加

现在我们进入构建触发器部分,在这里我们设置触发器,它将告诉 Jenkins 何时构建一个项目。最常见和最有效的方法是使用网络挂钩。

Web 挂钩允许通过使用自定义回调在基于 web 的应用程序之间进行交互。web 挂钩的使用允许 web 应用程序自动与其他 web 应用程序通信。web-hook 被设置为在某个事件发生时触发。

来源:GeeksForGeeks

在我们的例子中,触发 webhook 的事件将是对远程存储库的推送操作。在本教程中,我们不打算使用 webhooks,而是使用 Poll SCM 选项,该选项的作用是根据预定义的时间表不断查询 VCS,以发现新的变化。如果遇到新的变化,Jenkins 将开始项目构建步骤。

这里使用的预定义时间表是**** * * * * ****,这是每分钟的时间表,Jenkins 使用类似 Crontab 的语法,在 crontab.guru 上探索格式。

剩下的唯一一步是编写构建命令,直接进入构建部分,在分离模式下编写 docker 构建和运行命令。

我们已经完成了项目设置,最后一步是点击屏幕底部的保存,并通过点击立即构建按钮开始第一次构建。

如果构建成功,构建号将显示一个绿色勾号图标,您的应用程序将在定义的网络的指定端口上发布,在我们的示例中,应用程序将在 localhost:3000 上运行。您可以通过单击内部版本号旁边的下拉菜单来检查构建过程的控制台输出。

在这个控制台输出的帮助下,用户可以调试构建过程。

结论

希望您能够跟随并成功完成您的第一个构建。我很乐意在评论中回答你的疑问。感谢阅读!保持联系,获取更多关于自动化和 python 项目的教程。

在 FastAPI 中创建您的第一个 REST API

原文:https://towardsdatascience.com/create-your-first-rest-api-in-fastapi-e728ae649a60?source=collection_archive---------7-----------------------

用 Python 创建高性能 API 的分步指南

尼古拉斯·霍伊泽在 Unsplash 上拍摄的照片

在这篇文章中,我将介绍 FastAPI :一个基于 Python 的框架来创建 Rest APIs。我将向您简要介绍这个框架的一些基本特性,然后我们将为联系人管理系统创建一组简单的 API。使用这个框架,Python 知识是非常必要的。

在我们讨论 FastAPI 框架之前,让我们先谈谈 REST 本身。

来自维基百科:

表述性状态转移(REST) 是一种软件架构风格,它定义了一组用于创建 Web 服务的约束。符合 REST 架构风格的 Web 服务,称为 RESTful Web 服务,提供互联网上计算机系统之间的互操作性。RESTful Web 服务允许请求系统通过使用一组统一的、预定义的无状态操作来访问和操作 Web 资源的文本表示。其他种类的 Web 服务,如 SOAP Web 服务,公开了它们自己的任意操作集。[1]

什么是 FastAPI 框架?

来自官方网站:

FastAPI 是一个现代、快速(高性能)的 web 框架,用于基于标准 Python 类型提示用 Python 3.6+构建 API。

是的,它是快,非常快,这是由于对 Python 3.6+异步特性的开箱即用支持,这就是为什么建议使用最新版本的 Python。

FastAPI 是由塞巴斯蒂安·拉米雷斯创建的,他对现有的框架如 Flask 和 DRF 并不满意。你可以在这里了解更多。他们网站上提到的一些主要功能有:

  • :非常高的性能,与 NodeJSGo 不相上下(感谢 Starlette 和 Pydantic)。目前最快的 Python 框架之一。
  • 快速编码:将开发特性的速度提高 200%到 300%左右。*
  • 更少的 bug:减少约 40%的人为(开发人员)导致的错误。*
  • 直观:大编辑支持。无处不在的完成。调试时间更少。
  • 简单:设计为易于使用和学习。减少阅读文件的时间。
  • 简短:尽量减少代码重复。每个参数声明中的多个特性。更少的错误。
  • 健壮:获得生产就绪代码。自动交互式文档。
  • 基于标准:基于(并完全兼容)API 开放标准(Open API)

FastAPI 的创造者相信站在巨人的肩膀上,并使用现有的工具和框架,如 Starlette 和 Pydantic

安装和设置

我将使用 Pipenv 为我们的 API 设置开发环境。Pipenv 使隔离您的开发环境变得更加容易,不管您的机器上安装了什么。它还允许您选择不同于您机器上安装的 Python 版本。它使用Pipfile来管理所有与项目相关的依赖项。我不打算在这里详细介绍 Pipenv,所以将只使用项目所必需的命令。

运行pip install pipenv可以通过 PyPy 安装 Pipenv

pipenv install --python 3.9

安装后,您可以通过运行命令pipenv shell来激活虚拟环境

你也可以运行pipenv install --three,其中三表示 Python 3.x

安装后,您可以通过运行命令pipenv shell激活虚拟环境

首先,我们将通过运行以下命令安装FastAPI:pipenv install fastapi

注意是 pipenv ,不是 pip。当您进入 shell 时,您将使用pipenv。底层使用 pip,但所有条目都存储在Pipfile中。下面的Pipfile会是什么样子:

好了,我们已经建立了我们的开发环境。是时候开始编写我们的第一个 API 端点了。我将创建一个名为main.py的文件。这将是我们 app 的切入点。

from fastapi import FastAPIapp = FastAPI()[@app](http://twitter.com/app).get("/")
def home():
    return {"Hello": "FastAPI"}

如果你在 Flask 上工作过,你会发现它非常相似。导入所需的库后,您创建了一个app实例,并用装饰器创建了您的第一条路线。

现在你想知道如何运行它。FastAPI 附带了一个 ASGI 服务器。您只需运行命令uvicorn main:app --reload

您提供的文件名( )。py)和类对象( app 在这种情况下),它将启动服务器。我使用了--reload标志,这样每次修改后它都会自动重新加载。

访问http://localhost:8000/,您将看到 JSON 格式的消息{"Hello":"FastAPI"}

很酷,不是吗?

FastAPI 也提供了一个 API 文档引擎。如果你访问的是使用 Swagger UI 界面的http://localhost:8000/docs

或者,如果你需要一些奇特的东西,请访问[http://localhost:8080/redoc](http://localhost:8080/redoc)

FastAPI 还提供了 API 端点的 OpenAPI 版本,比如这个[http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json)

路径和参数

让我们继续前进。我们添加了另一个 API 端点。比方说,它是关于通过 id 获取联系信息的。

[@app](http://twitter.com/app).get("/contact/{contact_id}")
def contact_details(contact_id: int):
    return {'contact_id': contact_id}

这里有一个方法,contact_details,它只接受一个int参数,并以dict格式返回它。现在,当我通过 cURL 访问它时,它看起来如下:

现在,如果我传递一个字符串而不是一个整数呢?你会看到下面的

你看到了吗?它返回一条错误消息,指出您发送了错误的数据类型。您不需要为这些琐碎的事情编写验证器。这就是在法斯塔皮工作的美妙之处。

查询字符串

如果以查询字符串的形式传递额外的数据会怎样?例如,您的 API 端点返回大量记录,因此您需要分页。嗯,没问题,你也可以获取这些信息。

首先,我们将导入Optional类型:

from typing import Optional

[@app](http://twitter.com/app).get("/contact/{contact_id}")
def contact_details(contact_id: int, page: Optional[int] = 1):
    if page:
        return {'contact_id': contact_id, 'page': page}
    return {'contact_id': contact_id}

在这里,我传递了另一个参数page,并在这里设置了它的类型Optional[int]。可选的,顾名思义它是一个可选的参数。设置类型int是为了确保它只接受整数值,否则就会像上面那样抛出一个错误。

访问网址http://127.0.0.1:8000/contact/1?page=5,你会看到如下内容:

很酷,不是吗?

到目前为止,我们只是手动返回了dict。一点也不酷。输入一个值并返回一个 YUUGE JSON 结构是很常见的。FastAPI 提供了一种优雅的方式来处理它,使用 Pydantic 模型。

Pydantic 模型实际上有助于数据验证,这意味着什么?这意味着它确保被传递的数据是有效的,否则它返回一个错误。我们已经在使用 Python 的类型提示,这些数据模型使得净化的数据被传递。让我们写一点代码。为此,我将再次扩展 contact API。

from typing import Optionalfrom fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()class Contact(BaseModel):
    contact_id:int
    first_name:str
    last_name:str
    user_name:str
    password:str[@app](http://twitter.com/app).post('/contact')
async def create_contact(contact: Contact):
    return contact

我从 pydantic 导入了BaseModel类。之后,我创建了一个扩展了BaseModel类的模型类,并在其中设置了 3 个字段。请注意,我还设置了它的类型。完成后,我创建了一个POST API 端点,并向其传递了一个Contact参数。我在这里也使用了async,它将简单的 python 函数转换成一个协程。FastAPI 支持开箱即用。

转到http://localhost:8080/docs,您将看到如下内容:

当您运行 CURL 命令时,您会看到如下所示的内容:

正如所料,它只是以 JSON 格式返回了Contact对象。

正如您注意到的,它只是以 JSON 格式转储整个模型,包括密码。即使您的密码不是纯文本格式,它也没有意义。那怎么办呢?响应模型就是答案。

什么是响应模型

顾名思义,响应模型是针对请求发送响应时使用的模型。基本上,当你使用一个模型时,它会返回所有的字段。通过使用响应模型,您可以控制应该向用户返回哪种数据。让我们稍微改变一下代码。

class Contact(BaseModel):
    contact_id:int
    first_name:str
    last_name:str
    user_name:str
    password:strclass ContactOut(BaseModel):
    contact_id:int
    first_name:str
    last_name:str
    user_name:str[@app](http://twitter.com/app).get("/")
def home():
    return {"Hello": "FastAPI"}[@app](http://twitter.com/app).post('/contact', response_model=ContactOut)
async def create_contact(contact: Contact):
    return contact

我添加了另一个类,ContactOut,它几乎是Contact类的副本。这里唯一不同的是没有了password字段。为了使用它,我们将在 post 装饰器的response_model参数中分配它。就是这样。现在,当我运行点击相同的网址,它不会返回密码字段。

如您所见,这里没有可见的密码字段。如果你注意到了/docs的网址,你也会在那里看到它。

如果您愿意在多个方法中使用不同的响应模型,那么使用不同的响应模型是可行的,但是如果您只想从一个方法中省略机密信息,那么您也可以在装饰器中使用response_model_exclude参数。

[@app](http://twitter.com/app).post('/contact', response_model=Contact, response_model_exclude={"password"})
async def create_contact(contact: Contact):
    return contact

输出将是相似的。您在这里设置response_modelresponse_model_exclude。结果是一样的。您还可以将元数据附加到 API 端点。

[@app](http://twitter.com/app).post('/contact', response_model=Contact, response_model_exclude={"password"},description="Create a single contact")
async def create_contact(contact: Contact):
    return contact

我们添加了此端点的描述,您可以在文档中看到。

FastAPI 文档的精彩并没有到此结束,它还让您设置模型的示例 JSON 结构。

class Contact(BaseModel):
    contact_id:int
    first_name:str
    last_name:str
    user_name:str
    password:strclass Config:
        schema_extra = {
            "example": {
                "contact_id": 1,
                "first_name": "Jhon",
                "last_name": "Doe",
                "user_name": "jhon_123",
            }
        }

当你这样做的时候,它会呈现为:

FastAPI 中的错误处理

你总是有可能得不到所需的信息。FastAPI 提供了HTTPException类来处理这样的情况。

[@app](http://twitter.com/app).get("/contact/{id}", response_model=Contact, response_model_exclude={"password"},description="Fetch a single contact")
async def contact_details(id: int):
    if id < 1:
        raise HTTPException(status_code=404, detail="The required contact details not found")
    contact = Contact(contact_id=id, first_name='Adnan', last_name='Siddiqi', user_name='adnan1', password='adn34')
    return contact

简单的端点。它根据 id 返回联系信息。如果id小于 1,则返回一条 404 错误消息,并提供详细信息。

在我离开之前,让我告诉你如何发送自定义标题。

from fastapi import FastAPI, HTTPException, Response[@app](http://twitter.com/app).get("/contact/{id}", response_model=Contact, response_model_exclude={"password"},
         description="Fetch a single contact")
async def contact_details(id: int, response: Response):
    response.headers["X-LOL"] = "1"
    if id < 1:
        raise HTTPException(status_code=404, detail="The required contact details not found")
    contact = Contact(contact_id=id, first_name='Adnan', last_name='Siddiqi', user_name='adnan1', password='adn34')
    return contact

在导入了Response类之后,我传递了Request类型的request参数,并设置了头文件X-LOL

运行 curl 命令后,您会看到类似下面的内容:

你可以在标题中找到x-lol。LOL!

结论

因此,在这篇文章中,您了解了如何开始使用 FastAPI 构建高性能 API。我们已经有了一个名为 Flask 的最小框架,但 FastAPI 的异步支持使它对现代生产系统非常有吸引力,尤其是通过 REST APIs 访问的机器学习模型。我只是触及了它的表面。可以在官方 FastAPI 网站进一步了解。

希望在下一篇文章中,我会讨论一些高级的话题,比如与数据库集成、认证和其他事情。

原载于 2021 年 1 月 23 日http://blog . adnansiddiqi . me

立即创建您的第一个 Tableau 仪表板

原文:https://towardsdatascience.com/create-your-first-tableau-dashboard-in-no-time-203700cc7e0c?source=collection_archive---------35-----------------------

Tableau 的实用介绍

(图片由作者提供)

数据可视化是数据科学不可或缺的一部分。设计良好的可视化是数据探索的一个好方法。与简单的数字相比,通过数据可视化来传递你的发现也更加直观和高效。

Tableau 是创建数据可视化的强大而高效的工具。它允许创建高度信息化的情节,而无需编写任何代码。此外,多个可视化可以很容易地结合到一个仪表板。

Tableau 还提供 Tableau Public,这是一个免费的平台,可以公开分享你的仪表盘。这是展示你的技能和创造力的好方法。

下载 Tableau 桌面的公版即可免费使用 Tableau,该公版适用于 Windows 和 Mac。在本文中,我们将使用 public edition 创建一个简单的仪表板。我们将使用来自 Kaggle 的包含医疗保险数据的数据集。

第一步是添加到数据源的连接。这里强调“连接”这个词很重要,因为 Tableau 连接到数据文件并使用它来创建可视化。它不编辑原始文件。

(图片由作者提供)

我们选择适当的格式,然后导航到保存数据集的文件。

Tableau 连接到文件后,它会提供数据源的概述,并自动创建一个工作表。

数据源(图片由作者提供)

工作表用于在 Tableau 中创建可视化效果,因此我们从左下角选择工作表。默认情况下,它被称为“工作表 1”,但我们可以将其重命名。

(图片由作者提供)

列名显示在左窗格中。我们可以将列拖放到工作表中。我们将创建一个具有三种数据可视化的仪表板。

第一个是包含保险成本的 charges 列的直方图。我们将 charges 列拖到 rows 部分,并选择右侧窗格中的直方图符号。让我们也根据吸烟者列来区分行,以便我们可以看到吸烟对费用的影响。这是通过在 rows 部分添加 smoker 列来实现的。

下面的屏幕记录显示了我们刚刚提到的步骤。

直方图(作者提供的 gif)

就是这样!在 Tableau 中创建直方图就是这么简单。您可能已经注意到了列名旁边的缩写,如 bin 和 CNT。它们表示应用于数据的聚合。我们可以从列名的下拉菜单中更改或自定义聚合。

我们清楚地看到,总体而言,吸烟者的医疗保险费用更高。

最好给工作表一个描述性的名称,这可以通过右键单击工作表的名称来完成。在我们的例子中,我将其重命名为“电荷分布”。

第二个可视化是散点图。我们通过单击左下方工作表名称旁边的图标来创建一个新工作表。

下面是我们如何在 Tableau 中创建散点图:

散点图(作者 gif)

我们将“费用”列拖到“行”部分。在这种情况下,我们不需要任何聚合,所以我们选择它作为一个维度。我们对 bmi 列进行了同样的操作,但是是在列部分。然后 Tableau 自动生成散点图。

我们可以通过在标记窗格下的颜色部分添加吸烟者列,使用不同的颜色来区分吸烟者和非吸烟者。代表数据点的圆圈的大小也可以在这里调整。

第二次可视化完成。我会将其重命名为“Bmi 与费用”,然后为下一个图创建一个新的工作表。

第三个可视化图形是一个显示不同地区 bmi 柱分布的箱线图。

我们将 bmi 列放在 rows 部分,将 region 列放在 columns 部分。然后我们将 bmi 列更改为一个维度。

正如我们可以在屏幕记录中看到的,当列被放入部分中时,绘图选项会在右窗格中突出显示。

方框图(作者 gif)

我将把方框图重新命名为“Bmi 与区域”。它概述了不同地区之间 bmi 值分布的差异。东南部地区的 bmi 值普遍较高。

我们已经使用医疗保险费用数据集创建了三个可视化。下一步是将它们合并到一个仪表板中。我们通过单击工作表旁边左下方的新仪表板图标来创建一个空仪表板。

仪表板(作者图片)

包含可视化效果的工作表显示在左侧。我们现在可以使用工作表自定义控制面板。

填充仪表板(gif by author)

我们可以进行许多定制,以使仪表板更具信息性、功能性和吸引力。例如,我们可以添加一个标题,并将一个特定的可视化设置为过滤器。我们也可以调整大小。

自定义仪表板(gif by author)

我们的仪表板现在已经完成。我们可以将其保存到我们的 Tableau 公共个人资料中,并与其他人分享。这是我的 Tableau 公共配置文件中仪表板的最终版本。

(图片由作者提供)

结论

我们创建了一个简单的仪表板。Tableau 是一个高度通用和实用的工具,因此它可以用来创建更高级的仪表板。然而,最好先理解基础知识。

成为高级 Tableau 用户需要大量的练习。如果您正在或计划在数据科学领域工作,这是一个非常重要的工具。

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

用自然语言处理在 10 分钟内创造你自己的人造莎士比亚

原文:https://towardsdatascience.com/create-your-own-artificial-shakespeare-in-10-minutes-with-natural-language-processing-1fde5edc8f28?source=collection_archive---------7-----------------------

第一部分 | 第二部分 | 第三部分 |自然语言处理

使用递归神经网络和莎士比亚语料库生成莎士比亚风格的文学作品

图一。由杰西卡·潘普在 Unsplash 上拍摄的照片

I

研究表明,用于自然语言处理任务的最有效的人工神经网络类型之一是递归神经网络(RNNs)。rnn 广泛应用于自然语言处理任务,如机器翻译、文本生成、图像字幕等。在 NLP 任务中,我们通常使用 NLP 工具和方法将文本数据处理成向量,然后将它们馈送到选定的人工神经网络,如 RNN、CNN,甚至前馈神经网络,以完成任务。在本帖中,我们将遵循这两个标准化的步骤:(1)将文本处理成向量,(2)用这些向量训练神经网络。

递归神经网络和序列文本数据

在深入我们的教程之前,我们需要讨论一下递归神经网络和顺序数据,因为文本数据具有顺序性。

递归神经网络(RNN)是一类人工神经网络,其中神经元之间的连接形成时间序列。

能够捕获动态时间信息(时间记忆)的 rnn。递归神经网络源自前馈神经网络,但是它们提供了更多。

为什么不是前馈神经网络?

普通前馈神经网络有三个主要限制,使它们不适合序列数据:

  • 前馈神经网络不能考虑阶数;
  • 前馈神经网络需要固定的输入大小;
  • 前馈神经网络不能输出不同长度的预测。

文本数据的基本特征之一是其顺序的重要性。就像重新排列月销售额的顺序可以将我们从上升趋势引向下降趋势一样,重新排列句子中单词的顺序可以完全改变或扭曲它的意思。这就是前馈神经网络的局限性所在。在前馈神经网络中,由于这种限制,不能考虑数据的顺序。重新安排月销售额的顺序会得到同样的结果,这证明他们不能利用投入的顺序。

图二。深度学习中的潜在序列数据任务(图由作者提供)

递归神经网络拯救世界

RNN 通过将以前的信息保存在内存中来使用它们,这些信息以“状态”的形式保存在 RNN 神经元中。有几种类型的 RNN,如香草 RNN,GRU 和 LSTM。

下面用一个基本的天气预报例子来说一下记忆结构。我们想通过使用序列中提供的信息来猜测是否会下雨。该数据序列可以从文本、语音或视频中获得。每有新的信息,我们就慢慢更新降雨的概率,最后得出结论。图 3 显示了这项任务:

图 3。一个简单的天气预报任务:会下雨吗?(图由作者提供)

在图 3 中,我们首先记录了多云天气。这一单一信息可能指示降雨,这计算成 50%(或 0.5)的降雨概率。然后,我们收到以下输入:一条拥挤的街道。拥挤的街道意味着人们在外面,这意味着降雨的可能性更小,因此,我们的估计下降到 30%(或 0.3)。然后,我们被提供了更多的信息:膝盖疼痛。人们认为风湿病患者在下雨前会感到膝盖疼痛。因此,我的估计上升到 70%(或 0.7)。最后,当我们的模型将闪电作为最新信息时,集体估计增加到 90%(或 0.9)。在每个时间间隔,我们的神经元使用它的记忆——包含以前的信息,并在这个记忆的基础上添加新的信息,来计算降雨的可能性。可以在层级别以及单元级别设置存储器结构。图 4 示出了细胞水平的 RNN 机制,(I)左边是折叠版本,右边是展开版本。

图 4。一种基于细胞的递归神经网络活动(图片由作者提供)

RNN 类型

如前所述,RNNs 有许多不同的变体。在本节中,我们将介绍我们经常遇到的三种 RNN:

  • 简单的 RNN
  • 长短期记忆(LSTM)网络
  • 门控循环单元(GRU)网络

您可以在图 5 中找到这些备选 RNN 单元的可视化效果:

图 5。递归神经网络的 3 种流行变体:香草 RNN、GRU、LSTM

门控循环单元(gru)——门控循环单元由 Kyunghyun Cho 于 2014 年推出。正如 LSTMs 一样,gru 也是 RNNs 中处理序列数据的门控机制。然而,为了简化计算过程,GRUs 使用两个门:(I)复位门和(ii)更新门。gru 也为隐藏状态和单元状态使用相同的值。图 5 显示了门控循环单元的内部结构:

基于莎士比亚语料库的神经文本生成

在这个案例研究中,我们的目标是训练一个能够从字符中生成有意义文本的 RNN。RNN 可以从单词和字符中生成文本,我们选择使用字符来生成这个案例研究的文本。

当我们建立一个没有经过训练的新 RNN 时,它组合了一堆毫无意义的字符,这没有任何意义。然而,如果我们给我们的 RNN 输入大量文本数据,它就会开始模仿这些文本的风格,并使用字符生成有意义的文本。

所以,如果我们给模型输入大量说教性的文本,我们的模型就会生成教育材料。如果我们给我们的模型输入大量的诗歌,我们的模型将生成诗歌,所以我们将有一个人工诗人。这些都是可行的选择,但是我们将为我们的模型提供一些其他的东西:一个包含莎士比亚作品的长文本数据集。因此,我们将创建一个莎士比亚机器人。

莎士比亚文集

图 6。维基媒体上的一本莎士比亚的书

莎士比亚语料库(Shakespeare Corpus)是一个包含 40000 行莎士比亚作品的文本文件,由 Karpathy 清理和准备,由 TensorFlow 团队托管。我强烈建议您看一下.txt文件,以理解我们正在处理的文本。该文件包含对话内容,其中每个角色的名字放在相应部分的前面,如图 7 所示。

图 7。莎士比亚语料库中的随机样本文本(图由作者提供)

初始进口

在本案例研究中,所需的库是 TensorFlow、NumPy 和 os,我们可以使用以下代码导入它们:

要从在线目录加载数据集,我们可以使用 TensorFlow 中 Keras API 的 util 模块。对于这个任务,我们将使用get_file()函数,如果文件不在缓存中,它将从 URL 下载文件,代码如下:

下载完我们的文件后,我们可以用下面的 Python 代码从缓存中读取文件。现在,我们成功地将整个语料库作为变量保存在了 Colab 笔记本的内存中。让我们看看语料库中有多少个字符,前 100 个字符是什么,代码如下:

图 8。语料库的前 100 个字符(由作者提供)

我们的整个语料库可以通过一个名为*text*的 Python 变量来访问,现在我们可以开始对它进行矢量化了。

向量化文本

文本矢量化是一种基本的 NLP 方法,用于将文本数据转换为机器可以理解的有意义的数字向量。文本矢量化有多种方法。在本案例研究中,我们是这样一步步进行的:

  • 给每个独特的字符一个索引号;
  • 在语料库中运行一个 for 循环,并索引整篇文本中的每个字符。

为了给每个独特的字符一个索引号,我们首先要找到文本文件中所有独特的字符。使用内置的set()函数很容易做到这一点,该函数将 list 对象转换为 set 对象。

T *he difference between set and list data structures is that lists are ordered and allow duplicates while sets are unordered and don’t allow duplicate elements. So, when we run the set() function -as shown in the below code-, it returns a set of unique characters in the text file.*

输出:

图 9。唯一字符列表的一部分(图由作者提供)

我们还需要给每个字符一个索引号。下面的代码为每个集合项分配一个数字,然后用给定的数字创建一个集合项字典。我们还制作了 NumPy 数组格式的唯一集合元素的副本,供以后解码预测时使用。然后,我们可以使用一个简单的 for 循环对文本进行矢量化,遍历文本中的每个字符,分配它们对应的索引值,并将所有索引值保存为一个新列表,代码如下:

创建数据集

此时,我们用char2idx字典对文本进行矢量化,用idx2char对矢量化后的文本进行去矢量化(即解码)。最后,我们将text_as_int作为矢量化的 NumPy 数组。我们现在可以创建数据集了。

首先,我们将使用 Dataset 模块中的from_tensor_slices方法从我们的text_as_int对象中创建一个 TensorFlow Dataset 对象,我们将把它们分成几批。数据集的每个输入的长度限制为 100 个字符。我们可以用下面的代码实现所有这些:

我们的序列对象包含字符序列,但是我们必须创建一个这些序列的元组,以馈入 RNN 模型。我们可以通过下面的自定义映射函数来实现这一点:

我们生成这些元组的原因是为了让 RNN 工作,我们需要创建一个管道,如图 10 所示:

图 10。一个具有 4 维输入和输出层的 RNN 的例子。注意输入和输出字符之间的延迟。

最后,我们将数据集打乱,分成 64 个句子批次,每行如下:

构建模型

我们的数据已经准备好输入模型管道。让我们创建我们的模型。我们希望训练我们的模型,然后做出新的预测。首先,让我们用下面的代码设置一些参数:

现在,重要的是,我们的训练管道将在每一批输入 64 个句子。因此,我们需要构建我们的模型来一次接受 64 个输入句子。然而,在我们训练了我们的模型之后,我们想要输入单句来生成新的任务。所以,我们需要不同的训练前和训练后模型的批量大小。为了实现这一点,我们需要创建一个函数,它允许我们为不同的批量大小重现模型。下面的代码可以做到这一点:

我们的模型有三层:

  • 一个嵌入层:这一层作为输入层,接受输入值(数字格式中的)并转换成矢量。
  • GRU 层:填充了 1024 个梯度下降单元的 RNN 层
  • 密集层:输出结果,用vocab_size输出。

现在,我们可以使用以下代码创建我们的培训模型:

图 11 总结了我们的模型:

图 11。培训模型的概要视图(由作者提供的图)。请注意输出形状中的 64,对于训练后的单个预测,它必须为 1

编译和培训

为了编译我们的模型,我们需要配置我们的优化器和损失函数。对于这个任务,我们选择Adam作为我们的优化器,稀疏分类交叉熵函数作为我们的损失函数。

由于我们的输出总是 65 个字符中的一个,这是一个多类分类问题。因此,我们必须选择一个分类交叉熵函数。然而,在这个例子中,我们选择了分类交叉熵的一个变体:稀疏分类交叉熵。我们使用稀疏分类交叉熵,因为即使它们使用相同的损失函数,它们的输出格式也是不同的。请记住,我们将文本矢量化为整数(,【2】,【1】,),而不是一键编码格式(,例如【0,0,0】,【0,1】,【1,0,0】,)。为了能够输出整数,我们必须使用稀疏分类交叉熵函数。

为了能够设置自定义损失函数,我们创建了一个包含稀疏分类交叉熵损失的基本函数:

现在,我们可以使用以下代码设置损失函数和优化器:

为了能够加载我们的重量并保存我们的训练成绩,我们需要使用以下代码设置和配置一个检查点目录:

我们的模型和检查点目录已经配置好了。我们将为我们的模型训练 30 个时期,并将训练历史保存到名为 history 的变量中,代码如下:

图 12。模特训练的最后八个时期(图由作者提供)

由于模型的简单性以及我们对模型的编码方式,我们的培训并不需要太长时间(大约 3-4 分钟)。现在,我们可以使用保存的权重,构建一个接受单个输入来生成文本的定制模型。

生成新文本

为了能够查看我们最新检查点的位置,我们需要运行以下代码:

现在,我们可以使用我们之前创建的自定义函数,使用保存在 latest_checkpoint 中的权重,用batch_size=1load_weights构建一个新模型,使用 build 函数基于接收到的输入形状构建模型(即【1,无】)。我们可以用下面的代码实现所有这些和summarize()的新模型:

图 13。新创建的模型的概要视图(图由作者提供)。现在它接受单一输入。

我们的模型已经准备好进行预测,我们所需要的只是一个定制函数来为模型准备输入。我们必须设置以下内容:

  • 要生成的字符数,
  • 向量化输入(从字符串到数字),
  • 存储结果的空变量,
  • 手动调整预测可变性的温度值,
  • 对输出进行去因子化,并且还将输出再次馈送到模型用于下一次预测,
  • 将所有生成的字符连接成一个最终字符串。

下面的自定义函数执行所有这些操作:

它返回我们的最终预测值,我们可以很容易地生成一个文本,我们可以使用下面的代码用内置的打印函数打印出来:

图 14。由我们的模型生成的 500 个字符长的文本(图由作者提供)

最后的话

使用门控循环单元和莎士比亚语料库,您为自己构建了一个能够生成任意长度文本的莎士比亚机器人。

*Note that our model uses characters, so the miracle of the model is that it learned to create meaningful words from characters. So, do not think that it adds a bunch of unrelated words together. It goes over thousands of words and learns the relationship between different characters and how they are used to create meaningful words. Then it replicates this and returns us sentences with meaningful words.*

您可以随意使用 temperature,看看如何将输出从更合适的单词变成更失真的单词。较高的温度值会增加我们的功能选择不太可能的字符的机会。当我们把它们都加起来时,我们得到的结果就没那么有意义了。另一方面,低温会导致函数生成更简单的文本,更像是原始语料库的副本。

让我们保持联系

除了我的最新内容,我还与我的订户分享我的 Google Colab 笔记本 ,其中包含我发表的每篇文章的完整代码。如果你喜欢这篇文章,考虑订阅时事通讯: 订阅时事通讯!✉️

既然您正在阅读这篇文章,我相信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . yaln—Linkedin

创建自己的 Python 包,并将其发布到 PyPI 中

原文:https://towardsdatascience.com/create-your-own-python-package-and-publish-it-into-pypi-9306a29bc116?source=collection_archive---------3-----------------------

在本文中,您将找到将代码转换成 Python 包并将其上传到 Python 包索引站点的简单步骤

由 Pixabay 授权

您愿意与全球 Python 开发者社区分享您的代码吗?

开始吧!

我假设正在阅读本文的大多数人已经运行了下面的命令。但是,幕后发生了什么?

pip install pandas

在你运行命令 pip install 的时候,你正在访问 PyPI 站点来下载一个包。网站https://pypi.org/是 Python 编程语言的软件仓库。

步骤 0:准备要共享的代码

作为一个例子,我将使用几个程序转换成一个 Python 包。这个代码是一个简单的游戏,能够“猜测”玩家心中的数字。你可以在我的 GitHub 库中看到代码。

文件夹内容。作者图片

步骤 1:创建 init。py 文件

创建一个名为 init 的文件。py 并将其保存到您的代码所在的文件夹中。这个文件告诉 Python 这个文件夹包含一个 Python 包。 init 里面的代码。每当您在 Python 程序中导入一个包时,就会运行 py 文件。在这种情况下,我的 init。py 文件正在从 numberGuesserGame 模块导入 GuessMyNumber 类。

init。py 文件内容。作者图片

现在,我的文件夹里有三个文件:

文件夹内容。作者图片

步骤 2:创建 setup.py 文件

在目录中向上一级,创建 setup.py 文件。

文件夹内容。作者图片

这个重要的文件包含关于包的信息。每次运行命令 pip ,它都会自动寻找 setup.py 文件。

setup.py 文件内容。作者图片

它主要包括对 setup 函数的调用,该函数接收参数以指定项目如何定义的细节,例如,名称、作者、版本、描述等。

步骤 3:在本地安装您的软件包

完成步骤 1 和 2 后,就可以在本地安装 Python 包了。首先,打开一个终端,转到包含您的软件包的文件夹,键入下面的命令。圆点表示在当前文件夹中查找 setup.py 文件,并在其中安装软件包。

pip install .

现在,您可以留在该文件夹中或移动到另一个文件夹来运行 Python 并使用您的包。让我们看看这个例子:

运行我的包。作者图片

步骤 4:创建许可证和自述文件

回到包含您的包的目录,再创建两个文件:

  • License.txt 将告诉用户使用你的软件包的条款和条件。我将麻省理工学院的许可证复制并粘贴到我的文件中
  • README.md 会简单的告诉用户你的包是关于什么的

你的文件夹应该看起来像下面的图片,你的包,和 4 个附加文件:

文件夹内容。作者图片

第五步。生成您的源代码发行版

一旦你有了所有需要的文件,使用下面的命令安装最新版本的 setuptools 包(我们在 setup.py 文件中使用)。

python -m pip install --user --upgrade setuptools

确保您位于 setup.py 所在的目录中,并运行以下命令:

python setup.py sdist

你会看到有一个新的文件夹 dist 包含了 tar.gz 文件,它提供了元数据和 pip 安装所需的基本源文件。

文件夹内容。作者图片

您还会看到一个 ProjectName.egg-info 文件夹,它包含需要移动到目标系统上特定位置的文件和元数据。别担心,你可以忽略它,删除它或在这里了解更多信息。

第六步。为测试 PyPI 和 PyPI 存储库创建帐户。

去 PyPI 测试和 PyPI 网站创建你的账户,记住你的密码很重要,这些密码很快会被重新输入命令行。

第七步。将您的包上传到测试 PyPI 存储库

下一步是安装 twine ,这个实用程序将帮助你把你的包上传到 PyPI 仓库或者其他仓库。一旦安装好绳线,就不需要重复这个步骤。

pip install twine

打开一个终端,在你的命令行中输入下面的命令,它会要求你提供你之前在步骤 6 中创建的用户名和密码。

twine upload --repository-url https://test.pypi.org/legacy/ dist/*

上传包裹。作者图片

文件夹内容。作者图片

登录到 Test PyPI 存储库并验证您的包在那里。如果是这样,复制软件包名称下的命令,在命令行中运行它,并在屏幕上阅读说明软件包已成功安装的消息。

pip install -i https://test.pypi.org/simple/ guesser-game

第八步。将您的包上传到 PyPI 存储库

最后,这是您必须运行的最后一个命令,以便与全球 Python 开发人员社区共享您的包。确保你在 setup.py 文件所在的同一个目录下。

twine upload dist/*

现在,这个包在 PyPI 仓库中!

文件夹内容。作者图片

结论:

知道如何上传你的 Python 包很重要,但在我看来,愿意分享你的知识、与社区合作、创造学习文化和寻找不同的做事方法同样重要,甚至更重要。

更多参考资料,可以回顾一下packaging.python.org。

用 R 中的 Pagedown 包创建你的简历

原文:https://towardsdatascience.com/create-your-resume-with-pagedown-package-in-r-123ca6310d52?source=collection_archive---------10-----------------------

使用 pagedown 包在 1 小时内制作令人印象深刻的简历

马库斯·温克勒在 Unsplash 上拍摄的照片

过去,我一直梦想用 LaTeX 制作我的简历,但要达到这种完美的学习曲线似乎从未实现。因此,我总是以使用 word 文档制作简历告终,并默默忍受随之而来的对齐问题。

最近,我正在经历更新简历的相同周期,并在对齐上花了很多时间。然后我想,让我们看看是否有一个永久的解决方案,偶然间,我想到了 Nick Strayer 的这个可爱的博客,它提供了一个非常简单的解决方案,通过将简历分成不同的 CSV 文件来自动构建简历。并进一步添加了一个选项来选择要在简历上显示的子部分。这种风格可以灵活地为不同的工作类型创建有针对性的简历。来自pagedown包的内置简历模板负责简历的格式。所以,在某种程度上,这是一个我一直在寻找的无忧无虑的解决方案。

受博客的启发,我创建了这个详细的教程来制作简历,添加我觉得博客中没有充分涵盖的细节(像我这样没有或很少了解 CSS 的人)。

使用 R pagedown包简历模板增强您的数据组合。

我们将把简历构建分为以下 4 个部分:

  1. 简历要点
  2. 模板定制
  3. 打印到 Pdf
  4. 数据自动化

最终目标是让定制的模板启动并运行,如图所示。

简历模板(图片由作者提供)

如果你还没有安装pagedown包,首先你要在 RStudio 中制作你的简历。该软件包带有一个内置的简历模板。在安装完pagedown包之后,首先创建一个新的R Markdown文档。

创建一个新的 R Markdown 文档(图片由作者提供)

弹出一个新窗口,选择【模板中的选项,然后pagedown打包 HTML 恢复模板,点击确定

按 pagedown 选择 HTML 简历模板(按作者选择图片)

这将在 RStudio 上打开简历的默认版本。编织文档,它可能会要求你先保存文档,之后,它会编译简历,一个新的窗口会弹出简历。默认的简历会是这样的。

默认简历(图片由作者提供)

简历要点

简历分为两个面板:主面板和侧面板。在上面的图片中总共标出了 8 个区域,这些区域将在下面解释,这将有助于你建立你的简历。

所以我们暂时先不讨论 YAML 的头球部分,稍后再来讨论。在 YAML 标题块的后面是上图中被标记为侧栏的标题和被标记为主面板的 标题。第 1-5 点来自简历主面板,第 6-8 点来自侧边栏。让我们逐点而行(参考上图):

点 1 :你的名字或主标题的占位符。

第二点 :这是你简历的副标题(突出你希望招聘人员或招聘经理注意到的重要细节)。

第三点 :总结部分。你们很清楚该填什么。

第 1 点至第 3 点将在下面重点介绍。

*Main
================================================================================Lijia Yu {#title}                        ***[POINT 1: heading]***
--------------------------------------------------------------------------------### Currently searching for a PhD student position             ***[POINT 2: sub-heading]***TEXT SUMMARY                              ***[POINT 3: summary]****

如果您不太熟悉章节标题的标记语法,标题下的一系列=相当于标题前的#,一系列—相当于##。(文本来自 Pagedown 手册)

这一部分可以重复写:工作经历,研究经历,证书,教育等。,模式也是一样的。所以这一段文字可以重复复制。

简历模板中使用的图标均来自 字体牛逼网站。**

第 5 点 :一旦你定义了一个部分,它可以进一步分解成许多子部分。该子部分有 5 个要填写的字段,其中前 4 个是必填字段。第一个是小节的标题,第二个是小节的副标题,第三个是位置,第四个是时间段。时间段可以是一年,如 2021 年,也可以是一个范围,如 2020 年 2 月至 2021 年 3 月或 2020 年至 2021 年。第五个字段不是强制性的,用于支持文本,可以留空。第 4 点和第 5 点解释如下:

****Education {data-icon=graduation-cap}   ***[POINT 4: section heading]***
--------------------------------------------------------------------------------### Beijing University of Chemical Technology  ***[POINT 5: subsection                    heading]***B.S. in Information and Computing Sciences    ***[POINT 5: subtitle]*** Beijing, China                                ***[POINT 5: location]***2010                                          ***[POINT 5: time period]*** Thesis: Dyadic wavelet and its application in edge detection
                                          ***[POINT 5: supporting text]*******

在 4 个必填字段中,只有副标题、位置和时间段字段可以通过填写 N/A 来跳过。

第五个字段是向您的子部分添加细节。默认情况下,文本将作为单列发布,但可以使用如下所示的:::concise块将显示更改为 2 列。

****:::concise
- sentence 1
- sentence 2
- sentence 3
- sentence 4
:::****

现在让我们继续讨论第 6-8 点。

第 6 点 :默认情况下,模板中会插入一个 logo,只要在文本中添加正确的路径,任何图片都可以更改这个 logo。

****Aside
================================================================================![Lijia Yu]([https://avatars1.githubusercontent.com/u/895125?s=400&v=4){width=80%](https://avatars1.githubusercontent.com/u/895125?s=400&v=4){width=80%)}****

第 7 点 :联系信息部分是您可以突出显示您的社交媒体页面或博客以及个人联系信息的地方。再次图标来自字体真棒网页。联系人信息中的信息可以通过以下方式添加:

****- <i class="fa fa-github"></i> [github.com/yulijia]([https://github.com/yulijia](https://github.com/yulijia))****

第 8 点 :技能部分是你可以记下所有技能的地方。如果您想列出技能,可以通过以下方式完成:

****Skills {#skills}
--------------------------------------------------------------------------------
- skill 1
- skill 2
- skill 3****

到目前为止,我们已经介绍了制作简历的基本要素。编辑好的简历会让你知道它会是什么样子。如果你对当前版本满意,那么你可以跳到最后。如果你不确定它的外观,那么让我们来看看它的定制部分。

模板定制

乍一看,如果你认为沿着边框有大量的空白,或者侧边栏太厚,甚至你认为字体样式与你的风格不符,那么你需要定制它。你甚至可以使用左侧时间轴的颜色和侧边栏的背景颜色。

要解决所有这些问题,你需要了解 CSS。如果你和我一样没有 CSS 背景,那么继续读下去。

**页边距:要覆盖预定义的函数,需要在函数前添加一个星号(*),如下文所示。这样就可以为页面定义新的边距值。

******* {
  /* Override default margins*/
  --pagedjs-margin-right: 0.2in;
  --pagedjs-margin-left: 0.2in;
  --pagedjs-margin-top: 0.2in;
  --pagedjs-margin-bottom: 0.2in;
}******

**侧边栏宽度:在根函数中,侧边栏宽度的默认值为 15 rem。这个值可以被改变以获得想要的侧边栏宽度。对于目前的情况,它已被分配到 12 雷姆。

 ******--sidebar-width: 12rem;******

**侧边栏颜色:在 root 功能中,侧边栏背景颜色也可以改变。出于演示目的,颜色从#f2f2f2切换到#a2e2e2

******--sidebar-background-color: #a2e2e2;******

**时间线颜色:简历左侧的时间线是由同一板块下的点连接起来的竖线组成。垂直线的粗细和颜色都可以更改,如下所示。

******--decorator-border: 2px solid #a2e2e2;** /* change color and thickness of timeline */****

此外,点的背景颜色可以如下所示进行更改。

 ******background-color: #a2e2e2; /* change color timeline dots */******

**字体类型:通过定义字体族,可以在 body 函数中改变字体类型。在这个例子中,我将字体从 Open Sans 改为 Roboto ,两者都是无衬线字体。

******/* Define the font family here */
body{
  font-family: "Roboto", sans-serif;
}******

为定制所做的所有更改都在override.css文件中定义。完整的代码在这里:

为了在 CSS 文件中包含所有的更改,我们可以完全覆盖现有的 CSS 文件,或者在 YAML 文件头中使用新的规则来覆盖某些规则。这是通过添加带有 CSS 扩展名的新文件名来完成的。新创建的 CSS 文件应该保存在 markdown 文件所在的文件夹中。原始 CSS 文件的位置将是…Resume_demo_files\paged-0.13\css\resume.css。该文件夹将在减价文件以默认状态编织时创建。

****output:
  pagedown::html_resume:
    css: 
      - override.css         # OVERIDE CERTAIN FUNCTIONS OF CSS
      - resume               # DEFAULT FILE****

打印到 pdf

您会注意到,当您编制降价文件时,会弹出一个窗口,在左上角显示带有 在浏览器中打开 选项的简历。点击这个选项,它会在你的浏览器上打开一个空白标签。要使简历显示在浏览器选项卡上,必须将 YAML 设置从默认值“假”更改为“真”。这可以通过将self_contained: false设置为self_contained: true来实现。然后,可以通过在浏览器选项卡上打印显示的简历来生成 pdf。

创建 pdf 文件的另一个选项是将knit: pagedown::chrome_print添加到 YAML 文件头。

数据自动化

现在到了简历制作的最佳部分,你可以自动填写数据。感谢 Nick Strayer 让我的简历从仅仅定制变成了完全数据自动化。和往常一样,你需要为简历的所有部分创建主数据 CSV 文件。主数据可以通过两种方式完成:

  1. **CSV 文件:创建 CSV 文件,并根据您的需要不断更新。CSV 文件可以在您的个人设备或 google sheets 上制作。可以为工作、技能和联系方式建立单独的文件。
  2. **混合方法:如果您很着急,那么您可以直接填写简历模板的降价文件中的字段,并会给出默认简历模板中显示的所需输出,或者包含定制内容。在某些情况下,可能会使用 CSV 文件来添加数据。因为我倾向于使用技能栏来突出我的编程技能的熟练程度,而不是仅仅将它们作为文本添加。所以我选择混合方法。

因此,让我向您演示一下,通过使用默认简历模板中的文本来自动构建简历意味着什么。第一步是创建 CSV 文件。以下是工作和教育历史的 CSV 文件详细信息的示例。

作者图片

一旦你创建了文件,你就可以使用简历模板,链接在末尾。有两个 R 文件与模板相关联。如果需要从 google sheets 或 CSV 文件中读取数据,那么gather_data.R会寻找数据源。降价文件中指出了对此的偏好。当功能涉及教育、工作历史、联系信息、技能等时,parsing_functions.R将相关信息粘贴到降价文件中。被召唤。

如果技能栏的颜色需要改变,那么参考parsing_functions.R文件并寻找build_skill_bars()功能。

结论

在本文中,我一步一步地展示了如何从pagedown包中定制默认的简历模板。这是通过中断模板的工作流实现的。在第一部分中,解释了模板的基本构造块和需要注意的区域。第二部分集中在模板定制上,寻找可能的陷阱并根据我的需要定制它们。第三部分是生成一份 pdf 版本的简历。

第四部分,也就是最后一部分,是基于 Nick Strayer 的工作,关于简历中数据填充的自动化。在这一部分,我试着解释了需要关注的一些基本特征,以使简历能够立即运行起来。

通过这种方式,您可以展示您的数据技能和由 R pagedown软件包支持的数据组合。

简历模板的链接:

定制简历:链接

自动化定制简历:链接

参考资料:

  1. https://livefreeordichotomize . com/2019/09/04/building _ a _ data _ driven _ cv _ with _ r/
  2. https://pagedown.rbind.io/
  3. https://fontawesome.com/

您可以在 LinkedIn 和 Twitter 上与我联系,跟随我的数据科学和数据可视化之旅。

使用 Python、Dash 和 Plotly 创建更好的仪表板

原文:https://towardsdatascience.com/creating-a-better-dashboard-with-python-dash-and-plotly-80dfb4269882?source=collection_archive---------0-----------------------

让您开始使用 python 轻松创建仪表板的演练。

仪表板——来自 Pexels 的迈克拍摄

介绍

我的爱好是研究商品和期货的深度。正如人们可能想象的那样,其中包含大量数据和分析。表格、报告、图表、图形——应有尽有。

在努力前进并弄清楚这一切的过程中,我发现自己需要想象那些并不总是存在的东西。我需要以我想要的方式查看数据。

如果你从事任何形式或行业的数据分析,你可能已经知道我在说什么了。然而,有很多刚接触数据分析的人只是在尝试。也有一些比较有经验的人只是没用过这些工具。

这篇文章是写给那些想做更多事情或者想尝试新工具的人的。也许你已经完成了 Dash 和 Plotly 的基础部分,想看看不同的东西。

希望这能回答一些问题或激发一些新的创意。

期待什么

我将用一种全新的方法来研究这篇文章。我将解释这个项目是如何产生的,它的结构和功能,以及我认为它未来的发展方向。

由于大小的原因,我无法对所有内容进行完整的逐行解剖。然而,我已经煞费苦心地编写了包含大量内联文档的冗长而简单的代码。作为补充,存储库文件将是非常宝贵的。

我的目的是提供一个运行这样一个项目的模板概述,并展示一些可能的东西。你不需要真正理解底层数据,甚至不需要对它感兴趣就能获得洞察力。如果你对商品和期货感兴趣,那么这将会有一个全新的价值维度。

开始的时候…

正如我在介绍中所说,我的爱好是收集和分析商品数据。这些数据的一个重要来源是商品期货交易委员会(CFTC)提供的每周报告。

我在整个项目中使用的数据保存在这里:https://www . CFTC . gov/market reports/CommitmentsofTraders/index . htm

对我来说,整个项目始于对一些报告的剖析。当我第一次开始时,我编写了一个快速脚本,它将获取报告,对文件进行一些处理,添加一些值,并输出一些图表。然后举报数量开始增长。

随着我的继续,我开始观察多种商品。我运行我的脚本,让几十个标签用各种各样的图表填满浏览器窗口。这是不可持续的。

我需要组织这一切。因此,仪表板被概念化了。

像所有懒惰的程序员一样,我从一个模板开始。该模板碰巧是我过去使用的标准模板,并针对更大的数据库驱动的分析系统进行了改进。我开始撕掉我不需要的东西,开始建造。

我提出这个并不是为了用不必要的描述和故事来浪费时间,而是为了给出一些架构决策背后的一些逻辑。乍一看似乎很奇怪的事情。然而,当把简单的系统扩展成更健壮和更复杂的系统时,这一切都是有意义的。

好的解决方案解决今天的问题。更好的解决方案着眼于未来。伟大的系统融合了这两者。

代码

当我们深入研究时,你需要访问代码。这是我的这个项目资源库的链接。所有代码示例和参考均来自此处:

https://github.com/brad-darksbian/commodities-dashboard

商品仪表板——我们在构建什么

高层设计

该仪表板包含多个元素,这些元素被划分为不同的组织文件。

  1. main.py —此文件包含仪表板代码,用作前端组织文件。
  2. support_functions.py —这个文件是系统的核心。从报告检索到实际图表创建的一切都存在于此。
  3. business_logic.py —该文件充当收集数据和设置必要数据框架的桥梁。
  4. layout_configs.py —该文件包含帮助器元素,用于按照我希望的方式设计图表,以及定义我希望使用的工具。

如果我要进一步重构,我可以通过重新组织来删除其中的一些文件。然而,随着系统的增长,它为适当地合并其他功能提供了一个很好的平衡。例如,在我的较大的应用程序中,我的 business_logic 文件处理数据库调用和更多的数据争论,然后才进行传递。

支持功能

让我们从讨论一些获取数据所需的后台函数开始。没有一些数据,我们真的做不了什么。

deacot_file = "/tmp/deacot2021.txt"
da_file = "/tmp/deacot_DA_2021.txt"# Data Retreival and Handling
# Function to retrieve reports
def get_COT(url, file_name):
  with urllib.request.urlopen(url) as response, open(file_name, "wb") as out_file:
    shutil.copyfileobj(response, out_file)
  with zipfile.ZipFile(file_name) as zf:
    zf.extractall()# Function to make sure things are fresh for data
def get_reports():
  freshness_date = datetime.now() - timedelta(days=7)
  if os.path.exists(deacot_file):
    filetime = datetime.fromtimestamp(os.path.getctime(deacot_file))
    if (filetime - timedelta(days=7)) <= freshness_date:
      print("Deacot file exists and is current - using cached data")
    else:
      get_COT(
        "https://www.cftc.gov/files/dea/history/deacot2021.zip",
        "deacot2021.zip",)
      os.rename(r"annual.txt", deacot_file)
      print("Deacot file is stale - getting fresh copy")
  else:
    print("Deacot file does not exist - getting fresh copy")
    get_COT(
      "https://www.cftc.gov/files/dea/history/deacot2021.zip",
      "deacot2021.zip")
    os.rename(r"annual.txt", deacot_file) if os.path.exists(da_file):
    filetime = datetime.fromtimestamp(os.path.getctime(da_file))
    if (filetime - timedelta(days=7)) <= freshness_date:
      print("Disaggregation report file exists and is current - using cached data")
    else:
      get_COT( "https://www.cftc.gov/files/dea/history/fut_disagg_txt_2021.zip",
        "fut_disagg_txt_2021.zip",)
      os.rename(r"f_year.txt", da_file)
      print(
        "Disaggregation report file is stale - getting fresh copy")
  else:
    print(
      "Disaggregation report file does not exist - getting fresh copy")
    get_COT(
   "https://www.cftc.gov/files/dea/history/fut_disagg_txt_2021.zip",
      "fut_disagg_txt_2021.zip",)
    os.rename(r"f_year.txt", da_file)

上面的两个函数(在 Medium 的代码框中被可怕地格式化了)做了几件事。首先,函数 get_reports()评估文本报告文件是否存在。如果是,则检查它们是否是“新鲜的”,因为它们少于或等于七天。如果它们是好的,则使用现有的文件。如果没有,则检索新的。同样,如果文件不存在,则从 CFTC 网站检索。

文件检索使用第一个函数 get_COT,并将 url 和文件名作为参数。这些函数使用 python 模块 zip 文件、url lib、shutil、os 和 datetime。设置两个变量来定义路径。

如果使用此代码,请记住根据您的情况适当地设置这些变量。

一旦我们有了文件,我们就有了要处理的数据。但是,它还是生的。文件“deacot_process”和“DA_process”中的下两个函数会对数据帧进行一些修改。

一般来说,这些函数首先重命名一些列,使事情更容易处理。接下来,他们按照日期对数据帧进行排序,以确保事情按照预期的方式有序进行。之后,会创建一些新的计算列,以便以后参考。最后,拆分“exchange”列,为商品和市场创建两个新列。最后一步是必要的,以便以后在图表和其他位置提供一些标签。

就我个人而言,我总是觉得很难决定是应该将计算列添加到主数据框架中,还是等到以后再添加。我个人的原则是,如果我认为有可能不止一个地方需要它,我会全力以赴。

这个文件的其余部分由生成特定图表的函数组成,这些图表将在仪表板上使用。我不会详细讨论它们,但是如果有不清楚的地方,我鼓励任何人提问。

因为这是一个图表优先的过程,所以图表是在合并到仪表板框架之前定义的。简单地将它们创建为可调用的函数比采用其他方法更有意义。但是,和任何事情一样,应对这一挑战的方法不止一种。

要记住的关键是图表是由函数作为一个现成的对象返回的。这意味着您可以将其作为函数的输出、图形变量或作为布局对象的一部分内联调用。你的选择实际上取决于组织和使用。

业务逻辑

在这个应用程序中,business_logic.py 文件非常简单。总共 41 行,包括许多注释,它实际上只是提供了一个在应用程序启动或重新加载时运行某些功能的入口。

"""    
This files does a lot of the dataframe work and larger data functions. Mostly this is data retrieval, organization, and making sure everything is ready to be called by the main app via call backs.    
This is called by main.py and in turn calls support functions when needed
"""
import pandas as pd
import numpy as np
import plotly.io as pio
import support_functions as sf pd.options.plotting.backend = "plotly"
pio.templates.default = "plotly_dark" # Make sure we have data
# This will check to see if a file exists and if not gets one
#  This also checks the data freshness
sf.get_reports() # Get the data frames to work with
# DEACOT report
df_deacot = pd.read_csv("/tmp/deacot2021.txt", na_values="x")
df_deacot = sf.deacot_process(df_deacot) # Disambiguation report
df_da = pd.read_csv("/tmp/deacot_DA_2021.txt", na_values="x", low_memory=False)
df_da = sf.DA_process(df_da) ####################################################
# Generate the commodities list - use the DA listing
####################################################
da_list = df_da["Exchange"].unique()
da_list = np.sort(da_list) if __name__ == "__main__":    
  print("business logic should not be run like this")

总体布局如下:

  1. 将数据帧后端设置为 plotly。
  2. 将默认模板配置为深色主题。
  3. 使用函数获取报告
  4. 将 CSV 读入数据帧并适当处理
  5. 创建一个只包含交换列中唯一值的新数组

第 5 项用于创建商品的主列表,我们将使用它来驱动仪表板视图并相应地更新图表。

布局配置

layout_config.py 文件包含一些可以跨图表重用的样式数据。它的存在主要是为了简化布局和图表构建过程。

例如:

layout = go.Layout(    
  template="plotly_dark",    
  # plot_bgcolor="#FFFFFF",    
  hovermode="x",    
  hoverdistance=100,  # Distance to show hover label of data point    
  spikedistance=1000,  # Distance to show spike    
  xaxis=dict(        
    title="time",        
    linecolor="#BCCCDC",        
    showspikes=True,        
    spikesnap="cursor",        
    spikethickness=1,        
    spikedash="dot",        
    spikecolor="#999999",        
    spikemode="across",    
  ),    
  yaxis=dict(        
    title="price",        
    linecolor="#BCCCDC",        
    tickformat=".2%",        
    showspikes=True,        
    spikesnap="cursor",        
    spikethickness=1,        
    spikedash="dot",        
    spikecolor="#999999",        
    spikemode="across",    
  ),
)tool_config = {    
  "modeBarButtonsToAdd": [        
    "drawline",        
    "drawopenpath",        
    "drawclosedpath",        
    "drawcircle",        
    "drawrect",        
    "eraseshape",        
    "hoverclosest",        
    "hovercompare",    
  ],    
  "modeBarButtonsToRemove": [        
    "zoom2d",        
    "pan2d",        
    "select2d",        
    "lasso2d",        
    "zoomIn2d",        
    "zoomOut2d",        
    "autoScale2d",    
  ],    
  "showTips": False,    
  "displaylogo": False,
}

在这两种情况下,放置这些类型的配置允许对图表呈现和工具配置进行集中管理。

主仪表板

这是你们期待已久的时刻,构建真正的仪表板代码。

我知道当我第一次开始使用 Dash 时,主文件似乎令人生畏。发生了很多事。我也没有明确的组织流程。但是,我让它以一种对我有意义的方式工作。这就是我将带领你经历的。

我倾向于按以下方式整理我的主要文件:

  1. 样式修饰符。
  2. 内容结构。通常,这些是保存行数据的容器。我发现以反映实际布局的方式构造我的文件是最容易的。我从顶部开始向下移动。
  3. 页面布局聚合。内容结构被放入页面布局中,并被组织到一个引用中。
  4. 应用参数。这是实际应用程序行为以及应用程序标题、样式表和主题等全局项目所在的地方。
  5. 复试。这些是允许窗口小部件运行的动态代码,并真正使仪表板起作用。
  6. 服务器运行。这是实际启动服务器和运行仪表板的最后一行代码。

让我们浏览其中的一些,让您感受一下所有部分是如何组合在一起的。我要把这些有点乱,但没什么大不了的。

首先,让我们看看应用程序参数和服务器一起运行。这些构成了仪表板的骨架,并告知了布局的其他一些方面。

#####################################################
# Application parameters
#####################################################
app = dash.Dash(    
  __name__,    
  suppress_callback_exceptions=True,    
  external_stylesheets=[dbc.themes.CYBORG],
)
app.title = "CFTC Data Analysis"
app.layout = html.Div(    
  [
    dcc.Location(
      id="url", 
      refresh=False), 
    html.Div(id="page-content")
  ]) # Multi-page selector callback - left in for future use
@app.callback(
  Output("page-content", "children"), 
  Input("url", "pathname")
)
def display_page(pathname):        
  # if pathname == "/market-sentiment":    
  #     return volumes    
  # else:    
  return main_page###################################################
# Server Run
###################################################
if __name__ == "__main__":    
  app.run_server(
    debug=True, 
    host="0.0.0.0", 
    port=8050, 
    dev_tools_hot_reload=True
  )

在大多数情况下,应用程序参数应该是不言自明的。需要注意的关键项目是“外部样式表”。这正是我们所说的——外部样式表。在这个例子中,我使用了一个名为 CYBORG 的引导主题,这是一个黑暗主题。

这里,我们还有 app.title 参数,用于应用程序设置标题。app.layout 参数设置了一个过程,通过该过程,名为“page-content”的 id 通过回调函数“display_page”的输出进行传递。这不是绝对必要的,但它允许读取 URL 路径并基于该路径提供不同的内容。它用于多页应用程序。我把它留在里面作为参考。

最后,我们有服务器运行部分。我们可以在这里设置监听 ip 地址和端口。因为我在本地服务器上运行我的仪表板,以便在我所有的计算机上使用,所以我被配置为在端口 8050 上公开侦听。我还将 debug 设置为 True。这减少了我的日志文件中的喋喋不休。如果 debug 设置为 true,应用程序还会在检测到任何文件中的更改时进行热重新加载,这对于开发来说非常有用。

复试

许多文章、视频和其他材料都是围绕着回调而产生的。这是一个复杂的问题,我只谈一点皮毛。然而,这个主题至少可以让你了解它们是如何排列的。

在这个仪表板中,有一个主下拉选择器,用于更新页面上的所有图表。稍后我将介绍这个下拉菜单,但是现在,重要的是要理解这个下拉菜单提供了一个 id 为“future”的输入

记住这一点,让我们分解 main.py 文件中的第一个回调。

# Sentiment charts
@app.callback(    
  dash.dependencies.Output("deacot_sent", "figure"),    
  [dash.dependencies.Input("future", "value")],
)
def deacot_sentiment(future1):    
  df1 = bl.df_deacot[bl.df_deacot["Exchange"] == future1]    
  df1.set_index("Date", inplace=True)       arr = df1["commodity"].unique()    
  asset = arr[0]     

  fig = sf.make_sentiment_chart(df1, asset)    
  return fig

在不多的代码中,发生了很多事情。这主要是因为我们前面提到的组织。

回调从 decorator app.callback 开始,这里我们有一行用于输出,一行用于输入。两者都接受它们引用的元素的 id 和被传递的数据类型的参数。

在这种情况下,输入从“future”id 中收集一个值,我在本节开始时提到过。输出将图形数据发送到“deacot _ sent”。(是的,我知道我应该用连字符来标识……)

有了发送的输入和输出路由,我们必须做些什么来将该值转换成一个数字。这就是函数“deacot _ 情操”的用武之地。它接受输入参数,并简单地将其命名为 future1。

该函数首先过滤在 business_logic 中定义的名为 df _ deacot 的数据帧,并匹配从 future1 传入的值。我们只剩下一个整合的数据框架(df1 ),其中包含交换列与下拉列表中的选择相匹配的数据。

下一行将日期列设置为索引。接下来,我们获取商品列中的唯一值,并将它们放入一个数组中。由于报告的过滤方式,我们应该只有一个值。但是,因为有时事情不会按计划进行,所以我们将第一个数组元素放入名为“asset”的变量中。

然后,我们的 dataframe (df1)和变量“asset”被输入到位于 support_functions 文件中的图表函数 SF . make _ invision _ chart 中。函数的输出被设置为变量“fig”,它是图表的代码。

最后,fig 通过回调的输出以图形的形式返回。它正前往 id“deacot _ sent”。

需要注意的是回调可以有多个输入和输出。输出可以链接到其他回调。

然而,让我们跟随这个数字的路径…

内容

我们刚刚看到了输入如何触发回调并将数字返回到 id。如果我们跳回内容,我们可以在构建用于显示的元素时看到这一点。

正如我前面提到的,我喜欢按照行设置的自上而下的布局来排列我的主文件。这有助于我想象网格,并在构建时将它保存在我的脑海中。在这种情况下,我们为两个情绪图表定义了一行:

# Container for sentiment charts
sentiment_direction = dbc.Row(    
  [        
    dbc.Col(            
      dcc.Graph(                
        id="deacot_sent",                
        style={"height": "70vh"},                
        config=lc.tool_config,            
      ),            
      md=6,        
    ),        
    dbc.Col(            
      dcc.Graph(                
        id="da_sent",                
        style={"height": "70vh"},                
        config=lc.tool_config,            
      ),            
      md=6,        
    ),    
  ]
)

上面的代码设置了一个包含两列的行,每列包含一个不同的图表。第一列的 id 为“deacot _ sent”,这是回调输出的目标 id。

因为我们持有一个图表,所以我们使用 dash 核心组件(dcc)库提供的图形容器。在这里,我们设置 id 和许多其他参数。我特意将高度设置为样式覆盖。我还添加了一个“config”元素,它被设置为上面突出显示的 layout_config.py 文件中的 tool_config 值。

因为元素是从回调的输出填充的,所以不需要显式数据源。如果我们以不同的方式生成图表,我们可能会使用“figure”参数来保存数据。

最后,在 dbc 中。Col 函数,我们看到了“md=6”。这是一个使用引导框架的格式值。其中,每行被分成 12 个单元。设置“md=6”告诉框架,我希望我的列填充总数的 6 或一半。

除了不同的 id 值之外,第二列是相同的。该列将是同一行上另一个图表的输出,占据了另一半空间。

布局

我们从输入到输出之旅的最后一步是将行实际链接到将通过应用程序显示的页面布局。这很简单:

####################################################
# Layout Creation Section
####################################################
main_page = html.Div(    
  [        
    html.Hr(),        
    html.H5(
      "Futures Market Comparison and Analysis", 
      style=TEXT_STYLE
    ),        
    html.Hr(),        
    future_select,        
    html.Hr(),        
    info_bar,        
    html.Hr(),        
    sentiment_direction,        
    html.Hr(),        
    da_postiions,        
    html.Hr(),        
    da_pos_snap,        
    html.Hr(),        
    da_diffs,        
    html.Hr(),        
    references,    
  ],    
  style=CONTENT_STYLE,
)

如果您还记得关于应用程序参数的部分,您会注意到应用程序的页面内容 id。没关系——再读一遍那个句子,有很多是连在一起的。

main_page 变量只是 html.div 的另一个容器。div 由对以前构造的其他元素的引用组成。本质上,我们只是一点一点地构建,以达到最终的结果。

这里是页面集合的地方。在上面的代码中,我从空格、要显示的标题、更多空格、包含选择下拉列表的行、空格、信息栏、更多空格开始,然后是我们的第一行图表。这就是我上面展示的那一行。

这是我们构建仪表板所需的一切。实际上,这比我们需要的要多得多,因为这个设计有点大,而且分散在几个文件中。然而,你现在也许能明白为什么为组织分解各种元素对保持你的理智是有效的。有很多块和元素。将它们组织成逻辑单元对于创建有用且可维护的应用程序大有帮助。

最后一件事

在我结束之前,我真的想为你整理一下。

下拉菜单驱动仪表板。它提供了原始数据点,并允许基于特定商品评估整套报告。它是页面标题下的第一行,非常重要。

# Create drop-down selector
future_select = dbc.Row(    
  [        
    dbc.Col(            
      [                
        html.Div(                    
          [                        
            dcc.Dropdown(                            
              id="future",                            
              options=[
                {"label": i, "value": i} for i in bl.da_list],                            
              value="SILVER - COMMODITY EXCHANGE INC.",                        
            ),                    
          ],                    
          className="dash-bootstrap",                
        ),            
      ],            
      md=6,        
    )    
  ]
)

和以前一样,这是一个非常普通的结构。我们从行开始,然后添加一列。列中有一个 Div,包含 id 为“future”的下拉列表。记住“未来”是回调的输入。

在下拉列表中,我们设置选项,这只是一个基于我们在 business_logic 文件中定义的 bl.da_list 数组的标签和值的扩展列表。这是从 DA 报告数据框架中提取的所有商品的唯一列表。实际上,DA 报告数据框架比 DEACOT 报告包含的内容少,因此使用 DA 作为主列表只是最小的公分母。

我们最后设置了一个默认值,就是在启动时加载一些东西。在这种情况下,我使用银,因为这是我经常看的商品。

同样重要的是,尤其是在使用深色主题时,设置 classname 值。这允许应用适当的样式,以便下拉菜单在深色背景上看起来很合适。这会省去你很多审美上的头疼。

沿着样式线,虽然我们只有一列,但它被设置为只延伸到整个行的一半。这是一个设计上的选择。你可能不同意。

包扎

这要涵盖的内容太多了。Dash 不是一个简单的平台,因为你可以用它完成很多事情。它的能力令人难以置信,一旦你习惯了它的细微差别,事情就会变得更有意义,你可以很快地构建。

正如我在开始时提到的,从我的存储库中抓取代码并浏览它。虽然这只是一个大概的介绍,但是实际的代码是通过文档逐步实现的。更重要的是,这是一个你可以自己运行和探索的功能系统。

如果您确实提取了代码,请随意使用它。做一些很酷的东西,或者只是解剖它,尽你所能去学习。如果你真的想用我写的东西,就告诉我一声。否则,这就是我给这个世界的礼物。

如果有关于清晰性的问题或与代码相关的问题,请随时直接联系我或留下您的评论。我鼓励提供反馈和建议,让事情变得更好。

为 Web3 平台 Mirror.xyz 的用户创建特定于社区的信誉分数

原文:https://towardsdatascience.com/creating-a-community-specific-reputation-score-for-users-of-web3-platform-mirror-xyz-14d494a25ea8?source=collection_archive---------28-----------------------

思想和理论

使用图形数据科学计算 Twitter、治理和以太坊交易中镜像用户交互的信誉分数(中间中心性)

本帖首次发表于ath . mirror . XYZ,请务必订阅并关注我的Twitter以获取我的最新加密和数据科学内容。后来,这种方法被用于第一个$WRITE 令牌空投,你可以 在这里 阅读。

在我之前关于数字身份的文章中,我提到过“这些图碎片的标记化可以有多种形式,并且很可能被证明标记所覆盖。”我认为,分片图身份方法需要提出一个特定于社区的声誉得分,以衡量某个人在扩展特定网络方面的影响力。虽然一些信誉分数可能更多地是根据必须完成 X 或 Y 动作来设置的,但是该分数以更灵活的方式捕获其他用户上下文中的用户信誉— 表现得像一个信号而不是徽章

通常在 Web2 中,用户会得到一种算法的“奖励”,这种算法会根据他们给平台带来的参与度和关注度来突出显示他们。因此,他们的声誉得分仅仅是他们拥有的喜欢或追随者的数量——不管这些虚荣指标来自谁。在 Web3 中,我们通常会奖励代表协议或产品价值的代币。这些代币还以投票和其他特权的形式承载着很大的权力。因此,随着时间的推移,不仅表明影响力,还表明用户与社区其他成员的支持度或联盟度的分数将变得越来越重要。

在这篇文章中,我们将重点关注为镜像用户(投票者、作者、贡献者)创建一个信誉分数,这个分数是基于每个用户在以太坊、Twitter 和镜像数据的基于交互的社交图上的位置。我选择镜子有三个原因:

  1. 我已经非常熟悉他们的社区和产品
  2. 他们在他们的平台(以太坊<> Twitter)上有可验证的身份整合,允许我将社交图分层在一起。
  3. 他们的产品和治理非常注重用户对用户的交互,这是以太坊上的大多数产品目前不具备的(我们主要与池或市场协议进行交互)。

社交图本身并不新鲜,但是有选择地将它们分层将会打开相当多的可用性和意义的新大门。这有两个主要原因:

  1. 启用新应用:我们可以使用该图表数据来创建依赖于上下文的特定于社区的信誉评分,该评分可应用于许多情况。
  2. 数据代表什么:建立在稀缺性基础上的代表性网络的创建创建了一个社交图,它代表了用户如何相互支持。

支持新应用:我们理解分层的方式会影响我们对数据的处理。在我看来,以太坊是一个基础层社交图,其他一切都建立在它的基础上。像 Mirror 和 Twitter 这样的平台是上下文,位于这个基础层之上,改变了我们如何看待用户在空间中的联系。

作者图片

我没有设计能力,但想象一下在 3D 中,每个盒子都是从不同角度穿过球体的一部分。

因为我只想分析 Mirror 的用户,所以我只取了可用以太坊和 Twitter 数据的一个子集。那些具有高的特定于社区的信誉分数的人可以获得更大的令牌空投,被委派财政管理中的角色(或更多选票),或者获得对新协议特征的优先访问。还有更多的类似 Mirror 的环境建立在 Web2 + Web3 平台之上,比如 NFT 社区(Cryptopunks,BAYC,Blitmaps)和游戏社区(Axie Infinity,Darkforest)。

随着 Dao 开始更多地合作,元宇宙变得更加互联,我们将看到更多的社区(和环境)重叠。我想,研究人们和社区如何在社交图的不同背景下互动可以产生混合社区声誉得分,这可以应用于相当多的不同情况。例如,这个分数可以用于多令牌或协作 NFT 空投,以及选择合作伙伴和项目的领导者,如 rabbithole 的探路者计划。

数据代表什么:收集和使用的数据种类也会影响社交图谱。使用来自$WRITE 投票、资金贡献(跨版本、拆分、众筹和拍卖)和 Twitter 提及的数据,我想代表三种稀缺(分别):信仰、资本和关注。

作者图片

是的,从技术上来说,这应该被视为一个自引用循环,但这可能会让人感到困惑

我相信,分析互动如何将不同的人联系到这三个方面会给我们一个代理,显示他们相互支持的程度。我也相信的支持网络给了我们一个在社交图中更准确的社区表现。这两个假设让我有信心使用一个叫做“中间性中心性”的概念作为声誉得分的原始值。

数据表示和上下文的选择是社交图最终形式的关键。如果我只是想代理贡献的意愿,那么我可能会创建一个完全基于不同种类的产品/类别的创建者的创建节点模式,而不是一个纯用户到用户的图。这可能会彻底改变社交图谱的形状。

使用图数据科学创建社区声誉得分:中间中心性

让我们尝试定位并量化种族参与者、作家和贡献者的社交图的强连接点。我选择使用一个叫做“中间中心性”的概念来表示每个节点的得分。使用为所有节点计算所有节点之间的最短路径的算法来计算中间中心性。

对于 Mirror 来说,谁投票给谁的基本社交图是这样的:

作者图片

金点是赢家,紫点仍在比赛中竞争。上面有 2130 个节点,其中 2041 个节点至少投了一票。

作者图片

这是细胞核的放大图,使用莱顿社区检测方法对每个社区进行了颜色编码。从这个和上面的图,我们可以看到有相当多的社区,但几乎所有的赢家都坐在中间。

然而,这还没有一个种族外的社会背景。让我们将以太坊交易级数据分层——这仅限于参与者之间的镜像相关交易,如发送分割、众筹融资以及购买版本或保留拍卖。

作者图片

粉红色表示以太坊 tx,请注意,有一些节点只是以太坊地址,没有相关的 Twitter 数据,因为它们没有在比赛中注册。

现在,我们还将添加 Twitter 数据,这将基于在最近 2000 条推文中提到另一个参与者的来链接节点。

作者图片

蓝色现在代表节点间的 Twitter 提及

以更清晰的方式显示交互(边缘),社交图中的交互组合如下所示:

作者图片

计算在每个方面已经相互交互的用户的数量。

现在回到最初的观点,预期是大型集群之间的一些节点将获得比其他节点更高的权重,因为它们已经连接了跨越大多数其他节点的路径。

作者图片

前 300 名中间用户以红色突出显示,我们可以看到他们开始从图表的中心向外扩散。

这被称为“中间性”,我认为这是一个非常重要的因素,当试图积极发展一个社区。这里的基本思想是,一个人的“中间性”因素越高,他们就越有可能建立联系和分支,从而建立一个更加多样化的社区。已经有一些研究论文强调了具有高介数的节点对社区的扩散以及建立网络弹性的有益影响。

你们中的一些人可能会奇怪,为什么我选择了中间中心性,而不是亲密度或程度中心性。后两个指标强调的是纯粹的影响力,我认为一个社区中的声誉不应该仅仅基于那些已经拥有这种影响力的人。Neo4j 的图算法教科书很好地解释了中间性背后的概念:

有时系统中最重要的齿轮并不是权力最大或地位最高的。有时是中间人连接着各个团体,或者是对资源或信息流动拥有最大控制权的经纪人。中间中心性是一种检测图中节点对信息流或资源的影响程度的方法。它通常用于查找作为从图的一部分到另一部分的桥梁的节点。

很多 Web2 都是关于集中影响力和回音室的,我认为 Web3 应该尽可能地支持和激励创造桥梁。

任何想看分数的人都可以在这里查看表格。请注意,这些值没有基于数据/边缘类型进行加权,因此一些用户可能由于 Twitter 交互而不是镜像/以太坊交互而具有更高的介数。

为什么这种方法对分数很重要?

我们已经讨论了这个分数的一些应用,但我使用的解决方案可能仍然显得不必要的复杂或过度工程化。我认为需要这种方法来提供可组合性,同时也以一种更难游戏的方式来衡量声誉。

可组合性:如前所述,这个图是逐层构建的。数据元素都可以公开收集,模型遵循一种搜索算法,对选择的任何节点或边(用户或交互)都是灵活的,一旦构建了管道,就可以重复使用或分支进行任何调整。希望在未来,所有可用的数据组件都在一个用户界面中,这种模式变成了拖放。从那里我想象你可以输出分数或者直接连接到类似 disperse.app 或者银河落点的东西。

持久性:很多分数和度量的问题在于,一旦它们被公开使用过一次,那么人们就可以开始琢磨如何博弈系统了。对于任何仅仅基于user <> protocol互动的事情来说,这一点尤其正确。创建一个依赖于user <> user <> user的模型更难,因为当前社区中的用户不一定会与坏人互动。行动也是复合的,所以只有一种互动(或一种类型的互动)不足以获得更高的分数。即使他们找到了一些游戏的方法,那么恭喜你现在有了另一个对社区有贡献的积极参与者。

这两个要素允许一个整体上更强大的信誉评分机制,我相信这证明了我们为实现这一目标所付出的努力是值得的。

总之:

我想继续重复这项研究,并可能对协议和社区的具体用例使用这种评分(如果感兴趣,请联系)。如果你已经做到了这一步,并希望以想法或技术专长为这一分析做出贡献,我邀请你加入 ImagDAO 进一步研究社交图数据和分散身份。

接下来的步骤包括更多的数据收集,建立一个 Neo4j 仪表板供其他人使用,当然还包括应用更多的数据科学算法。随着我们试图预测社交图将如何增长或试图瞄准特定的子社区,机器学习和社区检测可能会在未来发挥更大的作用。

我之前提到过,这种分析之所以可能,是因为 Mirror 的平台(以太坊<> Twitter)对身份的可验证巩固。这项工作的继续也很大程度上依赖于身份巩固 API,所以任何在这方面工作的人也请与我联系(看看你的陶瓷和 Gitcoin👀).

一旦我重构并找出如何保护这个社交图中用户的隐私,这些数据和脚本可能会在以后公开共享。

特别感谢本·谢克特在评论这篇文章时给予的所有帮助和想法

创建自定义的 R 包

原文:https://towardsdatascience.com/creating-a-custom-r-package-9a2e303d3332?source=collection_archive---------12-----------------------

为所有用户定义的函数创建一个中心位置。

作者图片

我不知道你怎么想,但是我发现 R 用来排序数据帧的方法非常不直观。每当我想对一个数据帧进行排序时,我都不得不绞尽脑汁,通常是通过在网上查找别人是如何做到的,然后复制并修改他们的代码。最后,我决定创建一个易于使用的函数,它可以为我排序数据帧。这是我想到的函数的最新版本:

sortby <- function(df, col, desc = FALSE) { #### df is the dataframe to be sorted
    #### col is the variable by which it should be sorted
    #### desc indicates whether the sort order should be descending
    #### str2expression() allows us to dynamically create a df$col
    ####     variable which gets evaluated by eval()
    df[order(
            eval(
                str2expression(paste0("df$", col))
             ), 
            decreasing = desc
        ),]
}

我当时的问题是,当我想使用这个功能时,如何找到它。答案是创建我自己的包。现在,有很多关于如何创建 R 包的教程,但是它们都缺少一些东西。有些是不完整的或分成多页。有些令人困惑。有些已经过时了。本文的目的是从头到尾详细介绍我结合许多教程得出的过程。

首先,我应该提到我在所有的 R 编程中都使用 RStudio。我的一个要求是,它必须在那个环境中是可行的。虽然没有任何教程实际上排除了 RStudio 的使用,但许多教程完全忽略了它。

在 R 中创建可用包的过程有几个部分:

  • 编写要包含在包中的函数。
  • 为包中的功能创建文档。
  • 构建包。
  • (可选,不在此讨论)发布包。

我的 sortby()函数已经涵盖了第一步。我将这个函数存储在一个名为 sortby.R 的脚本中。

在我们继续之前,我们需要做一些设置。要在 Windows 中创建 R 包,需要安装 RTools 4.0。这是作为一个普通的 Windows 程序安装的,而不是作为 r 中的一个包。你可以在https://cran.r-project.org/bin/windows/Rtools/找到安装程序。我应该说,我在尝试让 RTools 工作时遇到了问题。安装进行得很顺利,但是安装出错了。当我创建。Renviron 文件编辑路径,我无法再安装软件包。我尝试了一些事情,包括重置窗口。经过大量的研究,我发现有人提到在试图安装包之前以管理员身份运行 R。这似乎解决了所有问题,我不再需要以管理员身份运行了。

一旦 RTools 设置好了,您就可以着手创建这个包了。在 RStudio 中,选择文件>新建项目>新建目录> R 包。在弹出的对话框中,给包起一个名字,并输入你希望包驻留的目录。如果您已经像我一样创建了 R 脚本,那么您可以将它添加到“基于源文件创建包:”下的框中。

作者截图

然后点击

此时,您应该在某处看到一个“Build”选项卡。我把它放在左下方我的“历史”标签旁边。(我相信默认是在右上角窗口。)选择“Build”选项卡,然后单击“Install and Restart”来安装您的软件包。一旦你这样做了,这个包应该出现在你的“包”标签中,如下所示。

作者截图

注意,包的描述仍然写着“包做什么(标题格)”。我们稍后会解决这个问题。接下来,查看“文件”选项卡。您将看到 RStudio 为您的项目创建的一系列文件和目录。脚本文件将位于“R”目录中,而帮助文件将位于“man”目录中。

作者截图

要解决上述描述问题,请打开描述文件。这个必需的文件存储关于包的元数据。

作者截图,显示默认描述文件

现在,让我们只改变显而易见的东西。如果你的包有任何依赖项(比如 dplyr 等等。),它应该包含在这个文件中,但不是默认设置的一部分。

作者截图

我已经编辑了标题、作者和描述行,并删除了维护行。请注意,标题行变成了右下方窗口中软件包列表中的描述。

帮助文件

创建帮助文件最简单的方法是使用 roxygen2 包。

install.packages("roxygen2")
library(roxygen2)

现在,我们转到 R 脚本,在开头添加一些 roxygen 注释。每个 oxygen 注释行都以# '开头。您应该添加几个项目:

#' @title 
#' @description
#' @param
#' @return
#' @example
#' @examples
  • 标题—用于向帮助页面添加标题(使用标题大小写)
  • 描述—用于添加简短描述
  • Param 为函数中的每个参数添加其中一行
  • return——函数会给你什么
  • 示例-添加一行或多行示例。如果你要添加一行以上的例子,用复数。在完成之前仔细检查这些例子,确保在你没注意的时候没有错误。

添加完 roxygen 注释后,运行以下命令:

roxygenize()

(和往常一样,R 允许命令的美式英语或英式英语版本,所以 roxygenise()也能很好地工作。)

此命令创建。man 文件夹中的 Rd 文件。的。RD 文件是用来创建实际的帮助文件的。我最终的 R 脚本和生成的帮助文件如下所示。

作者截图

结论

这就是创建 R 包的基础。您可以做更多的微调,尤其是如果您想要发布您的包。想了解更多关于软件包创建的信息,请在 https://r-pkgs.org/查看哈德利·威克姆的书 R 软件包

创建数据驱动的零售扩张框架

原文:https://towardsdatascience.com/creating-a-data-driven-retail-expansion-framework-2229fef33a17?source=collection_archive---------53-----------------------

现实世界中的 DS

所以你想开一家冰淇淋店…

你开了一家公司,它已经成长起来了。你在你认为合适的地方又开了一两个分店;也许你是星巴克,已经开了上千家。零售企业家或企业面临的最重要的问题之一是在哪里开设下一个位置。一些较大的企业有位置侦察兵,他们的唯一职责是发展业务;许多人不知道。

我之前写的一篇关于预测星巴克未来地点的文章促使一位正在经历这一挑战的企业家伸出援手——他们应该在大匹兹堡地区的哪里开设他们优质冰淇淋产品的下一个地点?他们如何利用数据来提高成功选址的几率?

点击此处 查看将在本文其余部分呈现的仪表盘。

想象一下,你是一个企业家,已经为你的优质冰淇淋品牌开了几家成功的分店。在选项的世界里,哪些变量对你来说是重要的?在与他们谈论这个问题后,我想到了几件事:

  • 人口:当地居民和游客的步行交通至关重要。在该地区服务的人越多,你的潜在客户就越多。此外,一个有价值的区别是由家庭组成的人口,因为他们的购买集体比个人更有价值。
  • 餐厅密度:引发去冰淇淋店的一个重要时间是晚饭后。人们已经承诺外出,他们已经付了饭钱,冰淇淋是结束一夜外出的一种令人欣慰的方式。
  • 位置,位置,位置:如果你离主街区只有一个街区,人流量就会减少。商店需要能见度高,方便,并且在一个步行区域。
  • 竞争对手:这个区域已经挤满竞争对手了吗?如果有人抢在你前面,而且它无法支持多项(或更多)业务,那么其他基本面看起来有多强也没用。

我们如何利用这些变量和更多数据来帮助解决这个问题?

这个项目有三个关键步骤:收集、分析、交流:

  • 收集:收集关于人口、收入、餐馆密度、竞争对手和位置的相关数据。处理数据以匹配所需的格式。
  • 分析:使用汇总的数据对地点进行客观评分和优先排序。平衡数据与人工筛选,以减少对评分算法的过度依赖。
  • 沟通:建立一个自助式 Tableau 仪表盘和一个有效沟通结果的演示。

聚集

我们不会花太多时间来讨论实际的数据收集过程——如果您想了解更多信息,请随时联系我们——但它的要点是在邮政编码级别获取和汇总美国政府、地方政府和商业数据,以生成一个包含每个地方邮政编码及其相关指标的主文件。

分析

我们首先看一些数据是如何按邮政编码在整个地区分布的。人口集中在哪里?哪些邮政编码的餐厅密度最高?哪个邮政编码倾向于在冰淇淋上花费更多?

人口,餐馆密度和平均。按邮政编码分列的冰淇淋支出。深绿色表示较高的值。

上面的地图开始让我们了解我们可能面临的权衡。总人口(最左边的地图)主要集中在市中心以外的 5-6 个邮政编码区。然而,市中心有最大的餐馆集群和餐馆密度(中间的地图),而在市中心外,平均冰淇淋消费趋于相当一致,但更高。我们优先考虑哪个?我们应该如何衡量每个变量的重要性?

这就是企业主的经验发挥作用的地方。能够认识到自己的局限性是很重要的。我擅长的一件事是收集、分析和展示数据。我做得不好的一件事是对每一个主题都有专业知识。

为了弥补这一点,我用自助输入构建了一个评分算法。你认为餐厅密度和总人口最重要吗?通过在框中输入较高的分数,为他们分配最大的权重。你想要更高的行走分数还是家庭的存在(K-12 注册)?增加这些分数,减少其他分数。可切换的变量有:

  • 步行评分:小区步行可达吗?这是一个可能会导致高客流量的地区吗?
  • 餐厅密度:附近有多少家餐厅?它是吸引潜在顾客的活动中心吗?
  • 竞争存在:是否有人已经“垄断”了这个位置?还有空间开更多商店吗?
  • 总人口:有足够多的人给一个大的潜在客户群吗?
  • K-12 入学:家庭与个人的代表——家庭人口多吗?

在左侧输入您的分数后,地图和表格会更新。每个邮政编码都有 0-1 分(0 分最差;1 最好)。

假设 100 分分配给我们最重要的变量。深绿色表示邮政编码得分较高。

我们现在已经定义了我们的重要变量,并有一种方法来优先考虑哪些邮政编码具有最有吸引力的人口统计信息。尽管该企业目前的大部分位置都在市中心核心区,但我们可以看到,有几个排名较高的邮政编码延伸到了郊区,我们可以根据这一初始优先级进一步考虑。

位置映射是从较大区域缩小到特定建议的连续过程

现在,假设您已经决定采用得分最高的邮政编码—高于 15212。你如何处理这些信息?邮政编码可以很大和/或多种多样,因此需要有一种方法比邮政编码更具体。

对我来说,我有兴趣知道的是大多数餐馆在邮政编码的什么地方。我们最有可能成功地将自己定位在客流量最大的区域或其附近。

在仪表板中,当您点击一个邮政编码时,它下面的地图会自动更新该邮政编码下的所有餐馆位置。对于邮政编码 15212,结果如下所示。第一个图像表示被单击的邮政编码中的所有餐馆,第二个图像在表中有更多的细节。该表标识了该邮政编码中餐馆位置最多的街道,当鼠标悬停在该街道上时,餐馆位置会在地图上高亮显示。

邮政编码为 15212 的所有餐厅位置

该邮政编码中位置最多的街道;悬停时,该位置会在地图上高亮显示。

综上所述,该控制面板允许我们:

  1. 确定我们的重要变量在数据中的分布位置
  2. 使用我们的主题专业知识对邮政编码进行排名和优先排序,同时保持更改可变重要性权重的灵活性
  3. 选择我们想要查看的邮政编码,并查看该邮政编码中的“活动”在哪里
  4. 找到值得实地调查的具体街道

我们的建议可以足够精细和具体,以便采取行动,同时也有足够的灵活性来适应不断变化的时间或用户偏好。

推荐

最终,我选择为扩展选项创建一个三管齐下的框架:

  • 现状:找一个与当前位置有相似特征的位置,并且靠近市中心
  • 地理扩张:寻找一个与当前人口统计数据相似但不在市中心核心区域的位置
  • 投机取巧:用直觉平衡数据,找到一个可能排名不是最高,但代表一个有希望考虑的机会的位置

每种方法的优点和注意事项如下所示。

对于这些扩展选项中的每一个,Tableau 工具——与谷歌地图中的“实地”研究相结合——导致了以下三个推荐的位置。

我的建议是,短期的方法应该是保持现状,而中长期的地理扩张选项应该进一步探索。

我觉得现状选项几乎没有自相残杀的风险(目前所有的商店都在河的南面),具有最高的自然客流量潜力(靠近足球场和棒球场外加一个儿童博物馆),并且在当前的零售状况下具有最小的不确定性。

从中长期来看,我觉得地域扩张是最好的选择,因为它覆盖了高收入地区的全新人群。我还认为,谨慎的做法是等待地理扩张,看看“城市人口外流”是永久的还是暂时的人口流动。

替代考虑因素:竞争分析和 COVID 影响

我将简要介绍的另一种方法是,我们可以使用该工具进行竞争分析。如果我们对市区感兴趣,我们可以突出显示这些邮政编码,并过滤底部的地图,只显示竞争对手。我们可以看到在河的北面很少有冰淇淋店。从这里,我们可以决定这是否代表机会(有吸引力的选择,还没有竞争对手继续前进),或者是否有合理的理由(分区、商业房地产的定价,或其他可用数据之外的原因使其成为无吸引力的选择)。

使用仪表板进行竞争分析的示例

从 COVID 的角度来看,很明显,任何新的位置都代表着不确定性,可能在短期内不可行。资本支出较低的替代方案可以是通过零售合作伙伴进行分销,例如便利店和杂货店。

该公司目前有零售合作伙伴关系,其逻辑延伸是尝试与他们目前的合作伙伴一起成长,因为这比寻找和建立新的合作伙伴更容易。从他们的网站上,我们可以汇总当前合作伙伴的所有潜在位置,并将其绘制在地图上。

黄点代表所有潜在的合作伙伴。星星是当前位置。家庭数量越多(人口越多),地图阴影越暗,家庭数量越少,地图阴影越暗。

同样有意义的是,任何分销渠道的扩张都应该发生在远离当前零售点的地方(在那里有人已经可以很容易地获得产品),以最大限度地扩大客户范围。左边的地图突出显示了他们当前合作伙伴的所有位置(不管产品当前是否在那里;该信息当前不可访问)以及他们当前的店面位置。红框代表最适合分销扩张的商店“集群”。

这种方法的另一个好处是它是郊区扩张的试验场。市中心位置以南的方框代表当前店面和之前确定的地理扩张选项之间的便利中点。如果产品在这些商店销售良好,我们可以更有信心,该位置可能会取得长期成功。如果销售不理想,这是一个低成本的测试,我们可以重新考虑市场是否可以维持我们的产品零售足迹。

同样值得注意的是,上述分析是在没有访问内部数据的情况下完成的;所有信息都是从公开的第三方来源收集的。

不幸的是,这一过程和合作关系在 COVID 之前就已经开始了,因此,随着保持业务的需要突然成为一个更为紧迫的问题,这一过程和合作关系就变得不那么重要了。然而,总有一天,企业会找到自己的立足点,到那时,随着一波租赁承诺到期,将会有一个数据驱动的框架向前发展,企业可能会看到机会。

有兴趣谈论位置策略和分析吗?请随时在 LinkedIn 上与我联系,或者在 jordan@jordanbean.com 与我联系。

使用概念创建数据科学和机器学习组合

原文:https://towardsdatascience.com/creating-a-data-science-and-machine-learning-portfolio-with-notion-25888cf19356?source=collection_archive---------30-----------------------

传统简历的现代化

我一直将理念视为一种生产力和组织工具。有了观念,我计划我的媒体发布时间表,在研究论文上做笔记,设置任务提醒,安排我的日常事务。

但是,我从未想过将“概念”作为一个在线投资组合,直到我看到 YouTube 上展示用“概念”制作的投资组合的视频和文章。

大多数用概念制作的作品集的例子来自设计师和艺术家。我决定创建一个专注于机器学习学科的概念组合。

这篇文章详细介绍了我使用概念创建机器学习/数据科学投资组合的步骤和推理。它将为您提供一些内容和布局创意,您可以采用这些创意来设计您的投资组合,如果您目前正在寻找一个新的角色,这可能会很有帮助。

在本文的结尾,我包含了本文中展示的投资组合的概念模板的链接,以及创建一些图像资产的 Canva 链接。

标题+简介

Richmond Alake 投资组合标题部分的版本 1

这个作品集的介绍部分向访问者提供了我的专业背景、动机和特长。我已经写了两段文字,简要介绍了我在机器学习方面的专业知识,包括我所从事的具体技术。

在为你的作品集准备介绍性的文字时,你要给访问者提供有趣的信息,鼓励他们探索你作品集的其他方面。这有助于将此部分视为“关于我”的页面。

第一段概括了我 5 年多的职业生涯,而第二段重点介绍了我希望访问者关注的主要学科和专业知识。我还考虑用第一段来展示我职业生涯的技术方面,第二段着重于软技能,如沟通、互动和协作。请随意尝试最适合您的内容结构。

标题部分的左边包含了一张你的非常漂亮的照片。但严肃地说,这张照片为整个作品增添了人性化的元素。突然间,我不再是网上随便找的人了。现在我是一个有脸的普通人。

我还包含了外部资源的链接,这些资源提供了对我实现的代码、在线内容和社交媒体资料的访问。添加这些链接为访问者提供了展示我职业自我的其他途径。

为了结束这一部分,我提供了导航到产品组合中其他区域的链接。一些访问者可能对我做过的项目感兴趣,而其他人可能想查看我的工作经历。此外,通过提供一个导航菜单,我向访问者突出这个投资组合包含什么。

下面是写介绍性段落时可以考虑的一些有用的提示

  • 试着用吸引人的语气写作,并确保展示你最好的技能和品质。
  • 使用关键词,并且要具体。你的陈述不要模棱两可。尽可能包含数字,例如,你在一个领域工作的年数。
  • 请不要做得太长。两段话绰绰有余。

对一些人来说,标题部分的空间太大了,我不是设计专家,但是丰富多彩的导航链接让这个文件夹更有活力。但是对于那些喜欢简单视觉布局的人来说,下面的标题和介绍部分的结构可能更合适。

Richmond Alake 投资组合标题部分的版本 2

职业

Richmond Alake 的投资组合职业部分

你可能会认出这个投资组合中职业部分的布局。我特意采用了类似 LinkedIn 的工作经历部分的内容布局。对职业部分的熟悉将使访问者更容易浏览和理解所展示的内容。

职业部分包括我前几年承担的与机器学习相关的角色。值得注意的是,我没有包括任何我的网络开发工作经验和项目。这个投资组合集中在我职业生涯的机器学习部分。给求职者的一般建议是,尽可能多地放入工作经验,所以在你的文件夹中随意添加尽可能多的相关工作经验。

每个角色都遵循相同的布局:一个图像或标志;职位名称;公司名称;持续时间;位置、角色和职责。职责和技能是职业部分的关键信息。

技能部分强调了我在特定角色中使用的编程语言、工具、库和技术。为了美观,也为了吸引访问者的注意,我给每个技能交替使用背景色。

我提供的关于每个角色职责的信息很简短,但非常具体。我已经包括了技术信息,但是我在一些角色中添加了传达软技能的职责(沟通、互动、协作)。我甚至包括了 GitHub repos、工具和书籍的链接,为好奇的访问者提供更多的背景信息。

如果你想引起招聘人员和招聘经理的注意,就要特别注意职业部分的细节。一定要突出具体的技能,使用传递专业知识的关键词。

企业和项目

版本 1: Richmond Alake 的投资组合风险和项目部分

这部分是我可以灵活运用的地方💪。

我已经包括了我从事的业余爱好项目,我参与的风险投资等等。本节旨在介绍我目前持有的心态,即通过探索技术解决问题的方式来培养技能和专业知识。

本节传达的个人属性如下:

  • 创造力。虽然软件工程和机器学习是技术领域,但也有表达创造力的有趣方法。我见过的网站和手机应用程序都是艺术品。完美的设计表明,网页开发人员和设计师可以成为数字艺术家。
  • 企业家精神。在我的圈子里,私下交易几乎是一种常态;也许你也一样。2020 年至 2021 年间,我参与了几个项目,推出了几个应用,并与投资者进行了交谈。这是一个过山车般的旅程,但如果你还年轻,没有比现在更好的冒险时机了。
  • 好奇心。如何用技术解决这个问题?每当我在生活中遇到一个耗费太多时间或精力的过程时,我都会不断地问自己这个问题。我的大部分业余爱好项目试图简化和自动化我的生活。
  • 成长。机器学习的领域很广,我不断探索新的技术、库和技巧。拥有一个成长的心态将我从令人兴奋的 web 开发世界推向了人工智能世界。

每个包含的风险或项目都有一个外部链接,描述和我参与的细节。对于那些喜欢本节更直观的外观的人来说,下图描绘了一个更美观的结构。

当创建你的作品集时,不要不情愿包括你曾经做过的小项目。如果你写了一个删除文本中空格的脚本,在你的文件夹中展示它。招聘人员更感兴趣的是你拥有什么样的技能,而不是你的项目有多成功。

Richmond Alake 的投资组合风险和项目部分的第 2 版

媒体和内容

Richmond Alake 的媒体和内容组合

如果我想让你从这篇文章中学到什么,那就是:如果你想超越一般的职业轨迹,知名度和个人品牌是至关重要的。

去年,个人品牌在我的职业生涯和外部工作中变得更加普遍。我更加努力地将我的独特性融入到我的作品和我放在网上的内容中。

媒体和内容部分是向访问者展示我的在线身份的一个机会。我写的中型文章展示了我对机器学习概念的了解,我已经能够通过中型文章记录我在机器学习领域的学术和专业旅程。因此,访问者了解学习机器学习硕士是什么样的,以及我在职业生涯中从事哪些活动。

这一部分的内容是我采访著名数据科学 YouTuber 网站 Ken Jee 的视频。我还收录了一些我广受好评的媒体文章。如果你想创建一个作品集,那么花些时间在 LinkedIn、YouTube、Medium 等平台上创建内容。

学术界

里士满·阿拉克投资组合学术部

我的投资组合中的学术部分并不重要,但它确实是一个很好的补充。拥有学术资格在某种程度上证明了你的专业知识。至少,这表明你是一个聪明的人,可以长期致力于一项特定的事业。

随意收录在线机构和 MOOCs(海量在线公开课)颁发的证书。

使用概念的优势

为了使 idea 的优势更加具体,下面是作为投资组合制作者利用 idea 的一些好处。

  • 免费。我使用免费版的概念计划,用来创建我的时髦投资组合的功能也是免费的。
  • 省时省力。如果你使用像 SquareSpace 和 Wix 这样的网站建设工具,创建一个投资组合会花费大量的时间,至少需要几天。如果你是从零开始构建,甚至需要更长的时间。有了 concept,你不必担心网络语言或托管网站。
  • 易用性。观念使得向访问者展示你的作品集变得非常容易。只需点击一个按钮— 见下图

公开概念页面的步骤

  • 多种内容布局格式。概念提供了各种结构和格式来表示内容。表格、列表、切换、降价文本、代码等等都是概念上可用格式的例子。
  • PDF 和 HTML 是导出页面的几种格式。

导出概念页面的选项

结论

使用概念有更多的好处。您可以通过探索该工具和构建您的投资组合来发现这些优势。这里有一个 链接到我的作品集 。请随意使用我的模板并添加新的部分。

你必须欣赏这种观念提供的灵活性。与传统的简历相比,有更多的自由来展示你的项目和经历,既有创造性又令人兴奋。

在竞争激烈的就业市场中,独特性确实有助于脱颖而出。这就是为什么我恳求你创建一个作品集,公之于众,并在你的简历中添加一个作品集的链接。

感谢阅读。

概念组合

Canva 上的导航链接

要联系我或找到更多类似本文的内容,请执行以下操作:

  1. 订阅我的 邮箱列表 了解更多内容
  2. 跟着我上
  3. LinkedIn Twitter 上连接并联系我

创建数据科学产品组合

原文:https://towardsdatascience.com/creating-a-data-science-portfolio-bd485382f49?source=collection_archive---------3-----------------------

办公时间

建立投资组合的技巧和例子

找一份数据科学家的工作越来越难了。在数据科学被称为“21 世纪最性感的工作”之后,许多人都加入了这股潮流,开始在这个领域找工作。

现在,数据科学就业市场对刚从大学毕业的大三学生来说已经相当饱和了。空缺职位吸引了数百名初级数据科学家,有时甚至是高级数据科学家。

数据科学职位招聘中相互矛盾的要求让初级求职者日子不好过

问题是,你怎么做才能把自己从数百名申请者中脱颖而出?

虽然有很多方法可以做到这一点,比如额外的实习、课程、MOOCs 等。对我帮助很大的一件事就是创建一个投资组合。

构建数据科学组合有两个目标。首先,它可以让你向招聘经理展示你的技术专长。如果你是这个领域的新手,这尤其有用。第二,积极建立投资组合是一个很好的学习机会。你需要花时间构建算法,部署解决方案,并以有意义的方式交流结果。

这篇文章将告诉你我对这个问题的看法:

“创建可靠的数据科学产品组合需要什么?”

数据科学项目组合可以包含许多内容,但通常围绕您(数据科学专业人员)已经创建的内容。例如从头开始构建算法、研究新方法、进行有意义的分析等。

我的项目的几个例子。完整的概述可以在这里或者这里找到。背景由卢卡斯布拉塞克。

它还可以让你展示你在过去的工作经历中没有发展出来,但在个人项目中集中了的专业技能。

这也意味着作品集不是主要用来弥补工作经验差距的工具。它还能帮助你在这个领域更受欢迎的职位中获得优势。

在建立你的投资组合时,我相信一个人从专注于发展一个 T 形轮廓中获益匪浅:

t 型轮廓。图片由作者提供。

T 形轮廓代表了两件事。首先,单杠代表通才。数据科学家应该具备统计学、编程、部署、业务等方面的基础知识。第二,竖条代表一种专门的技能。这可以是对 NLP、计算机视觉、时间序列等的关注。

换句话说,尽管数据科学家可以专注于某个特定领域,但不应该忽略基础知识。在这两者之间找到平衡应该对你的职业生涯和个人发展都有帮助。

1。创建您的项目

投资组合的基础由许多项目组成。这些项目可以成就你的投资组合,也可以毁掉你的投资组合,因为它们是你工作的门面。

因此,这些项目应该被仔细选择,并且需要传达许多东西:分析的质量、沟通技巧、代码质量、业务相关性等等。

再进行一次泰坦尼克号分析不会让你与众不同。

在这里,我将详细介绍这些方面,并展示如果我要创建一个新的方面,我将如何在我的投资组合中处理它们。

这个想法

当创建一个项目时,我建议不要从一个数据集开始,而是从一个想法开始。没有目的的分析通常是没有意义的,应该尽可能避免。

尝试回答以下问题:

  • 我想解决什么问题?
  • 谁将从我的分析和/或产品中受益?
  • 有没有我可以改进的技术?

即使你自己想不出什么,也有很多资源可以帮助你开始:

  • 12 个数据科学项目创意
  • 例如,在 PyTorch 中复制以前仅在 Tensorflow 中提供的流行论文
  • 创建一个包来填补一定的空白,比如 AutoScraper 或 DrawData

但最重要的是:

选择你感兴趣的项目,否则它们会变得太繁琐

有时,我们不需要数据来创建与数据相关的项目。你可以开始构建算法,复制论文,或者创建一个包来填补特定的空白。

Autoscraper 是优雅而简单的包装的一个很好的例子,巧妙地填补了一个空白。由像素完美从平面图标制作的图标。

举个例子,在过去的几年里,我一直专注于开发像伯托皮、基伯特、 c-TF-IDF 和 VLAC 这样的算法。这些帮助我证明了我可以把分析带到下一个层次。

数据来源

尽管你可以在 Kaggle 上找到很多有趣的数据集,我还是建议你在数据集的选择上更有创意一点。例如,您可以分析来自当地政府的数据(荷兰、美国、法国等)。)、世卫组织数据,或者在大型孟德尔数据库中搜索数据。

换句话说,试着自己收集数据。在许多组织中,在获得一种清晰的格式之前,通常有相当多的困难需要克服。展示你可以自己找到并处理数据,这展示了你非凡的技能。

使用 BeautifulSoup 、 Scrapy 、 AutoScraper 或任何其他方法来抓取你的数据,肯定会给创意加分。它还表明您可以处理真实世界的数据,因为生成的数据通常是杂乱的。

储存库

在 Github 这样的公共场所分享你的作品。这是展示诸如版本控制、OOP、模型评估、文档等技能的好方法。

这些存储库应该有足够的文档,让不熟悉您的项目的人了解如何使用或解释它。试着清晰有效地交流项目是关于什么的,结果是什么,尤其是你的分析的含义。

尽管招聘经理不太可能会运行你的代码,但它很好地概述了你通常交付的工作质量。

提供清晰直观的自述文件大有帮助!伯托博的自述。图片由作者提供。

以下是一些好的自述文件页面示例:

  • 丛生,在 calmcode.io 上的视频系列的一部分。
  • 高质量自述文件页面的精彩概述

注意:如果你对质量文档的例子感兴趣,我强烈建议你浏览一下https://github.com/koaning的项目。正确记录的技能被严重低估了。

部署

展示您的技能能够产生影响的最佳方式之一是部署您的代码。对拥有软件工程技能的数据科学家的需求似乎正在迅速增加。

有几种方法可以解决这个问题:

首先,您可以从已经创建的分析中创建一个应用程序。例如,如果您要创建一个关键词提取工具,那么您可以创建一个 Streamlit 应用程序来展示您的应用程序的可用性。

第二,通过 Pypi 或 Anaconda 提供你的 python 包。如果为了使用你的 python 包,你必须做的唯一一件事就是pip install my_package,那该有多好?这表明你了解生产前和生产过程。

展示软件工程技能是让你脱颖而出的关键

认识到数据科学不仅仅是创建模型,这一点很重要。用户打算怎么用?需要如何部署?应该是什么样子?等等。

2。教程&博客

除了项目,你可以开始在你的文件夹中添加教程和博客文章。这些对于证明你能够以不熟悉内容的人可以理解的方式解释技术问题是至关重要的。

每当您创建一个分析、模型、包或任何感兴趣的东西时,您都可以将其打包在一篇博客文章中,使您的工作更加公开。

如果你能把某样东西教给别人,你就真正理解了它

类似地,写教程是帮助你理解材料的一个神奇的方法。每当我学习一个新的话题时,我会确保我能向别人解释它。

举个例子,我在下面写的这篇文章展示了用简单的方式呈现复杂的材料是多么重要:

</9-distance-measures-in-data-science-918109d069fa>

磨练你的写作技巧会帮助你成为一个更好的沟通者。你将慢慢开始对你的利益相关者的需求和愿望有一种直觉,这是一种令人惊奇的技能。

因为你很可能是在媒体上阅读这篇文章,所以我建议从这里开始也就不足为奇了。Medium,具体来说是 TowardsDataScience 出版物,是一个张贴你的技术教程和人工智能领域想法的好地方。

我在 TowardsDataScience 的工作并没有被忽视,而且在过去几年我参加的几乎所有面试中都有很大帮助。

https://medium.com/@maartengrootendorst

似乎不仅仅是我从写作中受益。梅根·迪布尔解释了在媒体上写作是如何让她的在数据分析部门找到工作的。同样,Dario rade ci写了作为数据科学家拥有博客的好处。作为最后一个例子,大卫·罗宾逊解释了开博客的好处。

还有几个地方可以让你开始写作:

  • 黑客月
  • 商务化人际关系网
  • Reddit—r/机器学习或r/数据科学
  • 个人网站— 以我的为例

3.社交媒体存在

你可能已经猜到了,如今你的社交媒体越来越重要。

公开你的工作有助于社区了解你的技能。对于招聘经理来说,除非他们能亲眼看到,否则很难真正知道你的能力。

虽然有很多方法可以达到这个目的,但是我相信选择你喜欢的事情是最有效的。话虽如此,下面是一些有趣的社区添加到您的投资组合。

卡格尔

竞争让 Kaggle 变得伟大。它们是练习你的建模技巧的极好方法。赢得比赛并展示你能深入预测建模是对你简历的一个很好的加分。

个人认为,用户提供的内核和笔记本才是让 Kaggle 保持伟大的原因。通过提供无价的 EDA 来帮助他人的机会是一项被严重低估的任务。

B 成为 Kaggle 的讨论专家被严重低估了

编写和发布内核有很大的价值。回答问题,开始讨论,开发内核,对训练你的沟通能力至关重要。

一个很好的例子是安德鲁·卢克扬科,他是笔记本和讨论大师,这是你在那个平台上能得到的最高级别。在一次采访中,他谈到了从事内核和讨论的挑战和好处。

Stackoverflow

在 Stackoverflow 上回答问题是一次很棒的经历。当涉及到交流复杂的主题时,你不仅会学到很多东西,而且它还为你提供了一个进一步发展技能的机会。

Jon Skeet 是 Stackoverflow 上最知名的用户之一,他解释了他如何在平台和上成名,以及为什么在编码时沟通是如此重要。这再次证明了沟通技巧不应该被忽视。

对这个 StackOverflow 问题的回答表明,良好的声誉有助于你在面试中“脱颖而出”。招聘经理不太可能询问你的简历,但拥有一份简历可能会给你带来竞争优势。

任何有助于证明你专业知识的东西都是有用的。

这表明你很好地理解了材料,尤其是如果你在平台上获得了声誉。假设您经常在 StackOverflow 上回答特定的基于 NLP 的问题。如果我是招聘委员会的一员,我肯定会认为这是一个优势。

Twitter 和 LinkedIn

每当你创建一个开源包或完成一项分析,通过 Twitter 或 LinkedIn 分享它。通过在这些平台上推广你的内容,你创造了一个有趣的机会与你所在领域的人合作和互动。

在这里,它主要是关于网络和建立你的个人“品牌”。为了给你一些提示,阿德蒙德·李讲述了为什么建立你的个人品牌很重要,以及它将如何影响你的职业生涯。

数据科学不仅仅是机器学习…统计、评估、理论、实验、模型服务、部署等等。

Philip Vollet 是一个很好的例子,他基于这些平台建立了一个庞大的追随者。他在 LinkedIn 上有 80,000 多名粉丝,作为开源倡导者,他为自己赢得了名声。我强烈建议跟随他学习更多有趣的开源项目。

因此,使用这些平台主要是为了让你的工作公开,并与他人联系。分享你的 Twitter 和 LinkedIn 账户不太可能给你带来梦想中的工作。

开源代码库

Github 是一个展示你的技能、与同行交流以及向导师学习的绝佳场所。和大多数事情一样,如果你有时间,我强烈建议要么创建一些你自己的库,要么贡献给开源。

当你创建自己的知识库时,它会迫使你考虑受众和用户。他们能理解我想要达到的目标吗?他们能轻松地使用代码库吗?这意味着在创建存储库时,您的自述文件应该是一个很大的焦点。

有许多文章介绍了如何建立你的 Github 组合(这里是,这里是,这里是),应该有足够的资源可以开始。

花大量时间在你的自述上,第一印象会持续很久!

积极参与开源社区不仅是一种很好的学习方式,而且真正表明你可以深入这项工作的某些技术方面。它展示了良好的编码实践、深厚的算法知识和协同工作的能力。

首先,搜索您经常使用的包,如 scikit-learn ,并搜索 CONTRIBUTING.md 文件。在这里,您通常会找到关于如何为软件包做贡献的详细说明。Scikit-learn 有一个优秀的教程,教你如何为这个包做出贡献。确保专注于一个简单的问题,并以此为基础。

这次对 Sebastian Raschka 的采访,他是 mlxtend 包和流行的“ Python 机器学习”书的作者,很好地概述了从事开源项目对你职业生涯的好处。

和大多数事情一样,雇主是否会看你的 Github 简介取决于你如何在简历中定位它。如果你把它放在简历上,很有可能有人会浏览你的 Github 简介。

4.投资组合是什么样的?

在创建了一组项目、包、博客文章和/或教程之后,是时候把它们放在一起了。完整的投资组合是什么样的?

幸运的是,这个问题没有单一的答案!这让你在开发的时候更有创造力。无论是通过个人网站还是 Github,都由你决定。

开源代码库

Github 是一个创建和分享你的作品集的优秀平台。有几种方法可以解决这个问题:

首先,花些时间优化你的个人资料的自述页。当有人打开你的 Github 档案时,他们首先看到的是 README 页面。这是一个讲述你自己、你做过的项目和你的经历的好方法。

我强烈建议从这篇优秀的投资组合阅读概述中寻找灵感。

我的 Github 作品集页面预览。图片由作者提供。

其次,您可以为您的投资组合创建一个链接到您的存储库的特定页面。这允许你创建一个你已经完成的所有项目的概览,而不需要在你的个人资料中浏览所有不相关的分支。

一个例子是 Andrey Lukynenko,他的 Github 投资组合通常被视为项目的清晰概述。

商务化人际关系网

不要忘记把你的项目和经验放到 LinkedIn 上。如今,它是你职业关系网的核心。试着建立你的关系网,这样每次你分享一个完成的项目时,它都会出现在正确的地方。

有很多方法可以提高你在 LinkedIn 上的个人资料,但它们都归结为一件事,沟通。用这样一种方式来交流你的技能,让读者明白,而不需要仔细阅读经验。

言简意赅,切中要害,注重结果。

你也可以把你的项目放在你的 LinkedIn 个人资料上。确保您关注技能、指标,但最重要的是关注影响。

你在数据科学上所做的一切都意味着会产生一些影响。确保阅读您正在处理的所有内容。

个人网站

创建个人网站对发展你的个人品牌大有帮助。您可以轻松管理想要发布的内容,并专注于对您来说重要的事情。

个人网站的伟大之处在于,你可以更容易地控制自己生活故事的叙述。关注你认为有趣的内容,比如项目、帖子,甚至是公开演讲。

一个著名的例子是大卫·罗宾逊的个人网站方差解释。他的开源网站建立在使用最小错误的基础上,这是一个 Jekyll 主题,用于轻松部署个人网站。

如果你不熟悉 Jekyll,我建议你从一个简单的 Github 页面站点开始。您只需要一个带有自述文件的存储库就可以开始了!

简历

在所有的项目陈述中,最受关注的是你的简历。这是一个所有事情都汇集在一起的地方,通常也是面试中判断的主要来源。

因此,在你的简历中充分展示你的项目并得到应有的关注是至关重要的。

简洁的简历格式示例。从背面的中检索。

我强烈推荐以下关于撰写简历的指南:

  • 数据科学简历综述系列,作者 Ken Jee
  • 如何构建引人注目的数据科学组合威廉·陈(Kaggle)
  • 乔纳森·贾维尔在 Snap Inc .的第一份工作后,他的简历一步一步地分解到了 T4
  • 蒂娜黄(Tina Huang)的一段视频,描述了她如何凭借这份简历在 FAANG 获得一份数据科学的入门工作。

通过关注技术、结果和影响,你可以传达你工作的重要性。

关注你工作的影响

背面是简历模板的一个很好的来源。不仅简历质量很好,而且这也是一个学习学术界常用的 LaTeX 的好机会。

没有一种格式是最有效的,因为招聘人员可能对应该在哪里提到什么有不同的看法。不过,似乎有一个共同点,那就是你会想把重点放在工具、技术和结果上

感谢您的阅读!

希望上面的提示能帮助你创建一个展示你专业知识的坚实的投资组合。你可能已经听我说过太多次了:

沟通是关键

如果你和我一样,对人工智能、数据科学或心理学充满热情,请随时在LinkedIn上添加我,或者在 Twitter 上关注我。

创建数据科学简历

原文:https://towardsdatascience.com/creating-a-data-science-resume-66685918c1ba?source=collection_archive---------24-----------------------

设计一份出色简历的指南——为你想要的工作接近招聘人员或招聘经理至关重要的第一步。

我们都知道为什么我们首先需要创建一份简历,对吗?一份简历反映了一个人的经历、资历,最重要的是,反映了一个人将如何适应一个角色。这篇博客文章将涵盖制作简历时应该记住的要点。

马库斯·温克勒在 Unsplash 上的照片

数据科学是一个充满各种机会的行业。每一次点击、每一次滑动、每一次搜索、每一次购物、每一条信息流都在创造数据。因此,不用说,这是一个需求不断上升的行业。一项研究显示,近年来,数据科学在印度市场的就业岗位增加了约 45%。

为了满足这一需求,各公司正在各地招聘 DS 职位。即使在校园实习期间,公司也会收到数百份申请两三个职位的简历。

现在,让我们来想想招聘人员,特威拉·桑兹。她每隔一天就会收到数百份求职者的简历。除了从这一大堆简历中挑选简历,她还有其他责任。她看一份简历的时间不会超过 30 秒。30 秒的时间足以吸引 Twyla 的注意力。

我们都知道性别差异在每个行业都很普遍,我们的科技世界也不例外。这种差距的存在可能有几个原因,但我将快速谈论两项研究。

使用主动语态。简历就是把你的经历和成就放在一个地方。它应该是关于你的,一个执行动作的明确主体。

基兰·斯奈德的一项研究表明,制作一份简历可能是一个促成因素。这项研究调查了 1100 份简历(50%是男性写的,另一半是女性写的)。斯奈德发现,不同性别的简历风格有着明显的差异。不同之处在于——长度、小节的组织、工作细节的写作方式、相关成就以及动词性动作词的使用,等等。

斯基德莫尔学院的社会心理学家 Corrine Moss-Racusin 进行了另一项关于 STEM 教师性别偏见的研究。该实验是给科学家两份相同的候选人简历进行评估(在资格和经验方面相似)。这两份简历的唯一区别是一份叫约翰,另一份叫詹妮弗。拉库辛和她的同事询问了一百多名 STEM 教授来评估这两份求职简历。拉库辛在斯坦福大学医学院展示了结果,结果令人吃惊。尽管有相似的资历和经历,教授们发现詹妮弗的简历明显不如约翰。所以,要消除人们头脑中的这些隐性偏见还有很长的路要走。但我们能做的就是努力设计一份更稳健的简历来缩小这些差距。

就像你的模型调整练习一样。

考虑到这一点,让我们深入以下要点,打造一份出色的简历。

1.模板

  • 选择一个具有视觉吸引力和专业性的模板。
  • 简历的长度不应该超过两页。还记得 Twyla 吗,我们的招聘人员。把她看简历需要的所有相关信息简洁地放在一页纸里会很方便。
  • 与你的字体风格和大小保持一致。在制作简历时,‘comic Sans MS’不是合适的字体样式。
  • 除非另有说明,否则以 PDF 格式保存简历。

2.个人信息

  • 写上你的名字,电话号码,电子邮件号码。
  • 最好将这一部分放在简历的顶部。
  • 没有必要把你的完整的物理地址或你父母的名字(是的,我见过有人这样做)等。
  • 您不希望输入类似“john123rocks@domain.com”的电子邮件地址。专业电子邮件 id 可以是“jane.doe@domain.com”或“jane.doeiitb@domain.com”。
  • 电话号码应处于工作状态。记住,Twyla 应该可以在打电话的时候找到你。
  • 放上你 LinkedIn 个人资料的链接。如果你有一个中型博客、GitHub 或 Kaggle 个人资料,也可以随意添加这些链接。不要犹豫展示你的作品,只要它是相关的。
  • 确保这些链接在 PDF 版本的简历中是可点击的。
  • 如果你决定在你的网站/LinkedIn/Github 上发布个人资料,不要忘记简洁地管理这些个人资料。添加关于你的项目,课程,额外工作等的描述。你认为哪一个对 Twyla 更有吸引力?只有标题的空简介还是写得很好的简介?

3.摘要

  • 在简历的开头添加一份执行摘要。
  • 不应超过 3-5 行。
  • 补充相关工作经验。
  • 补充几点关于你的技能,对 DS 的热情,以及你想在这家公司工作的原因。
  • 如果你即将开始你的数据科学之旅,写下你的收获,以及你认为自己有多适合这个职位。

让我们看两个写简明摘要的例子。一名大一新生可以写道:“初级数据科学家,拥有 IIM B 大学的分析和机器学习研究生学位,擅长统计模型、最大似然算法和编程。”。有解决不同现实问题的项目工作经验,尤其是在金融行业。另一个例子是,在零售领域有六年工作经验的数据科学家,专注于统计建模和机器学习技术。成就包括成功交付劳动力管理的多阶段预测系统。获得孟买 IIT 大学应用统计学硕士学位。

4.经验

  • 从你最近的经历开始。
  • 只列出相关经历。
  • 使用主动语态。简历就是把你的经历和成就放在一个地方。它应该是关于你的,一个执行动作的明确主体。斯奈德的研究发现,男性倾向于写更多动词性的动作词,而不是协作语言。被动语态的用法意味着主语是由别人来行动的。
  • 展示一些可衡量的成就(如果可能的话)。我们可以写“调整模型参数后实现了 85%的准确性”或“通过成功调整模型参数,利润率提高了 30%。”Twyla 可能没有统计学/经济学/数学背景,无法理解达到 85%模型准确性的含义。她了解公司业务,“利润率提高 30%”比“获得 85%的准确率”更有吸引力。
  • 使用 3-5 个要点。
  • 添加公司名称、职务和您与他们共事的年份。
  • 对于新生,你可以描述你的班级项目,论文或任何额外的或自由职业者的工作,如果有的话。尽量包括目标、使用的技术和可衡量的成就。

让我们看一个例子

  • 带领一个数据科学家团队使用一套机器学习方法构建预测解决方案。
  • 为一家大型房地产公司优化的 CRM 数据库。
  • 浪费的电话和电子邮件时间减少了 57%。
  • 使用 matplotlib 创建实时 ROI 图表,帮助团队专注于高利润业务。
  • 年利润增长了 20%。

当写下技能部分时,一定要记得看 JD 并包括相关的技能。

5.技能

为什么这一部分如此重要?首先,整理与你申请的职位描述相关的技能将有助于 Twyla 理解你的简历,结果,你会更好。第二,公司经常使用应用程序跟踪软件来解析收到的简历。软件会给出公司发布的职位描述和你简历的匹配百分比。分数越低,出现在废品堆中的可能性就越大。在记下这一部分的时候,一定要记得查看 JD,并包括相关的技能。您也可以将它分成多个子部分,

  • 技能-统计分析,假设检验,回归,时间序列预测,机器学习算法等。
  • 编程语言- R,Python,SQL 等。
  • 软技能——表达技能、形象化、解决问题的技能等。
  • 平台工作经验-谷歌云平台,Azure 等。
  • 使用不同工具的经验- Tableau,Git,MS Excel 等。

JDs 通常包含包或库的名称,比如 dplyr、forecast for R、scikit-learn 和 pandas for Python。在这种情况下,添加您知道的包或库。

6.其他项目/出版物

  • 如果有,写其他相关项目。例如,如果你参加过卡格尔比赛。
  • 描述您是否发表过任何论文/演讲(现有的或即将发表的)。将链接添加到出版物。

7.教育

  • 添加学院名称,地点,你获得的学位
  • 如果你正在开始你的数据科学之旅,你可以写下一些你上过的相关课程。
  • 额外的相关课程、证书(MOOCs )(如果你参加过的话)。

8.其他活动

  • 添加你积极参与的任何其他活动或计划(例如,你大学的就业协调员,你目前公司面试团队的一员)
  • 您获得的任何相关奖项。

简历中这些小节的顺序没有硬性规定。根据工作描述,你可能需要稍微改变一下顺序。如果你是大一新生,你可能想强调教育和技能部分,而不是经验部分。如果你申请的是金融领域的工作,并且只在科技或零售领域工作过,试着发挥你的技能,这在金融领域会很有用。就像你的模型调整练习一样。数据科学不可能无所不知。记住要诚实、简洁、自信,不要犹豫地把你的工作放在前面。

创建一个数据集来发现地中海的难民船

原文:https://towardsdatascience.com/creating-a-dataset-to-spot-refugee-boats-in-the-mediteranean-449e86e2d4b2?source=collection_archive---------38-----------------------

变更数据

照片由珍·西奥多在 Unsplash 上拍摄

大约半年前,我开始了一项非常有趣的探索:利用卫星数据寻找难民船。我与非政府组织太空眼合作,这是一个致力于这一探索的非营利组织。许多其他倡议也对这个主题感兴趣并正在努力。我有 ML 背景和一些编程经验,但是从一开始就解决这样的问题是一个相当大的挑战,同时也很有趣。

一开始,我们思考了很多问题——对于大多数问题,我们每隔一段时间就会回头来看——比如:有什么样的卫星数据可用?分辨率是否足以探测到船只?我们如何验证我们的预测?系统可扩展吗?

经过大量的研究和非常有趣的讨论,我们意识到我们需要先做一个可行性研究。雷根斯堡的团队选择了来自 planet.com 的可视卫星图像。柏林的佩德罗正在为雷达图像做类似的工作,并取得了一些很好的成果。奥格斯堡的 SearchWing 正在为他们自己的无人机研究探测算法。但是行星数据似乎更适合我们非地球科学的眼睛和我在计算机视觉方面的经验。除了雷达数据,它看起来就像我们习惯的普通图像和图片。

在这篇文章中,我将描述我们为可行性研究创建船舶数据集的过程。重建这个的代码可以在我的 github 上找到——你需要自己访问 planet.com 来查询图片。

阶段 1——概念化

我们决定使用的卫星图像来自 PlanetScope 4 波段卫星,该卫星提供 3m3m 分辨率的 4 通道图像(RGB+NIR)。我们选择了这个,因为它有最好的覆盖范围和分辨率的权衡。他们确实提供 0.8 米 0.8 米分辨率的图像,但这必须为某个位置提前订购,成本要高得多。行星镜卫星已经在那里有一段时间了,所以我们有一些历史数据要看。《星球日报》几乎只公布了海岸的卫星图像——也就是说,陆地上和海洋中 7 公里处的一切。这部分是因为海洋相当广阔,没有多少人对它的图像感兴趣(至少没有陆地图片那么多)。另一方面,planet 在定位他们在海洋上拍摄的卫星图像时遇到了一些问题。虽然在陆地上,他们可以使用地标来定位自己和他们的照片,但这些在海洋图像中是不可用的。这导致定位误差,从而降低质量。但是今年的某个时候,他们改进了他们的算法,现在提供了更高质量的海洋图像。

星球图像中的一艘船的例子——使用 planet.com 数据创建了我自己

有了这些信息,我们仍然没有参考系统的解决方案。我们不知道那些难民船在哪里——这就是我们开始整件事的原因。

为了训练和验证我们的船只检测模型,我们需要一些地面真实数据——至少对于监督模型来说是这样。我们可能无法通过目测找到足够多的难民船来训练任何东西。所以我们寻找其他探测飞船的可能性。我们发现了明显的 kaggle 飞船探测数据集,但是那些飞船比我们需要的要大得多。它们通常跨越几百个像素,而行星数据上的难民船仅测量大约 3 个像素。他们没有对我们来说非常有价值的 NIR 频道。所以我们决定去寻找一个基于原始 PlanetScope 数据的模型,但是是在非难民船上。但是如何在图片上找到正常的船呢?这将牵涉到大量的手工工作…

在和一些更有经验的船民在一起后,我了解了 AIS。AIS 是一个所有超过一定规模的船只都必须注册的系统。他们船上有一个发射机,不断广播他们的位置,他们还有一个接收机,告诉他们周围所有其他船只的位置。这基本上是一个确保它们不会相互碰撞的系统——至少我是这么理解的。这些数据通常对机器学习非常有用。有一些很棒的可视化项目和船舶跟踪应用程序。例如,世界自然基金会目前正在开发一种跟踪系统,利用人工智能系统来防止非法石油泄漏。我们的难民船没有 AIS 发送器。但这仍然可以帮助我们为我们的应用程序创建一个基本的训练集。

有一些网站可以让你自己请求当前的 AIS 数据来记录,但是这看起来太麻烦了。美国提供 marinecadastre.com海岸旧的 AIS 日志文件。其他一些国家也有类似的东西,但我们发现没有一个符合美国数据的分辨率。他们的文件中有一分钟的分辨率,这对我们的应用程序来说应该足够了。

所以现在我们有了一切,通过将 AIS 日志文件与行星卫星图像交叉,可以自动创建美国某个地方的船只/非船只数据集。概念阶段已经结束,我们终于可以开始实现数据集创建了。开始时,它看起来相当简单。

步骤 2 —交叉两个数据源

首先,我们需要交叉这两个数据源。我选择了迈阿密和棕榈滩之间的地区作为我感兴趣的地区。为此,我必须创建一个. geojson 文件(使用 geojson.io 并不难)。

来自 geojson.io 的截图,带有示例区域-我自己创建的

由于来自 marinecadastre 的 AIS 文件非常大,我想删除所有不在我感兴趣的区域内的条目。Geopandas 给了我很大的帮助,尽管它有时会让我发疯。这个代码可以在顶部链接的 jupyter 笔记本中的函数 reduce_ais_csv()中找到。

现在我们需要找出卫星在哪里拍的照片。没有全天覆盖,但卫星每天只通过一到三次来拍照。为了与 planet 通信,我使用了 porder API,这在本文的中有详细解释。我向 planet 索要了我的 geojson 中的图片 id 列表,这些图片的云层覆盖率不到 50%,与我感兴趣的区域至少有 80%的重叠。从 id 列表中,我们可以提取图像拍摄的准确时间。现在,从我们的 AIS 数据帧中,我们可以选择那些显示与相应卫星图像相同时间的条目。(不完全相同,但是+/- 30 秒,因为 AIS 文件的记录速度是每分钟。)

porder idlist --input "\infile.gejson" --start "day.month.year" --end "day.month.year" --item "PSScene4Band" --asset "analytic" --cmax 0.5 --outfile "\outfile.csv" --overlap 80

现在我们有了一个候选船只的列表,我们可以尝试下载卫星图像文件。

步骤 3-下载船舶图像

这一步听起来很容易,但它花费了我们几个下午和大量的脑细胞。对于在地质数据方面有经验的人来说,这可能并不难。但是我们遇到了一个大问题,地球是圆的。

是的,地球是圆的。因此,坐标空间中的简单矩形在卫星图像中不是矩形,反之亦然。长话短说,最后的结论是下载围绕坐标中预期船只位置的小片段。这些被指定为矩形。传回的图像是镶嵌在黑色未定义像素中的扭曲菱形。但是,如果我们指定矩形足够大,我们可以在这个混乱的中间切割一个矩形(在像素空间中),用于我们的训练系统。

船舶管道的可视化——如何获得一个中间有一艘船的矩形图像——创造了我自己

使用 porder API ,我们能够简单地在船的位置周围排序小的(坐标方向)矩形片段并下载这些图像。

哦,你知道有上百个坐标系统吗?正常人使用的一个叫做 EPSG-4326,还有一个特别为地中海人准备的…因为地球是圆的,转换并不简单。—这一发现又花了几个小时,但对这个项目来说是不必要的。

步骤 4-找到相应的非船只图像

我们现在已经成功地创建了我们的阳性样本。包含一艘船的那些。现在我们也需要反面的例子。不包含任何船只的卫星图像。这应该不会太复杂,因为海洋非常广阔。但是我不想只拍摄任何卫星图像,而是想要一个尽可能平衡的数据集。

所以我试着从我使用的包含一艘船的同一张卫星图像中获取一张不包含船的图像。这将自动平衡天气和闪电条件以及云和海洋条件。听起来很不错,不是吗?

为了找到一个满足我要求的片段,我创建了一个搜索半径,围绕着我目前想要补充的船。我从这个搜索半径中随机选择了一个区域,并使用 AIS 数据检查了这个区域内没有船只。接下来,我尝试使用 porder API 下载图像。我重复这个过程几次,希望得到每一个船只图像的非船只图像。有时它会失败——要么是因为当时有太多的船只在该区域航行,要么是因为它靠近我定义的 geojson 的边界。如果发生这种情况,我只是在一艘已经被用来创建非船的船上重做这个过程。因为只有大约百分之一的图像是这种情况,我认为这是一个好方法。

第五步——把所有东西放在一起

在我成功下载了 2016 年所选地区的所有数据后,我只需要更好地组织它。我把所有的船归入一艘。csv 文件和所有非船舶在另一个。它们包含 AIS 数据库中可用的所有元数据,如速度、名称等。接下来,我将所有的船图片放入一个基本文件夹,将所有的非船图片放入另一个文件夹(同时记住它们原来的名字和 AIS 条目!).最后,我们添加了一些文档,这样无论是谁,都不会完全迷路。所以数据集上有些闪亮;)

毕竟这是一个相当长的旅程,我非常期待进入创建模型和在这个数据集上评估它们的有趣部分。让我们希望我们能找到小到 3 个像素的船,这样我们就能最终开始处理真正的任务了!

声明:这不仅是我的工作。同事和其他组织提供了很多帮助。仅举几个例子:斯蒂芬、西蒙和佩德罗尽可能地帮助了我。谢谢大家!

我将在介质上发布数据集上的实验更新(如果有效,甚至可能在其他地方)。:)所以保持关注!

已知问题:目测显示我们有相当多的假阴性——所以很多非船图片包括船…

用 pyTigerGraph 创建不和谐聊天机器人

原文:https://towardsdatascience.com/creating-a-discord-chat-bot-with-pytigergraph-8439f1ea9774?source=collection_archive---------48-----------------------

创建一个聊天机器人,用 Discord.py 和 pyTigerGraph 回答 TigerGraph 的问题

什么是项目,为什么要完成它?

一个潜在的热门话题是用图形技术创建聊天机器人。虽然这绝不是一个高级聊天机器人,但它是一种结合 TigerGraph 和 Discord 的力量为 Discord 服务器创建响应机器人的方式。

第一步:创建不和谐的机器人

首先,您需要在 Discord 上创建机器人本身。对于这个项目,我们将使用 Discord.py 。要创建机器人,你需要一个不和谐的帐户,并启用开发模式。然后你应该可以进入申请页面:【https://discord.com/developers/applications

从这里,在右上角,单击“新建应用程序”

单击蓝色的“新建应用程序”按钮。

接下来,在提示符下命名您的应用程序。

命名后,您应该重定向到该机器人的页面。在这里,在左侧栏,切换到“机器人”,然后点击“添加机器人。”

切换到“机器人”,然后点击“添加机器人”

确认后,你就有你的机器人了!最终,你会需要机器人的令牌。要复制它,只需按蓝色的“复制”按钮。

用蓝色的复制按钮复制你的机器人令牌

第二步:创建图表

步骤 2a:导入库

图表将在 pyTigerGraph 中创建。首先,确保你已经安装了 pyTigerGraph 和 Discord.py。

pip install pyTigerGraph
pip install discord.py

步骤 2b:开始解决方案

然后,创建一个名为 createGraph.py 或类似的文档。首先,在http;//tgcloud.io/ 创建一个帐户,然后完成以下步骤:

  1. 转到“我的解决方案”,然后单击“创建解决方案”
  2. 单击“空白 v3 ”,然后按下一步两次。
  3. 根据需要编辑解决方案名称、标签和子域,然后按下一步。
  4. 按提交并等待解决方案启动。

步骤 2c:创建连接

一旦解决方案启动,您就可以在您的文档中使用以下内容创建一个连接。首先,导入 pyTigerGraph,然后使用它来创建连接,使用您在第三步中提交的信息作为主机名、用户名和密码。

import pyTigerGraph as tgconn = tg.TigerGraphConnection(host="https://HOST_NAME.i.tgcloud.io", username="USERNAME", version="3.0.5", password="PASSWORD", useCert=True)

步骤 2d:创建模式

接下来,我们将创建一个模式。这种情况下的模式很简单:顶点 Message 和 Word 用一个 MESSAGE_WORD 顶点连接。

conn.gsql('''CREATE VERTEX Word(primary_id word STRING) with primary_id_as_attribute="true"
CREATE VERTEX Message(primary_id id INT, message STRING, url STRING)
CREATE UNDIRECTED EDGE WORD_MESSAGE(FROM Message, To Word)
CREATE GRAPH ChatBot(Word, Message, WORD_MESSAGE)''')

运行此程序后,您将已经在 TigerGraph 中创建了您的图形!恭喜你。接下来,您需要调整连接细节,然后加载数据并编写查询。

conn.graphname = "ChatBot"
conn.apiToken = conn.getToken(conn.createSecret())

步骤三:从 API 中提取数据

为了得到我的数据,我从 https://community.tigergraph.com/的文章中提取。为此,我使用端点 https://community.tigergraph.com/posts.json.从论坛中提取了最近的消息。使用 JSON 库,我加载了“latest_posts”

import requests
import json

x = requests.get("https://community.tigergraph.com/posts.json")
data = json.loads(x.text)["latest_posts"] 

数据有几个重要的部分:raw(整个消息)、id、“topic_slug”和“topic_id”。“topic_slug”和“topic_id”一起可以检索原始 url。

print(data[0]["raw"]) # Message
print(data[0]["id"]) # ID
print("https://community.tigergraph.com/t/" + data[0]["topic_slug"] + "/" + str(data[0]["topic_id"])) # Url

接下来,我们需要将数据加载到图表中。在加载数据之前,我们需要清理数据,删除所有停用词或标点符号。接下来,我们将把它插入图表。

from nltk.corpus import stopwords
from nltk.tokenize import word_tokenizestop_words = set(stopwords.words('english'))for msg in data:  
   raw_msg="<br>".join(("".join(msg["raw"].split(","))).split("\n")) 
   individual_words = raw_msg.split()    
   word_tokens = word_tokenize(raw_msg.lower())    
   filtered_sentence = [w for w in word_tokens if not w in stop_words]    
   filtered_sentence = [w for w in filtered_sentence if not w in [        '.', ',', '!', '?', ':', ';']]
   url = "https://community.tigergraph.com/t/" + msg["topic_slug"] + "/" + str(msg["topic_id"])
   conn.upsertVertex("Message", msg["id"], attributes={"id": msg["id"], "message": msg["raw"], "url": url}) for word in filtered_sentence:        
       conn.upsertVertex("Word", word, attributes = {"word": word})
       conn.upsertEdge("Word", word, "WORD_MESSAGE", "Message", msg["id"])

太好了!现在,您已经将所有数据加载到图表中。接下来,让我们创建机器人!

第四步:创建机器人

现在创建一个新文件。还记得您在第一步中生成的令牌吗?你现在需要它。

我们将首先创建一个不和谐机器人的轮廓。

import discord
import pyTigerGraph as tg
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenizeclient = discord.Client()conn = tg.TigerGraphConnection(host="https://HOST_NAME.i.tgcloud.io", username="USERNAME", version="3.0.5", password="PASSWORD", useCert=True)conn.graphname = "ChatBot"
conn.apiToken = conn.getToken(conn.createSecret())@client.event
async def on_message(msg):
    print(msg.content)@client.event
async def on_ready():
    print(f"We have logged in as {client.user}")client.run("YOUR_DISCORD_TOKEN")

我们要做的所有工作都在 on_message 中。首先,我们将看看消息是否以“??"这个特殊机器人的触发器。接下来,我们将执行与步骤 III 中相同的数据清理步骤。最后,我们将找到消息最相似的帖子并返回它。

现在你可以运行你的机器人,看看结果!

机器人对不和谐的结果

第五步:下一步

恭喜你。你创造了一个基本的问答机器人与 TigerGraph 不和!接下来,把这个修改成你自己的。

如果你有任何问题或需要帮助,请加入 TigerGraph Discord。

https://discord.gg/7ft9PNZAM6

祝你好运!

注:所有图片,除特别注明外,均为作者所有。

幻想板球——线性规划的应用

原文:https://towardsdatascience.com/creating-a-fantasy-cricket-team-application-of-linear-programming-4b60c261702d?source=collection_archive---------4-----------------------

使用 Python(纸浆包)的分步指南

印度超级联赛(IPL)是全球最大的国内板球联赛。2020 年,IPL 冠名赞助商是 Dream11。Dream11 是一个基于印度的梦幻运动平台。它允许用户玩梦幻板球、曲棍球、足球、卡巴迪和篮球。

在本文中,我们将把规定性分析应用到体育运动中,我们将重点选择一个梦幻板球队,以其中一场比赛为例。

图片来自 Unsplash: 来源

简而言之,梦幻蟋蟀

如果你是幻想板球的新手,那么这就是它是如何工作的

  • 用户需要创建一个幻想板球队
  • 然后,用户可以与这支队伍一起参加竞赛。
  • 每个玩家被分配一个信用值。一个团队总积分是有上限的。
  • 每个球员将属于以下类别之一:击球手,守门员,投球手,全才
  • 在比赛中,分数是根据运动员的表现和类别来分配的。
  • 在比赛结束时,根据得分,遵守所有规则的得分最高的球队将是最佳 11 名球员的获胜组合。

游戏规则

建立一个梦幻团队需要遵循一套规则。

不同的幻想平台的规则可能会有所不同,需要相应地调整。

  • 一个队总共应该有 11 名队员
  • 队里应该有 1 到 3 名全才
  • 队里应该有 1 到 3 名守门人
  • 队里应该有 3 到 6 名击球手
  • 该队应该有 3 到 6 名投球手
  • 每一方应该有 4 到 7 名队员
  • 团队的总积分不应超过 100 分

如何挑选球员

此外,对于每场比赛,每个球员都可以获得以下信息:

  1. 玩家在同一锦标赛的前几场比赛中的得分
  2. 玩家每场比赛的平均得分
  3. 球员在同一赛事的过去比赛中进入前 11 名球队的次数
  4. 球员在过去进入最佳 11 队的次数百分比

以上任何一个指标都可以用来挑选最好的团队。

线性规划

运筹学中的线性规划是一种科学技术,用于通过考虑资源稀缺和约束来获得给定商业问题的最优解决方案。

线性规划允许我们将现实生活中的问题建模成由线性关系表示的数学模型。它涉及一个目标函数,该目标函数基于必须实现的目标和作为线性不等式的约束的创建来定义。顾名思义,目标函数和约束之间的关系本质上应该是线性的(一次方程)。

线性规划的快速回顾

这里有一个简单的例子来快速回顾线性编程。

线性规划中的基本术语

目标函数:目标函数是我们试图求解的线性函数。基于我们试图解决的问题,这个函数的值需要最小化或最大化。

决策变量:作为输入来决定最终输出的变量称为决策变量。它也被称为目标变量。

约束:约束是对决策变量的限制。

最终的目标函数必须在应用了所有约束的决策变量上实现。这是一个简单的线性规划问题的例子。

简单的例子

比方说,我们想要最大化 z,给定两个变量 x & y,它们需要遵循给定的约束。

目标函数:最大化 z,其中 z= 2x + 3y

决策变量: x & y

约束: x>= 0
y>= 1
x+2y<= 15
-2x+4y>=-7
-2x+y<= 4

绘制上述约束条件的所有线条,可得到如下图表。这里,阴影区域是所有上述约束都成立的公共区域。

线性规划的目标是在这个阴影区域内确定 x 和 y 的值,这将提供 z 的最大可能值。

简单的例子——线性规划(图片由作者提供)

解这个线性程序给出了 z 的最大值,在 x=9 & y=3 时为 27。

:参考文末提供的 git repo 访问 Python 代码生成上图也是用 PuLP 解决这个线性规划问题。

幻想板球&线性编程

线性规划可以用来解决许多现实生活中的问题,幻想板球就是其中之一。

要创建一个梦幻团队,你需要根据目标选择最好的球员。最终形成的团队应该遵循平台规定的所有规则或约束。

这使得它成为一个可以用线性规划解决的完美问题。我们需要在尊重给定的预算(学分)和团队组成约束的同时,最大化团队的选择度量投影。

用一个简单的例子理解线性规划,并用 Fantasy Team Generation 进行映射(图片由作者提供)

上面的映射说明了线性规划的每个基本组成部分是如何与一个简单的例子和这个组建梦幻团队的案例研究联系起来的。

什么是纸浆?

PuLP 是一个解决优化问题的开源 python 包。它提供了将数学程序转换成可以输入解算器的形式的接口。

通过提供代表优化问题和决策变量的 Python 对象,并允许以与原始数学表达式非常相似的方式表达约束,PuLP 完全在 Python 语言的语法内工作。

为了保持语法尽可能简单和直观,PuLP 专注于支持线性和混合整数模型。

纸浆支持像 GLPK,CPLE,硬币,古罗比解决方案。默认情况下,纸浆使用 CBC 解算器(硬币或分支切割解算器)。

有关纸浆的更多详情,请参考以下链接:https://pypi.org/project/PuLP/

使用 PuLP 解决 Python 中的线性问题

我们将使用 python 包 PuLP 来创建线性问题并解决它。

除了所提供的规则之外,还可以为用户添加额外的约束来进行游戏并创建最适合的团队。

一旦确定了一个最佳解决方案,它将产生一个梦幻团队以及一些概要细节。此外,我们将使用 ipywidgets 包来构建 Jupyter 笔记本中的用户界面,这样我们就可以处理约束了。

下面的代码片段是完整代码的一部分,有助于读者理解逻辑流程。

软件包安装

除了像 NumPy,pandas,sklearn 这样的常规包,这个代码还需要安装纸浆。如果您正在使用 pip,所有的软件包都可以用“pip install pulp”命令安装。

输入数据

这个程序需要两种输入。一个是玩家细节,另一个是用户配置来构建线性问题。

球员的详细资料是在 CSV 文件中创建的,该文件被读入熊猫数据帧。该文件的示例内容如下所示。

该数据目前无法在网上获得,并且是针对本案例研究手工整理的。

输入数据的样本内容(图片由作者提供)

创建线性规划问题

解决线性规划问题的第一步是创建问题。这可以使用纸浆包装来完成。

创建决策变量

准备创建目标函数和约束所需的决策变量。

应该为每个约束条件创建类似的变量。上面显示的是一个例子。同样的方法可以用来创建所有需要的变量。

定义目标函数

这里,目标函数可以基于以下之一来定义:

  • 基于每个玩家的点数最大化
  • 根据玩家过去在最佳 11 队的次数最大化
  • 基于每场比赛的平均分数最大化
  • 根据玩家在最佳 11 队中的百分比次数最大化

这种选择可以交给用户来配置,基于这种选择可以设置目标函数。

添加约束

一旦创建了线性规划问题并定义了目标函数,我们现在就可以为问题添加约束了。

基于玩家数量的限制

最终的队伍中应该正好有 11 名队员。这个条件可以用下面的约束来设置。

基于第 1 队队员的约束

每个队可以有 4 到 7 名队员。如果需要,用户可以进一步配置。

基于阵容中球员的约束

由于只有在掷硬币时(通常在比赛开始前 30 分钟)才知道比赛 11,所以可以对要挑选的运动员增加限制。

  • 从所有玩家中选择(默认)
  • 只选择参加过最后一场比赛的球员
  • 只选择至少打过一场比赛的球员
  • 只选择比赛中的 11 名球员

以上是不同约束的一些例子。类似地,可以设置所有需要的约束。

准备解决?

既然已经添加了约束条件并定义了目标函数,我们就可以解决这个问题了。

既然目标是目标最大化,那就相应地给问题设置客观细节,让纸浆去解决。

数学程序的纸浆表示

一旦向纸浆提供了要解决什么的细节,我们就可以通过打印问题对象来显示问题细节。

打印问题的输出示例如下。为了便于说明,这里我们只考虑了 3 个约束。请参考 git repo 查看所有约束的结果。

纸浆问题表述样本输出(图片由作者提供)

解决线性规划问题主要有三种类型的信息:

  1. 必须最大化或最小化的目标函数
  2. 最大化/最小化时需要遵循的约束或规则
  3. 必须应用目标函数和约束的输入变量

现在让我们试着去理解纸浆的内部表现。

目标函数的纸浆表示

纸浆中目标函数的表示(图片由作者提供)

  • 记住,我们创建了目标二进制变量来决定每个玩家是否会在幻想队中
  • 每个玩家都有一个唯一的玩家号,用于创建该玩家的标识符
  • 我们已经将目标函数设置为基于玩家点数最大化
  • 纸浆使用这些信息来导出目标函数,该函数是每个玩家的加权分数总和。
  • 这个线性规划问题的目标是找到一个组合的球员,将最大化这个总和。

纸浆对约束的表示

纸浆中约束的表示(图片由作者提供)

  • 因为我们在这里处理的是二元目标变量,所以考虑了所有匹配约束的玩家的总和
  • 例如,对于检票口看守人的约束,只考虑 WK 类型的玩家号码。类似的其他类型如击球手和投球手。
  • PuLP 将在内部保存添加到 LPProblem 的所有约束。最终的最优解将只考虑满足所有约束的组合。

变量的纸浆表示

纸浆中的决策/目标变量表示(图片由作者提供)

  • 将为数据集中的所有玩家创建决策/目标变量。
  • 目标函数和约束仅应用于这组变量

解释结果

纸浆将试图通过确定最佳选择来解决问题,该最佳选择将最大化目标函数,并且还满足所有已设置的约束。

如果在给定的约束条件下找不到任何可行的解决方案,那么它将返回不可行的状态。在这种情况下,PuLP 删除无法满足的约束,并返回一个输出。

抽样输出

作者图片

求解器的性能

由于数据很小,只有 46 个变量,因此求解器的性能不成问题。在我的本地系统(16 GB 内存)中,这一过程不到一秒钟。

求解器通过 32 次迭代找到一个最高得分为 2731 的最优解,以确定给定约束条件下的最终 11 名球员。

来自 CBC 求解器的日志(图片由作者提供)

最终最优解日志(图片作者提供)

摆弄数据

为了使应用程序更具交互性,使用了 ipywidgets,以便用户可以在 Jupyter 笔记本上选择配置值。

我们不会详细讨论在 Jupyter 笔记本上创建小部件的细节,因为已经有大量的文档可用,而且这也不是我们这里的重点。

作者图片

这些配置在内部被转换成目标函数或约束条件。

配置和创建团队—示例结果

给出你选择的约束条件,然后点击“创建梦幻团队”按钮。

作者图片

作者图片

砰!!!你已经准备好和你的梦幻团队一起开始参加比赛了!!一切顺利:-)

结论

本文是一个简单的例子,展示了如何将线性优化技术应用到板球比赛中来挑选最佳球员。线性优化的原则可以应用于许多有着简单目标的问题。

试试看,玩玩。为了探索更多,我们可以为每个玩家获取更多的历史数据,并将其添加到选择约束中。虽然这可能不会使精英队总是,但它肯定会指导用户选择球队。

免责声明:奇幻团队仅基于提供的数据和给出的约束条件进行提示。不能保证这些球员在比赛结束时会进入最佳 11 强。请在挑选团队时使用您自己的判断:-)

使用 Python 和 Streamlit 创建财务仪表板

原文:https://towardsdatascience.com/creating-a-financial-dashboard-using-python-and-streamlit-cccf6c026676?source=collection_archive---------10-----------------------

使用 Streamlit 库显示来自 Yahoo Finance 的财务数据

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

最近的轶事,日交易者在“深入”的价格图表分析后,用 OTM 看涨期权将他们的净值翻了三倍,导致了对一般投资尤其是股票的某种扭曲的看法。正是在这种乐观(或繁荣)的时期,向乔尔·格林布拉特这样的伟大投资者求助,可能会让我们对投资者在交易期权或买卖股票时最终押注的到底是什么有一个更有根据的理解。

“股票……不是一张纸,你可以在上面标上夏普比率和索丁诺指数……它们是企业的所有权股份,你对其进行估值,并试图以折扣价购买。”—乔尔·格林布拉特[1]

这表明,想要在一段时间内跑赢市场的投资者不应该通过在期权市场上鲁莽交易来实现这一目标。相反,格林布拉特建议,任何积极投资的方法都应该基于对公司基本面数据的分析。

在这一点上,值得一提的是,关于市场对证券进行充分定价的能力,长期以来一直存在一个更为根本性的争论(例如,参见 Fama [2]和 Shiller [3])。这场辩论的最终结果,反过来,对最初参与积极的投资组合管理的优点有着重大的影响。然而,这种担心不应该是本文的主题,我将做出(可能不准确的)假设,即积极的投资组合管理是有价值的。

鉴于成功的积极投资需要对公司财务状况的详细了解,剩下的核心问题是从哪里获得这些信息以及如何解读这些信息。虽然存在像彭博终端这样的巨大信息源,但大多数散户投资者没有通过购买此类服务的年度订阅来破产的冲动。在初步研究的情况下,我个人使用雅虎财经(Yahoo Finance)这样的免费产品,这些产品可以汇总财务信息,无需翻查冗长的年度和季度报告。

虽然我认为雅虎财经在提供对公司基本面的初步了解方面做得很好,但它没有提供某些重要的指标,其他指标也很难找到。

为了获得简明、易于理解的上市公司快照,我使用了一些 Python 自动化来编写一个财务仪表板应用程序。在这里,可能需要注意的是,我的编程技能肯定是不合格的,我确信有一种更好的方法来解决我的问题。因此,下面的文章应该是对 Python 和 Streamlit 潜力的证明,而绝不是编程教程。

财务仪表板应用程序

Streamlit 是一个 Python 包,它使得创建仪表板和数据应用程序变得非常容易,而不需要任何前端编程专业知识。该库可用于创建如下所示的应用程序,该应用程序允许用户输入公司股票代码,并根据公司最新的财务数据获得财务比率:

最终仪表板的预览

收集数据

为了收集作为应用程序输入的数据,使用 yahoo_fin 包非常有用。这个包从 Yahoo Finance 中抓取信息,并以 pandas DataFrames 的形式返回,而 pandas data frames 又可以很好地与 Streamlit 集成。

class Company:
    def __init__(self, ticker):
        price_df = si.get_data(ticker, dt.datetime.now()-           dt.timedelta(days=2*365), dt.datetime.date(dt.datetime.now()))
        overview_df = si.get_stats(ticker)
        overview_df = overview_df.set_index('Attribute')
        overview_dict = si.get_quote_table(ticker)
        income_statement = si.get_income_statement(ticker)
        balance_sheet = si.get_balance_sheet(ticker)
        cash_flows = si.get_cash_flow(ticker)

由此产生的数据框架可用于提取所需的信息,如公司市值或损益表指标,如 EBIT 或净收入。

self.year_end = overview_df.loc['Fiscal Year Ends'][0]
self.market_cap = get_integer(overview_dict['Market Cap'])
self.market_cap_cs = '{:,d}'.format(int(self.market_cap))
self.prices = price_df['adjclose']

self.sales = income_statement.loc['totalRevenue'][0]
self.gross_profit = income_statement.loc['grossProfit'][0]
self.ebit = income_statement.loc['ebit'][0]
self.interest = - income_statement.loc['interestExpense'][0]
self.net_profit = income_statement.loc['netIncome'][0]

最后,这些数据可以用来计算估值倍数或利润率等指标。此外,我计算了我的应用程序的流动性、杠杆和效率比率。

def get_overview(self):
        self.price_earnings_ratio = self.market_cap/self.net_profit
        self.ev_sales_ratio = self.ev/self.sales
        self.overview_dict = {
            'Values' : [self.ev_cs, self.market_cap_cs, self.ev_sales_ratio, self.price_earnings_ratio]
            }

def get_profit_margins(self):
        self.gross_margin = self.gross_profit/self.sales
        self.operating_margin = self.ebit/self.sales
        self.net_margin = self.net_profit/self.sales
        self.profit_margin_dict = {
            'Values' : [self.gross_margin, self.operating_margin, self.net_margin]
            }

显示数据

如前所述,Streamlit 使得以结构化的方式显示这些信息变得非常容易,只需很少的额外工作。在我的例子中,我只是添加了应用程序的标题和一个允许用户输入公司股票的文本字段。通过单击“Search”按钮,执行上面显示的代码行并收集数据。

st.title('Financial Dashboard')
ticker_input = st.text_input('Please enter your company ticker:')
search_button = st.button('Search')

if search_button:
    company = Company(ticker_input)
    company.get_overview()
    company.get_profit_margins()
    company.get_liquidity_ratios()
    company.get_leverage_ratios()
    company.get_efficiency_ratios()

Streamlit 提供了强大的功能,有助于通过折线图、表格或条形图等方式显示数据。

st.header('Company overview')
    overview_index = ['Enterprise value', 'Market cap', 'EV/sales ratio', 'P/E ratio']
    overview_df = pd.DataFrame(company.overview_dict, index = overview_index)
    st.line_chart(company.prices)
    st.table(overview_df)

    with st.beta_expander('Profit margins (as of {})'.format(company.year_end)):
        profit_margin_index = ['Gross margin', 'Operating margin', 'Net margin']
        profit_margin_df = pd.DataFrame(company.profit_margin_dict, index = profit_margin_index)
        st.table(profit_margin_df)
        st.bar_chart(profit_margin_df)

在我的例子中,结果如下所示:

最终控制面板,左侧是公司概况,右侧是更多指标

结束语

在我看来,Streamlit 非常容易使用,并且有很好的文档记录,使得显示和解释数据变得简单明了。我承认我的应用程序仍然相当有限,并且有许多额外的功能,一个更熟练的程序员可以集成。

总的来说,我认为增加基本指标的可用性和可访问性,如利润率或杠杆率,可以更好地了解公司的财务状况。这反过来可能会导致更明智的投资决策,这可能有助于投资者长期跑赢市场。

放弃

上面提供的代码只是将 Python 编程应用于金融领域的一个练习。本文包含的信息不应用于投资决策。此外,从雅虎财经收集的信息不应用于任何商业目的。

[1]https://www.youtube.com/watch?v=V8Zuw8Mnc-I
【2】法玛,E. F. (1970)。有效资本市场:理论与实证研究综述。《财经杂志》25 (2),383–417 页。
[3]希勒,R.J. (1981 年)。股票价格波动太大,以至于不能用随后的股息变化来解释吗?《美国经济评论》,第 71 期 (3),第 421–436 页。

在 Python 中创建创新的自定义损失函数

原文:https://towardsdatascience.com/creating-a-innovative-custom-loss-function-in-python-using-tensorflow-and-fitting-a-lstm-model-ded222efbc89?source=collection_archive---------20-----------------------

在 python 中使用 Tensorflow 包并使用 LSTM 模型进行测试

这里我想介绍一个创新的新损失函数。我将这个新的损失函数定义为 MSE-MAD。使用指数加权移动平均框架并结合使用 MSE 和 MAD 来构建损失函数。MSE-MAD 的结果将使用适合太阳黑子数据的 LSTM 模型进行比较。

图片来源【https://algorithm ia . com/blog/introduction-to-loss-functions】经作者允许编辑。

介绍

在我们进入新的损失函数之前,让我先介绍一下什么是损失函数,以及它如何应用于机器学习。损失函数的目的是衡量模型对输入数据的解释程度。换句话说,损失函数是我们的预测与响应变量之间距离的度量。在几乎所有的应用中,我们都有一个固定的模型,目标是在给定一些数据的情况下估计模型的参数。

在我介绍这个新的损失函数之前,我将首先介绍一些基本的损失函数以及它们在模型拟合期间的表现。

均方误差

均方差是我要介绍的第一个损失函数。均方误差(MSE)的计算公式如下

均方误差

根据 MSE 公式,hat 表示变量 y 的预测值或估计值。在数学中,变量上方的 hat 表示给定随机变量的估计值。n 代表我们估计的总数据点的数量。从某种意义上说,MSE 公式所做的只是测量每个预测与响应变量之间的距离,并对距离求平方,然后对所有测量值求平均值。下图用虚线显示了模型,每个数据点用绿色显示。

误差测量

python 中 MSE 的实现如下。

def MSE(y_predicted, y):
  squared_error = (y_predicted - y) ** 2
  sum_squared_error = np.sum(squared_error)
  mse = sum_squared_error / y.size
  return(mse)

平均绝对偏差

下一个损失函数是平均绝对偏差(MAD)。MAD 的公式如下所示

平均绝对偏差

在 MAD 函数的实现中,我使用 TensorFlow 包来计算平均值。

def MAD(y_true, y_pred):   
   mean =  tf.reduce_mean((y_true - y_pred))
   mad = tf.reduce_mean((y_true - mean)
   return(mad)

MSE-MAD 损失函数

这里我介绍一下自定义损失函数。这个损失函数的背景使用 EWMA 框架,其中我们的阿尔法项固定在 0.5。简单地说,损失函数是 MSE 和 MAD 公式的组合。

MSE-MAD 损失函数

def custom_loss_function(y_true, y_pred):
   squared_difference = tf.square((y_true - y_pred))
   mse = tf.reduce_mean(squared_difference, axis=-1)
   mean =  tf.reduce_mean((y_true - y_pred))
   mad = tf.reduce_mean((y_true - y_pred) - mean)
   return 0.5*mse + (1-0.5)*mad

使用 LSTM 模型的损失函数比较

首先,我介绍用于比较的数据集和机器学习模型。正在使用的数据集太阳黑子数据集和 LSTM 模型将用于预测太阳黑子时间序列。

LSTM 模式介绍

递归神经网络是用于建模时间序列数据的人工神经网络家族的一部分。递归神经网络结合先前的信息来预测当前的时间步长。给定一个输入向量 x = (x1,.。。,xn),我们假设每个 xi 独立于 x 中的每个其他观察值。但是,对于资产数据,这可能不成立,需要创建一个模型来说明某些给定时间序列数据的动态行为。对于给定数量的先前时间步骤,使用人工神经网络来构建递归神经网络的结构。在这篇论文中,我们探讨了 RNN 在预测未来股票价格中的应用。使用 RNN 的主要缺点是在尝试将模型参数拟合到数据时渐变会消失和爆炸

LSTM 门

每个块 A 代表具有输入 xt 和输出 ht 的神经网络。LSTM 背后的主要思想是遗忘之门,信息可以通过它传递给下一个神经网络。

LSTM 建筑

LSTM 模型成为时间序列预测的有力工具。

黑子数据集游戏攻略

该数据集包含太阳黑子数量的月度数据(从 1749 年到 2013 年)。有 3000 多个数据点。我们演示数据集的前几行。

从上表中我们可以看到,我们得到了包含太阳黑子数量的每月数据。当拟合 LSTM 模型来预测时间序列数据时,我们将要求值限制在 0 和 1 之间。

对于 LSTM 模型,模型结构由输入数据的结构和预测特征决定。取决于在拟合时有多少个月用于回顾,特征的数量将决定需要权重和偏差的神经元的数量。

为了在比较每个损失函数时保持一致,将使用相同的 LSTM 模型结构,如下所示。

# Initializing the LSTM
regressor = Sequential()
# Adding the first LSTM layer and some Dropout regularisation
regressor.add(LSTM(units = nodes, return_sequences = True, input_shape = (new.shape[1], new.shape[2])))
regressor.add(Dropout(0.2))
# Adding a second LSTM layer and some Dropout regularisation
regressor.add(LSTM(units = nodes, return_sequences = True))
regressor.add(Dropout(0.2))
# Adding a third LSTM layer and some Dropout regularisation
regressor.add(LSTM(units = nodes, return_sequences = True))
regressor.add(Dropout(0.2))
regressor.add(LSTM(units = nodes))
regressor.add(Dropout(0.2))
# Adding the output layer
regressor.add(Dense(units = t)) # this is the output layer so this represents a single node with our output value

既然我们已经编译了模型。我首先测试 MSE 损失函数作为基线。

# Compiling the RNN
regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')
# Fitting the RNN to the Training set
model = regressor.fit(new, y_train, epochs = 50, batch_size = 22)

损失函数在编译步骤中设置。

接下来我研究了 Huber 损失函数。我测试 Huber 损失函数的原因是它遵循与 MSE-MAD 相似的结构,其中 Huber 函数充当组合函数或分段函数。

# Compiling the RNN
regressor.compile(optimizer = 'adam', loss = "huber_loss")
# Fitting the RNN to the Training set
model = regressor.fit(new, y_train, epochs = 50, batch_size = 22)

胡伯损失函数

最后我给出了 MSE-MAD 损失函数的结果。实现是简单地将损失函数定义为 python 函数,然后在编译模型时以下面的方式调用它。

# Compiling the RNN
regressor.compile(optimizer='adam', loss=custom_loss_function)
# Fitting the RNN to the Training set
model = regressor.fit(new, y_train, epochs = 50, batch_size = 22)

MSE-MAD 损失函数

当比较 MSE-MAD 和 MSE 时,我们发现收敛大约是一半快,然而当我们比较 MSE-MAD 和 huber 损失函数时,我发现非常相似的结果。

LSTM 预言

下面使用自定义损失函数给出了 LSTM 的最终预测。使用覆盖速度更快的损失函数的主要好处是运行时间更短,并且可以更快地求解模型的最佳参数。

关于我自己的一点点

我最近在加拿大多伦多的瑞尔森大学获得了应用数学硕士学位。我是金融数学组的一员,专业是统计学。我深入研究了波动建模和算法交易。

我之前在庞巴迪宇航公司担任工程专业人员,负责与飞机维护相关的生命周期成本建模。

本人积极训练铁人三项,热爱健身。

推特:@Ethan_JS94

使用 SQL 创建机器学习模型

原文:https://towardsdatascience.com/creating-a-machine-learning-model-with-sql-81d843a5307c?source=collection_archive---------20-----------------------

在 Google Big Query 上使用 SQL 构建 ML 模型

迈克尔·泽兹奇在 Unsplash 上的照片

尽管机器学习已经非常先进了,但是它有一些弱点,让你很难使用它。

当前机器学习工作流及其问题

  • 如果你曾经使用过 ml 模型,你可能会意识到结构和准备它们是非常耗时的。
  • 对于典型的信息,研究人员最初应该将有限数量的信息从存储在 I-Python 便笺簿中的信息交换到负责结构的信息中,比如 Python 的 pandas。
  • 如果您正在装配一个定制模型,您首先需要更改和预处理所有信息,并在处理模型信息之前完成所有组件设计。
  • 然后,在那一点上,最后在你制作了你的模型并且说 TensorFlow 是另一个可比较的库之后,然后你在你的 PC 或 VM 上用一个小模型本地地训练它,然后,在那一点上,期望你返回并且制造所有更多的新信息包括并且进一步开发执行,你反复反复反复反复此外,这很难,所以你在几个周期之后停止

但是嘿,别担心!即使您不是团队的数据科学家,您也可以构建模型。

Google BigQuery 简介

照片由 帕特里克

BigQuery 是一个完全托管的 Pb 级企业数据仓库。它基本上由两个关键部分组成

  • 快速 SQL 查询引擎
  • 完全托管的数据存储

Big Query 支持用大家都习惯的标准 SQL 查询 Pb 级的数据。

示例:

#standardSQL
SELECT
COUNT(*) AS total_trips
FROM
`bigquery-public-data.san_francisco_bikeshare.bikeshare_trips`

其他主要查询功能

  1. 无服务器
  2. 灵活的定价模式
  3. 标准 GCP 数据加密和安全
  4. 非常适合 BI 和 AI 用例
  5. ML 和使用 BigQuery 的预测建模
  6. 非常便宜的存储—与谷歌云存储桶一样
  7. 使用 BigQuery BI 引擎进行交互式数据分析—连接到 tableau、data studio、looker 等

大查询及其 ml 特性

作为主要功能之一的一部分,big query 允许仅使用简单的 SQL 语法来构建预测性的机器学习模型。借助 google cloud 的 Pb 级处理能力,您可以在仓库中轻松创建模型。创建模型的示例语法如下所示

CREATE OR REPLACE MODEL `dataset.classification_model`
OPTIONS
(
model_type='logistic_reg',
labels = ['y']
)
AS

使用大查询 ML 的典型工作流程[5 个步骤]

作者提供的流程图

教程:使用大查询 ML(简单 SQL 语法)构建分类模型

你可以打开一个大的查询控制台,开始复制下面的步骤:

你可以在 youtube 上观看视频教程

Anuj Syal用 SQL(谷歌大查询)创建机器学习模型

资料组

我正在使用一个公共的大型查询数据集 google_analytics_sample 。该数据集提供了 12 个月(2016 年 8 月至 2017 年 8 月)来自谷歌商品商店的模糊谷歌分析 360 数据。数据包括电子商务网站会看到的典型数据,包括以下信息:

流量来源数据:关于网站访问者来源的信息,包括关于有机流量、付费搜索流量和显示流量内容数据:关于用户在网站上的行为的信息,如访问者查看的页面的 URL,他们如何与内容进行交互等。交易数据:谷歌商品商店网站上的交易信息。

数据集许可:公共数据集是指存储在 BigQuery 中并通过 Google Cloud 公共数据集计划向公众开放的任何数据集。公共数据集是 BigQuery 托管的数据集,供您访问并集成到应用程序中。谷歌为这些数据集的存储付费,并通过一个项目提供对数据的公共访问。您只需为对数据执行的查询付费。每月第一个 1 TB 是免费的,具体价格视查询情况而定。在知识共享署名 4.0 许可下

我们将尝试解决的机器学习问题

我们将尝试预测用户是否会在回访时购买产品,因此我们将我们的标签命名为will_buy_on_return_visit

步骤 1:探索数据集

  • 检查兑换率
WITH visitors AS(
SELECT
COUNT(DISTINCT fullVisitorId) AS total_visitors
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
),
purchasers AS(
SELECT
COUNT(DISTINCT fullVisitorId) AS total_purchasers
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
WHERE totals.transactions IS NOT NULL
)
SELECT
  total_visitors,
  total_purchasers,
  total_purchasers / total_visitors AS conversion_rate
FROM visitors, purchasers
  • 销量前 5 的产品是什么?
SELECT
  p.v2ProductName,
  p.v2ProductCategory,
  SUM(p.productQuantity) AS units_sold,
  ROUND(SUM(p.localProductRevenue/1000000),2) AS revenue
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`,
UNNEST(hits) AS h,
UNNEST(h.product) AS p
GROUP BY 1, 2
ORDER BY revenue DESC
LIMIT 5;
  • 有多少访问者在随后的访问中购买了该网站?
WITH all_visitor_stats AS (
SELECT
  fullvisitorid, # 741,721 unique visitors
  IF(COUNTIF(totals.transactions > 0 AND totals.newVisits IS NULL) > 0, 1, 0) AS will_buy_on_return_visit
  FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  GROUP BY fullvisitorid
)
SELECT
  COUNT(DISTINCT fullvisitorid) AS total_visitors,
  will_buy_on_return_visit
FROM all_visitor_stats
GROUP BY will_buy_on_return_visit

第二步。选择要素并创建训练数据集

现在我们对数据有了更多的了解,让我们最终确定并创建一个用于训练的最终数据集

SELECT
  * EXCEPT(fullVisitorId)
FROM
  # features
  (SELECT
    fullVisitorId,
    IFNULL(totals.bounces, 0) AS bounces,
    IFNULL(totals.timeOnSite, 0) AS time_on_site
  FROM
    `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  WHERE
    totals.newVisits = 1)
  JOIN
  (SELECT
    fullvisitorid,
    IF(COUNTIF(totals.transactions > 0 AND totals.newVisits IS NULL) > 0, 1, 0) AS will_buy_on_return_visit
  FROM
      `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  GROUP BY fullvisitorid)
  USING (fullVisitorId)
ORDER BY time_on_site DESC
LIMIT 10;

步骤 3:创建一个模型

此步骤对上一步中创建的数据集使用 create model 语句

CREATE OR REPLACE MODEL `ecommerce.classification_model`
OPTIONS
(
model_type='logistic_reg',
labels = ['will_buy_on_return_visit']
)
AS
#standardSQL
SELECT
  * EXCEPT(fullVisitorId)
FROM
  # features
  (SELECT
    fullVisitorId,
    IFNULL(totals.bounces, 0) AS bounces,
    IFNULL(totals.timeOnSite, 0) AS time_on_site
  FROM
    `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  WHERE
    totals.newVisits = 1)
  JOIN
  (SELECT
    fullvisitorid,
    IF(COUNTIF(totals.transactions > 0 AND totals.newVisits IS NULL) > 0, 1, 0) AS will_buy_on_return_visit
  FROM
      `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  GROUP BY fullvisitorid)
  USING (fullVisitorId)
;

步骤 4:评估分类模型性能

使用 SQL 评估您刚刚创建的模型的性能

SELECT
  roc_auc,
  CASE
    WHEN roc_auc > .9 THEN 'good'
    WHEN roc_auc > .8 THEN 'fair'
    WHEN roc_auc > .7 THEN 'not great'
  ELSE 'poor' END AS model_quality
FROM
  ML.EVALUATE(MODEL ecommerce.classification_model,  (
SELECT
  * EXCEPT(fullVisitorId)
FROM
  # features
  (SELECT
    fullVisitorId,
    IFNULL(totals.bounces, 0) AS bounces,
    IFNULL(totals.timeOnSite, 0) AS time_on_site
  FROM
    `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  WHERE
    totals.newVisits = 1
    AND date BETWEEN '20170501' AND '20170630') # eval on 2 months
  JOIN
  (SELECT
    fullvisitorid,
    IF(COUNTIF(totals.transactions > 0 AND totals.newVisits IS NULL) > 0, 1, 0) AS will_buy_on_return_visit
  FROM
      `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
  GROUP BY fullvisitorid)
  USING (fullVisitorId)
));

未来步骤和特征工程

如果您对提高模型的性能更感兴趣,可以随时选择向数据集添加更多要素

结论

像谷歌的 Big Query ML 这样的产品让更多人可以建立机器学习模型。有了简单的 SQL 语法和谷歌的处理能力,生产现实生活中的大数据模型真的很容易。

最初发表于【https://anujsyal.com】

创建电影分级模型第 1 部分:数据收集!

原文:https://towardsdatascience.com/creating-a-movie-rating-model-part-1-data-gathering-944bee6167c0?source=collection_archive---------14-----------------------

电影分级模型

通过收集我们需要的数据,开始创建电影分级预测模型的过程

你好,朋友们!欢迎来到一个新的系列,我从这篇关于创建电影分级预测模型的文章开始。在开始写这篇文章之前,我想快速提一下,我绝对没有放弃 Terraform + SageMaker 系列。我刚刚度过了一个超级忙碌的夏天,有很多事情要做,所以我暂时停止了写博客。这方面还有更多的内容,敬请关注!

我开始这个新系列的原因是一个有趣的原因。我是播客的忠实听众,我最喜欢的播客之一叫做https://www.podcastone.com/the-watercooler。这是一个轻松的播客,五个同事在一天结束后聚在一起谈论,嗯,几乎是天底下的一切!他们也有一些重复出现的片段,包括主持人之一卡兰·比恩(Caelan Biehn)将为不同的电影提供评级。他的评级实际上由两个分数组成:一个是简单的“赞成/不赞成”,另一个是一个介于 0 和 10 之间的十进制浮动分数,他称之为“Biehn 标度”。(顺便说一下,卡兰是演员迈克尔·比恩的儿子,他曾主演过《终结者**外星人等电影。)**

水冷器这些家伙真的很吸引他们的观众,所以有一次我在他们的脸书小组里开玩笑说,我应该围绕卡兰的电影评级创建一个电影评级预测模型。他们都觉得很好玩,我也觉得会很好玩,所以我们就来了!

在深入探讨这篇文章的主要目的——数据收集——之前,让我们在继续构建我们的模型的过程中,为我们将在整个系列中做的事情打下基础。和往常一样,非常欢迎您关注我的 GitHub 库中的代码。

项目范围和流程

作者创作的流动艺术品

如上所述,Caelan 为每个电影评级提供了两个分数:一个二元的“同意/不同意”和一个 0 到 10 的浮动分数。当然,这意味着我们需要创建两个预测模型:一个处理二元分类,另一个是更基于回归的模型。我有意不坚持一个特定的算法,因为我们将使用未来的帖子来验证一些算法,看看哪一个执行得最好。

为此,上面的流程图显示了我们将如何在整个系列中前进。在第一阶段(也就是本文),我们需要从各种来源收集数据来支持我们的模型。一旦我们收集了我们的数据,我们将需要执行所有适当的特征工程,以准备我们的数据通过我们各自的算法。接下来,我们将尝试几种不同的算法以及超参数调整,看看哪种算法的性能最好。一旦我们决定了要利用哪些算法,我们将创建一个完整的模型培训管道来实际创建预测模型。最后,我们将把训练好的模型包装在一个漂亮的推理 API 中!

在继续之前,有一点需要注意:我不一定要在这里创建一个完美的模型。在我的日常工作中,我是一名机器学习工程师,这个角色的范围更侧重于模型部署,而不是模型创建。也就是说,我并不精通模型创建,但我希望通过这个系列在这个领域有所发展!如果你在这个过程中发现可能有一些更好的方法,请在任何博客帖子上留下评论。

好了,让我们进入这项工作的第一阶段:数据收集!

收集电影评级

当然,如果我们想创建一个电影分级模型,我们必须有电影分级来训练我们的监督模型!据我所知,没有人在任何地方保存卡兰的电影评级,所以我不得不做一些许多人可能会害怕的事情:我必须自己收集它们。这意味着要翻遍《水冷器》的播客的完整目录,并听完它们,记下卡兰给出的任何评级。为了支持这一点,我创建了一个谷歌工作表电子表格,在那里我通过我的 iPhone 收集和输入数据。在这篇文章发表的时候,我只看了全部播客的 3/4,但是我认为我们有足够的数据来开始这个系列。

(补充说明:除了电影,Caelan 还对其他东西进行评级,所以你会在电子表格中找到比电影更多的东西。我捕捉这些其他的东西只是为了好玩,但它们会被过滤掉,只关注电影。此外,水冷器可以是 NSFW,也可以是一些非电影评级,所以……如果你看完整的电子表格,请注意这一点。😂)

好消息是,我发现了一种用 Python 编程从 Google 工作表中获取数据的方法,只要你知道sheet_id号是什么。在为我自己的 Google Sheet 找到特定的 ID 后,我可以使用下面的脚本在任何需要的时候获取更新的电影评论:

**# Defining the ID of the Google Sheet with the movie ratings
sheet_id = '1-8tdDUtm0iBrCdCRAsYCw2KOimecrHcmsnL-aqG-l0E'# Creating a small function to load the data sheet by ID and sheet name
def load_google_sheet(sheet_id, sheet_name):
    url = f'[https://docs.google.com/spreadsheets/d/{sheet_id}/gviz/tq?tqx=out:csv&sheet={sheet_name}'](https://docs.google.com/spreadsheets/d/{sheet_id}/gviz/tq?tqx=out:csv&sheet={sheet_name}')
    df = pd.read_csv(url)
    return df# Loading all the sheets and joining them together
df_main = load_google_sheet(sheet_id, 'main')
df_patreon = load_google_sheet(sheet_id, 'patreon')
df_mnight = load_google_sheet(sheet_id, 'movie_night')
df = pd.concat([df_main, df_patreon, df_mnight], axis = 0)**

这个小脚本从 Google Sheet 中的三个选项卡收集数据,并将它们全部加载到一个统一的 Pandas 数据框架中。显然,这个熊猫数据框架包含的不仅仅是电影评论。为了方便起见,谷歌表单包含一个名为“类别”的栏目,我们可以用它来过滤电影。下面是要执行的脚本:

**# Keeping only the movies
df_movies = df[df['Category'] == 'Movie']**

最后,我们可以去掉我们的项目不需要的列,包括“集号”、“类别”和“注释”列。做到这一点的代码非常简单:

**# Removing the columns we do not need for the model
df_movies.drop(columns = ['Category', 'Episode Number', 'Notes'], inplace = True)**

我们剩下的就是这个样子的东西!

作者截图

好吧!我们可以用 Pandas DataFrame to_csv函数保存下来,并准备继续前进。

收集支持数据

对于那些熟悉像臭名昭著的泰坦尼克号项目这样的 Kaggle 数据集的人来说,你会知道 Kaggle 基本上给了你所有你需要的数据。我们的项目显然不是这种情况,收集数据来支持任何这样的模型都是一个挑战。数据科学家在这个职位上必须考虑的一些事情包括如下问题:

  • 支持这种潜在模型的数据存在吗?
  • 创建模型时,我需要收集什么样的特征?
  • 我需要通过什么方式来整理原始形式的数据?
  • 我需要对原始数据进行大量的特征工程吗?
  • 原始数据真的代表了模型背后的推论吗?
  • 数据是否在推论上产生了不公平/不道德的偏向?

好消息是我可以很容易地回答其中的一些问题。数据存在吗?嗯,我知道 IMDb 的存在,所以我敢肯定,一些容量的电影数据存在!我也不必担心创建一个不道德的模型,因为这种努力的本质不会给未来带来糟糕的结果。如果你想知道不道德的努力会是什么样子,我总是用创建一个预测模型的例子来预测基于 20 世纪数据的最佳 CEO 候选人。大多数 20 世纪的首席执行官都是中年白人男性,这在很大程度上是因为压制女性和少数族裔的制度。在 20 世纪首席执行官信息的基础上创建一个模型,会使所有的推论偏向于选择一个中年白人男性,这显然是不好的,也是不道德的。

这里的挑战是从不同的来源获取数据来支持我们的模型。说实话,我一开始不知道我应该寻找的所有功能。我有一种直觉,将卡兰的分数与其他评论家的分数进行比较可能是一个好主意,因此这可能具体表现为收集每部电影的烂番茄分数。但是到了最后,我不知道我会找到什么。此外,我如何确保来自一个源的电影数据与另一个匹配?例如,我如何确保一个给我提供复仇者联盟 4:终局之战数据的来源不会意外地从另一个来源给我提供复仇者联盟 3:无限战争的数据?

幸运的是,由于谷歌的力量,数据收集没有我想象的那么困难!现在让我们来分析我收集电影数据的三个来源,以及第一个来源是如何帮助保持一个来源到另一个来源的一致性的。

(在继续之前,请注意,从现在开始,这篇文章中讨论的所有内容都被记录在这个独特的 Jupyter 笔记本中。在我们继续进行的过程中,请随意参考它!)

数据源#1:电影数据库(TMDb)

在谷歌上搜索可能对我们的项目有前景的资源,似乎不断出现的首选是这个叫做 电影数据库 的资源,通常缩写为 TMDb 。虽然它有一个非常好的用户界面,可以通过网络浏览,他们也提供了一个同样伟大的 API 进行交互。唯一的问题是,他们试图限制有多少流量被他们的 API 命中,所以他们要求用户通过他们的网站注册以获得 API 密钥。(注意:请不要问我要我的 TMDb API 密钥。我想确保我可以留在自由层,只有当我为自己保留我的 API 密匙时才有可能。)

如果你按照这个链接后面的说明去做,注册 TMDb 是非常简单的。注册完成后,您应该会看到这样一个屏幕,其中显示了您的特定 API 密钥。

作者截图

如前所述,这个 API 键是敏感的,所以如果你在自己的代码中使用它,我建议你在把代码上传到 GitHub 的情况下,想办法模糊它。有很多方法可以做到这一点,但为了简单起见,我将我的密钥加载到一个名为keys.yml的文件中,然后使用一个.gitignore文件来确保该文件不会上传到 GitHub。如果你不知道什么是.gitignore文件,它是一个你可以描述任何你不想上传到 GitHub 的东西的地方,无论它是一个单一的特定文件,一个特定的目录,还是任何以特定扩展名结尾的东西。这个.gitignore文件本身不存储任何敏感的东西,所以非常欢迎你复制我在这个项目中使用的。

那么,如何创建并使用这个keys.yml文件呢?让我创建一个不同的test.yml文件,向您展示它如何处理不敏感的信息。首先,让我们创建那个test.yml文件,并像这样填充它:

**test_keys:
    key1: s3cretz
    key2: p@ssw0rd!**

现在我们可以使用这个小脚本导入 Python 的默认yaml库并解析test.yml文件。下面你会看到一个截图,我特意打印了包含“敏感”信息本身的变量,但是请注意,你并不想用你实际的 API 键来打印。

**# Importing the default Python YAML library
import yaml# Loading the test keys from the separate, secret YAML file
with open('test.yml', 'r') as f:
    keys_yaml = yaml.safe_load(f)

# Extracting the test keys from the loaded YAML
key1 = keys_yaml['test_keys']['key1']
key2 = keys_yaml['test_keys']['key2']**

作者截图

好的,这就是我们如何保证 API 密匙的安全,但是我们实际上如何使用它呢?幸运的是,我们可以使用几个 Python 包装器来轻松地使用 Python 与 TMDb 进行交互,我选择使用的是一个名为 tmdbv3api 的包装器。tmdbv3api 的文档可以在这个链接中找到,我们将通过这个 Python 包装器遍历我所做的与 TMDb 的 api 交互的基础。

pip3 install tmdbv3api安装后,我们需要做的第一件事是实例化一些 TMDb Python 对象,这将允许我们获得我们需要的数据。让我先向您展示代码,我将解释这些对象的作用:

**# Instantiating the TMDb objects and setting the API key
tmdb = tmdbv3api.TMDb()
tmdb_search = tmdbv3api.Search()
tmdb_movies = tmdbv3api.Movie()
tmdb.api_key = tmdb_key**

第一个tmdb对象是一种“主”对象,它使用我们提供的 API 键实例化我们的 API 连接。tmdb_search对象是我们用来将电影名称的字符串文本传入 API 以获得关于电影的一些基本信息,尤其是电影的唯一标识符。然后,我们可以将该电影的唯一标识符传递给tmdb_movies对象,这将为我们提供一个数据宝库。

让我们通过搜索我最喜欢的电影之一来展示这一点。下面是我们如何使用tmdb_search来使用字符串搜索电影:

**# Performing a preliminary search for the movie "The Matrix"
matrix_search_results = tmdb_search.movies({'query': 'The Matrix'})**

如果你查看这些搜索结果,你会发现是一系列搜索结果,每一个都包含每部电影的有限细节。现在,就像任何搜索引擎一样,TMDb 将尝试返回与您的字符串最相关的搜索。作为一个例子,让我们看看当我遍历这些结果并从每个搜索结果条目中取出电影的标题时会发生什么:

作者截图

正如你所看到的,它首先返回了原始的黑客帝国电影,然后是其他后续的黑客帝国电影,然后是其他一些标题中有“黑客帝国”的随机电影。

在这里,我们将不得不接受我们的搜索结果的风险…你会在下面看到,我基本上要创建一个 Python for循环来迭代通过卡兰评级的每部电影。不幸的是,我无法切实验证我搜索的每部电影在第一次尝试时都会出现正确的一部。例如,我知道 Caelan 评论了旧的恐怖电影宠物语义的更新版本,没有看,我不知道 TMDb 是否会给我更新的版本或旧的经典。这只是我们不得不接受的风险。

单独做这个搜索并不能解决 TMDb 的问题。虽然这些初步结果确实返回了一些关于这部电影的信息,但实际上还有另一部分 TMDb 将提供我们想要的所有细节。在我们获得这些额外的细节之前,让我们看看原始搜索结果中的关键字,这样我们就可以显示我们将从下一步中提取多少更多的细节。

作者截图

为了进行更详细的搜索,我们需要将 TMDb ID 传递给tmdb_movies对象。我们可以通过查看matrix_search_results[0]['id']从原始搜索结果中获得 TMDb ID。这就是我们如何使用 TMDb ID 来提取关于电影的更多细节:

**# Getting details about "The Matrix" by passing in the TMDb ID from the original search results
matrix_details = dict(tmdb_movies.details(matrix_search_results[0]['id']))**

现在,我们来看看与初步结果相比,这个更详细的结果列表的新关键字:

作者截图

正如你所看到的,我们从这次搜索中获得了比以前更多的细节!现在,为了简洁起见,我不打算在这里花太多时间向您展示我将保留哪些特性。如果你想知道的话,我将创建一个数据字典作为我的 GitHub 的自述文件的一部分。但在进入下一个来源之前,我想指出一件事。还记得我说过我关心的是从一个数据源到另一个数据源保持电影结果的一致性吗?好了,朋友们,我有一些好消息!作为 TMDb 搜索结果的一部分,它们还包括imdb_id。这很好,因为像这样的唯一标识符肯定有助于确定正确的 IMDb 搜索结果。说到 IMDb…

数据来源#2: IMDb

所以您可能会奇怪,为什么我选择 TMDb 作为主要数据源,而不是 IMDb 呢?答案是因为虽然 IMDb 有官方 API,但我无法使用它。他们似乎需要某种特殊的商业案例来请求访问,老实说,我不想经历这样的麻烦。幸运的是,我确实找到了一个适合我们的替代品: IMDbPy 。IMDbPy ( 链接到 docs )是一个 Python 库,有人创建它来与来自 IMDb 的数据交互。现在,我真的不知道作者是如何获得这些数据的。这可能是因为他们可以访问官方的 IMDb API,或者他们正在做一些花哨的屏幕截图。无论是哪种情况,这个 Python 库都提供了我们需要的数据。

通过从 TMDb 搜索结果中提取 IMDb ID,我们可以使用它作为 IMDb 搜索的基础。不过有一点需要注意:TMDb 对 IMDb ID 的格式化有点奇怪。具体来说,就是将字符“tt”附加到每个 ID 的开头。不过,不要担心,因为我们可以简单地使用 Python 字符串迭代器,在将这些初始字符放入 IMDb 搜索之前,将其剥离。

在通过运行pip3 install imdbpy安装 IMDbPy 之后,我们准备通过运行下面的代码实例化我们的imdb_search对象:

**# Importing the IMDb Python library
from imdb import IMDb# Instantiating the IMDb search object
imdb_search = IMDb()**

现在,我们可以通过弹出 IMDb ID 来执行搜索,如下所示:

**# Obtaining IMDb search results about the movie "The Matrix"
matrix_imdb_results = dict(imdb_search.get_movie(matrix_imdb_id))**

唯一不幸的缺点是,虽然 IMDb 返回了大量信息,但大多数信息对我们的模型没有好处。IMDb 返回的大部分信息都是关于电影的配角和工作人员的,不幸的是,这些信息在预测模型中并不具有良好的特性。事实上,我们能从这些结果中提取的信息只有imdb_ratingimdb_votes。我要说这有点令人失望,但既然 TMDb 在第一遍中为我们返回了这么多信息,我也不太失望。

完成 IMDb 后,让我们继续第三个也是最后一个数据源。

数据源#3:开放电影数据库(OMDb)

从这个项目一开始,我就知道我绝对希望作为支持这些模型的特性的一件事是来自烂番茄的各自的评论家分数和观众分数,到目前为止,我们还没有从 TMDb 或 IMDb 获得这些数据。

幸运的是,开放电影数据库(OMDb) 在这方面显示了一些希望!实际使用 OMDb 将与我们使用 TMDb 非常相似,除了我们可以使用 IMDb ID 在 TMDb 中搜索电影。与 TMDb 一样,OMDb 要求您注册自己的 API 密钥。你可以通过在这个表格上提交你的电子邮件来做到这一点,他们会通过电子邮件把 API 密匙发给你。正如您在这个表单中注意到的,您每天只能使用 1000 次对这个 API 的调用,这对我们的目的来说完全没问题。(同样,如果您开始与世界共享这个 API 密匙,您将会遇到问题,所以一定要把这个 API 密匙留给自己!)

因为这篇博文已经开始变得很长了,所以我将粘贴我的脚本,它将获得烂番茄评论家评分和 Metacritic metascore。该脚本的行为与 TMDb 非常相似:

**# Instantiating the OMDb client
omdb_client = OMDBClient(apikey = omdb_key)# Iterating through all the movies to extract the proper OMDb information
for index, row in df_all_data.iterrows():
    # Extracting movie name from the row
    movie_name = row['movie_name']

    # Using the OMDb client to search for the movie results using the IMDb ID
    omdb_details = omdb_client.imdbid(row['imdb_id'])

    # Resetting the Rotten Tomatoes critic score variable
    rt_critic_score = None

    # Checking if the movie has any ratings populated under 'ratings'
    omdb_ratings_len = len(omdb_details['ratings'])

    if omdb_ratings_len == 0:
        print(f'{movie_name} has no Rotten Tomatoes critic score.')
    elif omdb_ratings_len >= 0:
        # Extracting out the Rotten Tomatoes score if available
        for rater in omdb_details['ratings']:
            if rater['source'] == 'Rotten Tomatoes':
                rt_critic_score = rater['value']

    # Populating Rotten Tomatoes critic score appropriately
    if rt_critic_score:
        df_all_data.loc[index, 'rt_critic_score'] = rt_critic_score
    else:
        df_all_data.loc[index, 'rt_critic_score'] = np.nan

    # Populating the Metacritic metascore appropriately
    df_all_data.loc[index, 'metascore'] = omdb_details['metascore']**

总而言之,以下是我们所有电影的 18 大特色:

作者截图

让我们继续将该数据集保存为 CSV 格式,并结束这篇文章!

接下来:特征工程

唷,我们在这篇文章中走了很长的路!我们从 3 个不同的数据源中获得了 18 个不同的特征,我希望这将为我们在下一个特征工程部分开始生成新的特征提供一个良好的基础。不幸的是,我们无法获得我所希望的烂番茄观众评分,所以我将向正式的烂番茄 API 提交一个请求,看看我是否能获得它,因为我认为这将是一个非常有用的功能,所以如果我能获得它,我可能会回来修改这篇文章的结尾。

感谢大家查看这篇文章!希望您发现它有趣且信息丰富。我也开始在 YouTube 上直播这个项目的编码过程,你可以在我的链接树中找到我所有的事情。实际上,我已经为这篇特别的帖子做了现场直播,重播可以在 YouTube 上看到。再次感谢你的阅读!下一篇帖子见。🎬

创建感知器网络:从零到英雄

原文:https://towardsdatascience.com/creating-a-perceptron-network-from-zero-to-hero-64acfbd7c7ef?source=collection_archive---------38-----------------------

神经网络系列

神经网络系列—第 1 章,第 2 部分

序言注释

这个故事是我正在创作的关于神经网络系列的一部分,也是专门讨论感知机网络的一章的第二部分(你可以在这里阅读第一部分)。在这篇文章中,我将应用上一篇文章中解释的所有概念,并用 Python 实现一个感知器网络。

简而言之,感知器

我们在我以前的文章中已经看到,感知器是一种使用阈值函数作为激活函数的神经网络。获得输出 y 的方法是将一组权重 W 乘以一组输入,加上偏置节点( b ),然后对这个结果应用阈值函数【f(z)

回顾我的上一篇文章,我们也看到了具有更复杂架构的矩阵是什么样子,具有 m 输入节点和 n 神经元。然而,在用于前馈方程以获得网络预测的符号中,我们还没有看到更复杂的体系结构的影响。**

(注:如果接下来的内容对你没有太大意义,建议你看一看基本的线性代数概念,即矩阵的转置和乘法。)

让我们像上一篇文章一样假设 m =3、 n =5。这意味着我们的 W 矩阵将有 3 行 5 列。如果我们将标量运算转换成矩阵符号,我们的前馈方程就变成这样:

前馈方程的矩阵符号

从这个“新”前馈方程中,可以突出一些变化:

  • 输入 X 现在是一个 3 行一列的矩阵。它有 3 行,因为我们假设 m =3 ( m 是输入神经元的数量)。一列代表数据集中的一个示例,但是可以将所有示例注入到 X 中,并通过使用每一列来放置数据集中的每个样本,一次性获得所有预测;
  • 偏置节点 b 现在是一个 5 行 1 列的矩阵。这是因为我们每个神经元需要一个偏置节点,我们将神经元的数量 n 定义为 5;
  • y 将必须与 b 的大小相同,因为如果有 5 个神经元,也将有 5 个输出。

上面描述的整个等式通常以一种更简单的方式表示为:y =f(wᵀx+b)。然而,通过将 b 作为 W 的额外一行,并将一个特殊的输入节点添加到常数值为 1 的中,这两个操作可以简化为一个操作,因为这是一个数学上等价的表达式:

前馈机制

为了实现前馈机制,我们需要三个组件:

  • 偏置节点加法器。它应该向 X 添加额外的行(值为 1 ),以容纳权重矩阵中偏差的额外行;
  • 激活功能。它应该接收输入 z 并应用阈值函数以提供y
  • 前馈功能。它应该接收一个或多个示例(我们的 X ),每个示例填充网络输入层的 m 条目,以及描述连接权重的权重矩阵。其输出应该是 y
**def **activation**(z):
    return np.where(z>=0, 1, 0)def **add_bias_node**(X):
    return np.vstack([X, np.ones(X.shape[1])])def **feed_forward**(W, X):
    return **activation**(np.dot(np.transpose(W), **add_bias_node**(X)))**

训练感知器

感知器训练算法是一个迭代过程,旨在找到使网络整体误差最小化的网络连接权重集。网络的单个权重可以通过使用以下等式来更新:

在每次迭代(也称为历元)中,我们通过计算预测输出和实际输出之间的差异来评估误差(【e】),并使用它们以及输入和学习率()系数来计算我们将改变每个权重多少(也称为δ,或δ)

下面的示例描述了训练过程的伪代码:

**W = initialize weight matrix with dimensions (M+1,N)
for each epoch (e):
    for each example (x):
        y = calculate network prediction using W and x
        error = calculate deviation between y and target (t)
        delta = calculate weight variations based on the error and learning rate
        update W with deltas
return W**

在将其具体化为 Python 代码后,我们得到了类似这样的东西:

**def **train**(W, inputs, targets, epochs, lr):
    for epoch in range(epochs):
        for x, t in zip(inputs.transpose(), targets):
            y = **feed_forward**(W, x.reshape(1, -1).transpose())
            errors = np.subtract(y, t)
            x_with_bias = **add_bias_node**(x.reshape(-1,1))
            deltas = lr * np.dot(x_with_bias, errors.transpose())
            W = np.subtract(W, deltas)
    return W**

感知器在最大似然问题中的应用

既然我们已经为感知器神经元建立了基础,我们可以将其应用于大型数据集,这是一个众所周知的数据集,主要用于介绍机器学习基础知识。目标是根据数据集中描述的一组特征来预测泰坦尼克号灾难中的幸存者。

在本文的上下文中,我只使用了两个特征来训练模型:乘客支付的票价和其年龄,因为这使得数据集和模型更容易可视化。使用两个特征意味着在 2D 空间中工作,这也意味着我们的神经网络架构由单个神经元( n =1)和两个条目( m =2)组成(如果我们包括偏差节点,则为三个)。

**import seaborn as snstitanic = sns.load_dataset('titanic')M = 2
N = 1X = np.asarray(titanic[features]).transpose()
W = np.random.rand(M + 1, N) # + 1 because of the bias node
t = titanic['survived'].to_numpy()**

在上面这段代码中,我们收集了 XWt ,以便计算y 并比较训练过程前后的错误率。 W 的初始化以随机方式进行,遵循 0 和 1 之间的均匀分布,因为这是初始化网络权重的一种可能方式。请记住,这是培训中一个非常重要的主题,因为初始化过程会对培训速度产生很大影响。但是,这个主题将在本系列的后面详细介绍,并且超出了本文的范围。
现在我们已经有了形状正确的所有矩阵,让我们在训练前后应用前馈机制:

**y = feed_forward(W, X)
error_rate(y.flatten().tolist(), t.tolist()) # 0.59383W_trained = train(W, X, t, 20, 0.1)y = feed_forward(W_trained, X)
error_rate(y.flatten().tolist(), t.tolist()) # 0.31512**

我们设法将神经网络错误预测的例子数量从 0.59 减少到 0.31,这意味着我们的模型准确性大约为 69%。但是神经网络预测我们样本的能力在整个训练过程中是如何变化的呢?为了回答这个问题,我们可以简单地得到每个时期的预测,并画出分类器的决策边界。在 2D 上下文中,该边界是给定乘客生还或不生还的概率相等的线。

在下面的 gif 中,你可以看到网络的预测以及分类器的决策边界。橙色样本是被正确预测为幸存者的乘客,绿色样本是被正确预测为非幸存者的乘客,灰色样本是被感知机错误预测的乘客。

使用泰坦尼克号数据集训练的感知机

最后意见

虽然我们设法提高了网络的准确性,但通过观察上面动画中的训练过程,我们可以记下一些想法:

  • 问题不是线性可分的
    我们已经看到,感知器收敛定理证明,如果存在线性可分性,就有可能达到最优解。异或问题也说明了感知器的局限性。在这个问题中,我们可以看到感知器努力寻找一条线,将消极和积极的类别完全分开……因为这条线是不可能画出来的,因为在图中总会有灰色的点,也就是错误的预测。
  • 添加更多功能可能有助于提高性能
    我们挑选了两个功能来解决这个问题。然而,如果我们添加更多的功能,会发生什么呢?也许线性可分性将通过有一个超平面来分离这两个类来实现,或者至少我们将更接近于此。我在我的感知机笔记本中做了这个小体验。

感谢阅读!你喜欢这篇文章吗?非常感谢你的反馈,🗣。你可以随时在 TwitterLinkedIn 上联系我,或者如果你对下一章的最新消息感兴趣,就在 Medium 上关注我😀。

一些相关阅读:

  • 关于感知器的完整笔记本可以在这里找到
  • 有关如何探索泰坦尼克号数据集和应用其他模型的更多想法,请查看由 Benedikt Droste 编写的泰坦尼克号数据集的机器学习

为空间分析创造一个平台

原文:https://towardsdatascience.com/creating-a-playground-for-spatial-analytics-c7b8a867ff34?source=collection_archive---------52-----------------------

如何在不到 30 分钟的时间内通过 SAP HANA 云设置和使用 QGIS

您对空间分析感兴趣,并且正在寻找一些入门内容?SAP HANA Cloud Trial 与 QGIS 的结合为您提供了大规模空间数据处理的低门槛。基于 SAP HANA 构建的空间工作流最终可以在业务应用程序中重用,以将位置维度注入到您的业务流程中。

不管你是第一次接触 QGIS 还是第一次接触SAP HANA——或者两者都是。这个博客的目标是在不到 30 分钟的时间里为你提供一个免费的工作场所。所以——把它加到你的书签里,在你的日历里划出一些时间!

照片由蒂姆·阿特伯里在 Unsplash 上拍摄

该教程将包含以下任务:

  • ⏳5m | 创建 HANA 云试用实例
  • ⏳2m | 安装 SAP HANA ODBC 驱动
  • ⏳3m | 安装 QGIS
  • ⏳5m | 将 QGIS 连接到 SAP HANA 云
  • ⏳5m | 上传您的第一个空间数据集
  • ⏳5m | 在底图上可视化数据
  • ⏳5m | 将空间工作负载下推到 SAP HANA 云

另外,我建议在开始前喝杯咖啡。这不是 30 分钟的一部分,因为准备时间因准备方法而异。所以,你可以看到这是开始这个宏观研讨会的先决条件。

另一个先决条件是在https://download.qgis.org上下载适用于您的操作系统的 QGIS 安装包。我在 Mac 上工作,QGIS 3.18 的相应安装包大小为 1.2GB。根据服务器速度,此下载可能会持续一段时间…

准备好你的☕️了吗?

⏳5m👉创建 HANA 云试用实例

这里我应该承认,5 分钟是净努力。SAP HANA 云试用实例的实际创建时间各不相同。好的一面是,当您的新实例启动时,您可以并行执行其他安装步骤。这样,我们应该仍然能够保持 30 分钟的目标。

⏯演练:创建 SAP HANA 云试用实例

遵循以下步骤:

  1. 前往https://www.sap.com/cmp/td/sap-hana-cloud-trial.html并点击立即开始免费试用
  2. 输入您的数据并选择您的首选地区(即美国东部、欧洲或新加坡)。
  3. 创建您的全球帐户、子帐户、组织和开发空间需要一两分钟。喝一口你的咖啡,然后等着。
  4. 您将自动收到一封电子邮件,其中包含您的试用链接。点击链接 进入您的试用
  5. 现在,你需要进入你的“空间”。为此:
    ➲点击进入你的试用账户 ➲点击子账户试用。相应的区域也会显示您之前选择的区域。
    ➲点击名为 dev 的空间。
    ➲点击左侧的 SAP HANA Cloud
  6. 接下来,我们将开始实际的 HANA 云试用实例。因此,点击右上角的创建
  7. 在下面的对话框中,需要注意这些配置:
    实例名。本教程我会选择 hctrial
    管理员密码 ➲ 允许的连接应该设置为允许所有 IP 地址为了简单(和安全的代价!).
    创建数据湖可以关闭,因为您不需要数据湖来执行这里概述的步骤。
  8. 将创建您的实例。继续其他步骤,我们稍后回来。

⏳2m👉安装 SAP HANA ODBC 驱动程序

在这里,2 分钟通常是慷慨的。要安装 SAP HANA ODBC 驱动程序,它是 SAP HANA 客户端的部分,您只需从 SAP 开发工具下载并执行操作系统特定的安装程序。

这里没有太多要考虑的,因为这是一个下下一个完成安装者(这是一个正式的表达吗?嗯,应该是。)。有适用于 Windows 、 macOS 和 Linux 的安装包。

⏳3m👉安装 QGIS

同样,这本质上是一个下一个完成的安装程序,没有具体的考虑。如上所述,Windows、macOS 和 Linux 的操作系统特定安装包可在 QGIS 下载页面上获得。您至少需要 3.18 版才能使用 SAP HANA。

一旦您下载并安装了 QGIS 3.18,您就可以启动客户端。确保您在左侧的数据浏览器中将 SAP HANA 视为数据提供商。

⏳5m👉将 QGIS 连接到 SAP HANA 云

关于如何将 QGIS 连接到 SAP HANA 的一般说明可以在 QGIS 文档中找到。此外,还有一个描述这一过程的短片。

⏯演练:将 QGIS 连接到 SAP HANA 云试用版

但是,让我们来详细了解一下如何获得必要的证书:

  1. 如果您不在 SAP BTP 驾驶舱内查看带有 SAP HANA 云实例的图块,请重复上述“创建 HANA 云试用实例”中的步骤 4 和 5。您应该看到您的创建的运行的实例。
  2. 点击动作复制 SQL 端点。端点将被复制到您的剪贴板。保持在那里。
  3. 打开 QGIS,在左侧窗格的浏览器中找到 SAP HANA 条目。
  4. 右键点击 SAP HANA ,选择新建连接
  5. 将会打开连接对话框。填写以下字段:
    名称:填写连接的名称。我会用 hctrial
    主持人:粘贴你的剪贴板,最后去掉 ":443" 。SQL 端点的格式为 <主机> : <端口> ,字段期望 <主机>
    标识符:将下拉菜单切换到端口并在文本字段中输入 443
    认证:选择基本认证,输入用户名密码。如果这只是一个游戏场,DBADMIN 用户将完成这项工作。请注意,建议仍然是创建一个具有有限访问权限的专用用户。
    (注意:旧版本的 ODBC 驱动程序要求您在连接属性中显式启用 SSL。确保使用最新的客户端版本)
  6. 在连接对话框中点击测试连接,如果我们两个都做对了工作,你应该会看到一次成功的连接尝试。
  7. 点击 OK 并检查您的连接(在我的例子中是 hctrial )是否列在左侧窗格的浏览器中。

⏳5m👉上传您的第一个空间数据集

到目前为止,我们取得了什么成就?我们已经创建了一个 SAP HANA 云试用实例,并通过 ODBC 连接了 QGIS。不幸的是,我们的数据库仍然是空的,我们应该改变这一点。好消息是,我们不需要任何数据库工具来上传我们的第一个数据集。我们将简单地使用 QGIS。

⏯演练:上传您的第一个空间数据集

正如我在之前的博客中所建议的,我们可以使用Geofabrik提供的 OpenStreetMap 数据。我们将从位于德国沃尔多夫的 SAP 总部区域的兴趣点数据开始。

让我们这样做:

  1. 下载“Regierungsbezirk Karlsruhe”的 Shapefile (.shp.zip)。您可以将 Shapefile 视为基于文件的地理空间数据数据库。
    下载页面 | 直接链接
  2. 打开 QGIS 并找到下载的文件(不要解压缩!)在浏览器左侧。在我的 Mac 上,我必须导航到主页>下载。您经常使用的文件夹也可以添加到收藏夹中。
  3. 该文件可以在浏览器中进一步展开。这样做,并找到名为 gis_osm_pois_free_1 的图层。
  4. 在浏览器中找到您的 SAP HANA 连接,并将其展开两次,这样您就可以看到该模式了(如果您遵循了上面的步骤,则为 DBADMIN )。
  5. 神奇的是:将 gis_osm_pois_free_1 层拖放到您的 DBADMIN 模式上。
  6. 您已成功将首个空间数据集导入 SAP HANA Cloud 试用版!

如果您需要证据,您可以打开数据库浏览器或 DBeaver 并检查已经创建的表。但请注意,这不会是我们 30 分钟交易的一部分!

⏳5m👉在底图上可视化数据

现在,我们已经在数据库中存储了个兴趣点(poi)及其坐标。这类数据(即点、线、多边形等。)给出的坐标称为矢量数据。矢量数据可以打印到地图甚至卫星图像上(这被认为是栅格数据)。

所以我们需要添加两个不同的到我们的 QGIS 项目中:

  1. 基础地图(例如街道地图或卫星图像)
  2. 绘制在该地图上的数据(由 SAP HANA 管理的矢量数据)

⏯演练:使用卫星图像添加基础层

如何添加基层:

  1. 在浏览器中左键点击 XYZ 瓷砖并选择新建连接
  2. 一个新的磁贴服务对话框打开了:
    ➲输入“谷歌地图卫星”作为名字
    ➲输入' https://mt1 . Google . com/vt/lyrs = s&x = { x }&y = { y }&z = { z } '作为 URL
    ➲设定了最大值。缩放级别至 19。
    ➲用确认正常。
  3. 在浏览器的 XYZ 磁贴下找到谷歌卫星
  4. 双击谷歌地图卫星添加带有卫星图像的基础图层。

如果您想添加不同的服务(如 OpenStreetMap),您可以查看本博客获取更多网址。

⏯走查:在 SAP HANA 中可视化数据

如何添加 SAP 总部周围的所有喷泉:

  1. 在浏览器中找到我们之前上传到 SAP HANA 的数据集。(SAP HANA>HC trial>db admin>GIS _ osm _ pois _ free _ 1)
  2. 双击 gis_osm_pois_free_1 在底图上添加另一个图层
  3. 在左下方的可见图层列表中,右击新添加的图层,选择缩放至图层。这将确定相应数据的边界框,并相应地缩放地图。
  4. 我们现在可以在地图上看到卡尔斯鲁厄地区的所有 poi。我们只想过滤掉喷泉。因此,我们再次右击图层,选择滤镜…
  5. 滤镜对话框打开:
    ➲作为滤镜表达式输入 "fclass" = '喷泉' ➲ 确认 OK
  6. 放大到 SAP 总部。你会看到两个喷泉——东边的一个是 3 号楼前的喷泉。花些时间——这是一项探索性的任务😉
  7. 在窗口的顶栏上选择识别特征工具。当光标悬停在地图上时,它会改变并包含一个小的信息图标。
  8. 单击喷泉的点,您将在右侧的数据库中看到相应的记录。

现在,您已经了解了如何在 QGIS 中可视化 SAP HANA 中的数据。如果你喜欢,你可以玩一点过滤器,改变基本地图。同样,这种热情不计入我们的 30 分钟!

⏳5m👉将空间工作负载下推到 SAP HANA 云

最后但同样重要的是,让我们看看如何在数据库级别执行一些空间工作负载,并将结果发送到 QGIS。由于 SAP HANA 上的所有空间处理功能都是 SQL 语法的一部分,因此最好的方法是创建一个 SQL 视图,可以在 QGIS 中使用。

因此,我们需要打开 SAP HANA 数据库浏览器,创建一个 SQL 视图并在 QGIS 中使用它。

⏯演练:为空间聚类创建视图

创建一个 SQL 视图,进行六边形聚类并计算每个聚类的兴趣点数量:

  1. 如果您不在 SAP BTP 驾驶舱内查看带有 SAP HANA 云实例的图块,请重复上面“创建 HANA 云试用实例”中的步骤 4 和 5。您应该看到您的创建的运行的实例。
  2. 点击操作并在 SAP HANA 数据库浏览器中打开
  3. 可能会提示您输入用户凭据。使用在 QGIS 中设置的同一用户(即 DBADMIN)。
  4. 点击左上角的 SQL 符号打开一个新的 SQL 控制台
  5. 将以下 SQL 语句复制到 SQL 控制台并执行:
CREATE VIEW POI_DENSITY AS
(
	SELECT 
		ST_ClusterId() AS cluster_id,
		ST_ClusterCell() AS cluster_cell,
		COUNT(*) AS count_pois
	FROM "gis_osm_pois_free_1"
	GROUP CLUSTER BY "geom" USING HEXAGON X CELLS 100
)

您可以在 SAP HANA 空间参考中找到关于空间聚类的更多信息。

⏯穿行:QGIS 中的基本符号系统

将数据放入 QGIS 并应用一些基本样式:

  1. 打开 QGIS 并通过双击添加底图(类似于上一步)。
  2. 在浏览器中找到 SQL 视图POI _ DENSITY(SAP HANA>HC trial>db admin>POI _ DENSITY)并双击将其添加到地图中。
  3. 右键点击 POI_DENSITY 图层,选择属性。(确保在图层选项卡中而不是在浏览器中完成此操作!)
  4. 在下面的对话框中,你可以调整图层样式:
    ➲选择左侧的符号
    最上面的➲将下拉值从单个符号更改为分级 ➲ 作为选择我们的数据库字段count _ pois选择合适的颜色渐变(即红色* )
    ➲将模式从相等计数(分位数即 8)
    ➲点击
    分类按钮创建颜色范围。
    ➲用
    确认 OK***
  5. 现在,您应该会在地图上看到类似热图的可视化效果。六边形单元根据单元中 poi 的数量进行着色。

这种类似热图的可视化方式可以很容易地发现 SAP 总部周围的主要城市:卡尔斯鲁厄、曼海姆和海德堡。

拉伸任务:给六边形单元格添加一些透明度

🏁下一步是什么?

恭喜你。您已经完成了空间分析运动场的设置。我很想知道您对设置好一切所需时间的反馈——请使用下面的评论部分。我承认,如果你第一次看到 SAP HANA 和 QGIS,30 分钟可能是一个具有挑战性的时间表,但我真的希望即使有这样或那样的复杂情况,你也能坚持不到 1 小时。

如果您想深入更复杂的场景,我建议您查看一些关于空间数据科学以及如何将地理空间维度添加到机器学习模型中的材料。一个很好的起点是我关于走向数据科学的文章。请注意,这是一个高层次的概述。文章中有更详细说明的博客链接。

走向数据科学:地理空间特征对机器学习的影响

为了了解更多关于 SAP HANA Spatial 和 Graph 的细节,我建议观看 Youtube 上 SAP Devtoberfest 的视频记录。这一系列 11 个视频是我能想到的网上最完整的记录。

Youtube: SAP HANA 多模型@ Devtoberfest

此外,我还定期维护一个资源博客,收集围绕 SAP HANA Spatial 的所有社区内容。值得一看,并可能找到这样或那样的宝石:

SAP HANA 空间资源:https://cutt.ly/saphanaspatial

结论

您已经学习了如何将空间数据上传到 SAP HANA 云,并使用 QGIS 对其进行可视化。您还创建了一个 SQL 视图,它在数据库级别应用了一个聚类算法。现在,您应该能够根据自己的空间数据构建自己的空间分析。

您在本博客中看到的是一个技术性很强的演练,旨在快速了解 SAP HANA Spatial。如果您有 GIS 背景,您可能会问,为什么首先要使用 SAP HANA?我所描述的基本任务可以通过任何 GIS 客户端轻松完成,无论有无数据库持久性或空间工作负载的下推。

我想引用我亲爱的同事汤姆·图尔奇奥的话,他概述了在 SAP HANA 上运行 GIS 的主要优势是 生产力、敏捷性、加速和集成 (重点强调集成😊).虽然 Tom 的博客是专门为 Arcg is 定制的,但无论实际的 GIS 客户端是什么,概述的质量都是有效的。

原载于 2021 年 3 月 1 日 https://blogs.sap.com*https://blogs.sap.com/2021/03/01/creating-a-playground-for-spatial-analytics/。***

在 Julia 中创建 Pluto.jl 笔记本阅读器

原文:https://towardsdatascience.com/creating-a-pluto-jl-notebook-reader-in-julia-da1c152db184?source=collection_archive---------26-----------------------

Jockey.jl

逆向工程冥王星笔记本读入我的自定义笔记本会话

(图片由 geralt 在 Pixabay 上提供)

介绍

Pluto.jl 是一个相当新的 IDE 开发,用于处理 Julia 编程语言中的笔记本文件。虽然 Pluto.jl 有一些很棒的功能,但这些功能肯定不符合我的个人偏好——我不是唯一一个这样想的人。我写了一整篇文章,详细介绍了我使用 Pluto.jl 的经历,我喜欢这个包的什么,不喜欢什么,你可以在这里阅读:

然后是海王星。Neptune 是 Pluto.jl 的一个分支,它修改了 Pluto.jl,排除了最初的创建者打算在每个笔记本会话中使用的所有有趣的东西。我最后还写了一篇关于 Neptune.jl 的文章,你可以在这里看到:

我认为 Pluto.jl 和 Neptune.jl 实际上向我展示了这是非常可能的。您可以拥有一台基于 Julia 的笔记本服务器,笔记本服务器提供的所有功能都可以通过 Julia 的全部功能进行定制和发挥。不管你是否使用 Julia,你都必须承认, IJulia 可能不是最好的解决方案。也就是说,所有这一切让我真的想创建自己的笔记本服务器,并在它下面设计自己的应用程序。

在这个项目的发布画布上有很多想法,一旦这个项目实际上处于常规开发阶段并有了可靠的发布,我会有更多的想法。如果你想了解更多关于这个新的 IDE jockey . JL 的信息,你可以在这里查看这个项目的 Github:

https://github.com/ChifiSource/Jockey.jl

还有一件事!在另一篇文章中,我初步研究了这种格式,并创建了一些新的类型来处理这种数据。考虑到这一点,为了给这里的总体目标提供更多的上下文,这可能是值得研究的。

Pluto.jl 文件格式

在我们开始制作文件阅读器之前,我们当然需要了解一下 Pluto.jl 文件格式实际上是如何工作的,我在上一篇讨论 Jockey 的文章中已经这样做了,这就是我所看到的:

(图片由作者提供)

恰当地说,我的反应是对他们实际上是如何做的感到惊讶。今天,我们将尝试读取这种文件格式,并将其放入我们的单元格对象中。像这样一个项目的一个伟大之处在于它需要大量的调试,也就是说,我将在笔记本中编写这些代码。这将使我编写的代码更容易与我所有的读者分享——这是更容易解释的额外好处——因为我不会在文件间跳来跳去。话虽如此,笔记本可在此处获得:

https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/Reading Pluto.jl.ipynb

[emmac@fedora ~]$ cd dev/nbs && jupyter-notebook

我已将 Cd 放入我们的笔记本目录,现在将创建一个新的 Jupyter 会话。不需要包含,因为这里的整个目标是让这些适合我们的类型。我们所需要做的就是读取这些数据的行,并想出某种加载算法来将其转换成我们的新类型。同样的事情也要用. IPYNB 来做,我知道,我明白;目前这有点无聊,但结果值得我们在后端做所有的工作。

总之,我创建了一个新的笔记本——因此,添加了我们的第一点代码。这段代码只是 Jockey Cells.jl 文件中的代码。您可以在 Github 上查看该文件,网址是:

https://github.com/ChifiSource/Jockey.jl/blob/cells_v1/src/ServerController/Cells.jl

using UUIDs, TOMLabstract type AbstractCell end
mutable struct InputCell <: AbstractCell
    ID::UUID
    Text::String
    env::Dict
endmutable struct OutputCell <: AbstractCell
    ID::UUID
    output::String
endmutable struct Cell <: AbstractCell
    input::Cell
    output::Cell
    hidden::Bool
    lang::Symbol
    env::UUID
end

接下来,我将把文件作为字符串读入。

uri = "weird.jl"
input = readlines(uri)

(图片由作者提供)

好消息是这个字符串包含了很多关于 Pluto.jl 文件类型以及为什么使用这种类型的信息。我计划在我自己的版本中使用一些元素,我们还需要考虑这里加载的依赖关系。虽然我不完全确定我们是否需要使用 interact,因为这两个服务器在本质上非常不同,但我们肯定会利用这个 UUID 场。我做了一个新的小函数,可以让我们更详细地看到所有这些工作:

function showsome(x::UnitRange, uri::String)
    f = readlines(uri)
    for i in x
       println(f[i]) 
    end
end

使用这个函数,我可以更好地查看文件中的文本。在我的方法中,我的第一个测试是编写一个函数来获取所有的 UUIDs,我认为这很容易,因为它们肯定有很多特定的字符。

function read_plto(uri::String)
    cells = Dict()
    celluuids = []
    for line in readlines(uri)
        if occursin('╟', line)
            println(line)
        end
    end
endread_plto(uri)

(图片由作者提供)

没什么疯狂的,但是朝着正确的方向迈出了一步。从这里开始,我们需要扫描下一个单元格。当我们点击该单元格时,我们将认为这两个单元格定义之间的所有行都是单元格内容。在我让这个功能工作之后,我要把这个函数提取出来,简单地通过重命名这个方法,然后写另一个调用它的方法。这将有助于保持“功能为步骤”的心态,并使这个包更容易看。下面是我的初始函数:

function read_plto(uri::String)
    # We need file lines for each cell UUID
    cellpos = Dict()
    first = 0
    ccount = 0
    for (count, line) in enumerate(readlines(uri))
        if occursin('╟', line)
            ccount += 1
            if first == 0
                first = count
            else
                push!(cellpos, ccount => first:count)
            end   
        end
    end
    return(cellpos)
end

这个 for 循环很粗糙,但是它可以作为我们需要做的事情的大纲。我们可以让它看起来更好,并在以后改变一些循环语法。首先,我们用 count 枚举我们的读取行。这些行被存储为变量行。变量 first、ccount(单元格计数)和 cellpos(一个字典)都在此之前初始化。我们要做的第一件事是看看这一行是否有 char ‘╟’ 我们之前已经看到这是如何获取所有 UUIDs 的。无论何时找到该行,首先会发生的是填充细胞计数。

这最终是为骑师,因为骑师将有一个关键的 UUID 和他们各自的号码。但是,每个单元格之后可以有不同的行数,这就是范围的来源。该范围将是单元格计数的值对。基本上,我将能够积累哪些线包含哪些环境。让我们快速运行一下:

cellpos = read_plto(uri)

(图片由作者提供)

奇怪。

首先,我们现在知道这个笔记本文件中有 25 个单元格——但是很明显单元格区域是不正确的。第一个也是最明显的错误是如何添加单元计数器。这需要移动到条件中,实际上是计数细胞。这就给了我一个规则有序的字典,它实际上有一个 1 值和类似的东西。然后我意识到我传递的字符只在文件的最底部。很快,我把它改成了包含整个开头的字符串。下面是最终的细胞定位功能:

function read_plto(uri::String)
    # We need file lines for each cell UUID
    cellpos = Dict()
    first = 0
    ccount = 0
    for (count, line) in enumerate(readlines(uri))
        if occursin("# ╔═╡", line)
            if first == 0
                first = count
            else
                ccount += 1
                push!(cellpos, ccount => first:count)
                println(ccount => first:count)
            end   
        end
    end
    return(cellpos)
end

我将把它重命名为 plto_cell_lines()方法,这只是开发人员 API 的一部分,所以除了我之外,没有人真的需要担心它。这将是对提取方法的公然使用,我使用这种方法是为了通过简单地使用更多的函数使我的代码看起来更简洁和漂亮。如果你感兴趣的话,我有一整篇关于这个主题的文章,还有一些做同样事情的其他技术。我认为这些技能对于数据科学工作来说是绝对必要的:

</5-fabulous-refactoring-methods-for-prettier-code-e3bc3447c0b2> [## 更漂亮的代码的 5 个惊人的重构方法

towardsdatascience.com](/5-fabulous-refactoring-methods-for-prettier-code-e3bc3447c0b2)

现在看看每当我运行这个函数时会发生什么:

cellpos = read_plto(uri)

(图片由作者提供)

如此接近…

好消息是,使用我编写的打印函数,我们可以断言第一个值是正确的(因为它从第一个单元格开始,到第二个单元格结束。):

showsome(17:24, uri)

然而,我们需要改变一些事情,因为首先;所有这些细胞都是从 17 开始的,这有点违背了我们的初衷。这只是归结为在使用第一个变量后缺少对它的重新赋值。

if occursin("# ╔═╡", line)
            if first == 0
                first = count
            else
                ccount += 1
                push!(cellpos, ccount => first:count)
                println(ccount => first:count)
                first = count
            end   
        end

我接下来要做的另一件事是,对于被推送到字典的范围,从计数中减去 1。这是因为我们不想包含下一个传入单元的头部。我也不确定这里的输入/输出结构,因为它可能是 8 个输入单元和 8 个输出单元,或者 16 个输入单元——一旦我们使用该算法,我们就会弄清楚所有这些。

cellpos = plto_cell_lines(uri)Dict{Any, Any} with 35 entries:
  5  => 38:40
  16 => 82:85
  20 => 99:103
  35 => 157:161
  12 => 64:68
  24 => 114:116
  28 => 131:133
  8  => 51:53
  17 => 86:88
  30 => 137:139
  1  => 17:23
  19 => 96:98
  22 => 108:110
  23 => 111:113
  6  => 41:43
  32 => 148:150
  11 => 61:63
  9  => 54:57
  31 => 140:147
  14 => 72:78
  3  => 28:30
  29 => 134:136
  7  => 44:50
  25 => 117:120
  33 => 151:153

好像这本字典突然有了新的价值。现在让我们在一个新函数中调用这个函数。

function read_plto(uri::String)

end

我还冒昧地通过查看细胞数据来了解更多的信息。为此,我使用了我们古老的 showsome()方法。幸运的是,它需要一个单位范围,所以我可以按部分查看数据:

showsome(cellpos[1], uri)# ╔═╡ b129ba7c-953a-11ea-3379-17adae34924c
md"# _Welcome to Pluto!_

Pluto is a programming environment for _Julia_, designed to be **interactive** and **helpful**. 

In this introduction, we will go through the basics of using Pluto. To make it interesting, this notebook does something special: it **changes while you work on it**. Computer magic ✨" showsome(cellpos[2], uri)# ╔═╡ 4d88b926-9543-11ea-293a-1379b1b5ae64
md"## Cats
Let's say you're like my grandma, and you have a lot of cats. Our story will be about them."

看完这个材料,我才知道这些都是输入细胞。我认为这很有道理,Pluto.jl 笔记本不是普通的笔记本——它们是主动的,或者说是“被动的”。我认为这绝对是一个很酷的特性和很好的实现,然而像这样的反应式会话确实给研究带来了一些问题。笔记本保存输出是有原因的,那就是为了可复制的代码。我当然同意这可能会导致国家和诸如此类的问题——但我不认为像这样消除产出是必要的。有了对 Pluto.jl 数据格式的新认识,我们可以通过调用新的单元格数据测距仪来继续我们的函数:

function read_plto(uri::String)
    cellpos = plto_cell_lines(uri)
    cells = Array{AbstractCell}()    
end

该过程的最后一步是将所有这些数据适当地放入我们的 Jockey 结构中,并确定我们正在内联处理哪种类型的单元。幸运的是,对于这次阅读,我相信我们将只需要处理输入单元!让我们回头看看我们的类型:

abstract type AbstractCell end
mutable struct InputCell <: AbstractCell
    ID::UUID
    Text::String
    env::Dict
endmutable struct OutputCell <: AbstractCell
    ID::UUID
    output::String
endmutable struct Cell <: AbstractCell
    input::AbstractCell
    output::AbstractCell
    hidden::Bool
    lang::Symbol
    env::UUID
end

现在,我们可以非常容易地创建我们的函数,它将调用我们刚刚编写的函数来获取有效的行位置,以及我们必须编写的一些新函数。看一看:

function read_plto(uri::String)
    cellpos = plto_cell_lines(uri)
    cells = []
    x = readlines(uri)
    for cell in values(cellpos)
        unprocessed_uuid = x[cell[1]]
        text_data = x[cell[2:end]]
        identifier = process_uuid(unprocessed_uuid)
        inp = InputCell(identifier, text_data)
        out = OutputCell(UUIDs.uuid1(), "")
        cl = Cell(inp, out, false, :JL, UUIDs.uuid1())
        push!(cells, cl)
    end
    return(cells)
end

我相信这个新方法会起作用,我们只需要创建一个函数来处理我们的 UUIDs,然后创建另一个函数来处理文本数据——这是比较困难的部分。在我们的第一次尝试中,让我们看看这个 UUID 实际上会是什么样子,这样我们就可以确保正确地分割每个字符串。此外,应该注意的是,输出也被分配了新的 id。

function process_uuid(text::String)
    println(text)
    uuid = UUID(id)
    return(uuid)
end8# ╔═╡ 611c28fa-9542-11ea-1751-fbdedcfb7690

我简单地把这个字符串分成三份,抓住第三个元素,然后把它变成 UUID 类型。

function process_uuid(text::String)
    dims = split(text, ' ')
    uuid = UUID(dims[3])
    return(uuid)
end

结论

我现在意识到我们已经结束了。不需要编写数据算法,因为最终大部分都将由 Java 来处理,无论如何我都需要编写解析器。将数据解析到 Julia 中,然后发送给 JavaScript,再次变得完全无法解析,这是没有用的。首先,我要说——这是一项很好的工作,但我很高兴它完成了。我们现在唯一需要做的就是测试代码:

read_plto("weird.jl")MethodError: Cannot `convert` an object of type InputCell to an object of type Cell
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:205
  Cell(::Any, ::Any, ::Any, ::Any, ::Any) at In[1]:15

有趣的是,我认为我对类型的更改需要内核重启。为了确保这些更改都在这里,下面是更新的类型:

using UUIDs, TOML, Markdownabstract type AbstractCell end
mutable struct InputCell <: AbstractCell
    ID::UUID
    Text::Any
endmutable struct OutputCell <: AbstractCell
    ID::UUID
    output::Any
endmutable struct Cell <: AbstractCell
    input::AbstractCell
    output::AbstractCell
    hidden::AbstractBool
    lang::Symbol
    env::UUID
end

这些当然只是它们未来类型的骨架,但是让我们通过重新运行我的笔记本来解决这个问题。

开始了。

read_plto("weird.jl")

(图片由作者提供)

现在这个问题已经解决了,我已经朝着完成这个计划迈出了重要的一步。然而,仍有大量工作要做。我很兴奋能继续写博客!感谢您的阅读,鉴于这篇文章中有很多很酷的算法内容,我希望它是有帮助的,或者至少是很酷的!在未来,我计划重申这些功能,使它们更流畅,并添加一些文档,但现在我将沉浸在数据加载的荣耀中。谢谢你看我的文章,祝你学习愉快!

用 PyTorch 创建一个强大的新冠肺炎面具检测工具

原文:https://towardsdatascience.com/creating-a-powerful-covid-19-mask-detection-tool-with-pytorch-d961b31dcd45?source=collection_archive---------23-----------------------

快速建立小而精确的图像分类模型的实例研究

马修·韦林在 Unsplash 上的照片

在过去的一年里,新冠肺炎给世界带来了社会、经济和人类的损失。人工智能工具可以识别正确的面具佩戴,以帮助重新打开世界,防止未来的大流行。

当然,这有更深层的社会含义,比如隐私和安全的权衡。这些将在随附的 arXiv 研究论文中讨论。

在这篇文章中,我将带你浏览我们创建的项目。

读完这篇文章,你将有知识创建一个类似的管道,不仅用于遮罩检测,也用于任何类型的图像识别

特征工程

我们的数据集

使用 MaskedFace-Net 和 Flickr Faces 数据集,我们将图像大小调整为 128x128 以节省空间。我们将图像移动到三个文件夹中(train、val 和 test)。每个文件夹都有三个子目录(正确/不正确/无掩码)。这使得他们很容易装载 PyTorch 的火炬视觉。

batch = 16 train_dataset = torchvision.datasets.ImageFolder('./Data_Sample/train', transform = train_transform)val_dataset = torchvision.datasets.ImageFolder('./Data_Sample/val', transform = test_transform)test_dataset = torchvision.datasets.ImageFolder('./Data_Sample/test', transform = test_transform)train_dataset_loader = torch.utils.data.DataLoader(
train_dataset, batch_size=batch, shuffle=True)val_dataset_loader = torch.utils.data.DataLoader(
val_dataset, batch_size=batch, shuffle=True)test_dataset_loader = torch.utils.data.DataLoader(
test_dataset, batch_size=batch, shuffle=False)

如果您查看代码片段,您会发现我们使用了 torchvision 的内置参数来对我们的图像进行转换。

对于所有数据,我们将图像转换为张量,并使用一些标准值对其进行归一化。对于训练和验证数据,我们应用了额外的转换。例如,随机对图像进行重新着色、调整大小和模糊处理。这些是应用于每一批的,意味着模型试图学习一个移动目标:每次应用不同噪声的训练图像。

import torchvision.transforms as transformstest_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

变换使您的模型规范化,使其更好地一般化。因此,它将在真实世界的数据上表现得更好。

基线模型

对于像实时图像分类这样的目标,准确性和速度都是关键。这些通常有一个权衡,因为较大的模型可能具有较高的准确性。为了获得基线,我们从应用更快的机器学习模型开始。

好家伙,我们会大吃一惊的!我们意识到,我们的数据集使用合成模型使得预测变得有些琐碎。在时间压力下,并且在我们使用的 180,000 张图像附近没有数据集,我们继续研究如何进一步提高性能

基线模型精度

对于这些更简单的模型,我们使用 LeakyReLU 和 AdamW 训练了 scikit-learn 的随机森林、cv2 的 Haar 级联分类器和自定义 CNN。

高级模型

接下来,我们开始使用最先进的模型。顶级研究人员使用数百万美元的计算来训练和微调这些模型。对于一般问题,它们往往工作得最好。

我们可以用我们的数据训练它们,看看它们在我们的面具分类任务中表现如何。这种转移学习比从头开始训练要快得多,因为权重已经接近最优。我们的训练会使他们变得更好。

下面的函数用于不同的 torchvision 模型,看看它们的性能如何。

# Takes the model and applies transfer learning
# Returns the model and an array of validation accuracies
def train_model(model, dataloaders, optimizer, criterion, scheduler, device, num_epochs=20):
 startTime = time.time()
 top_model = copy.deepcopy(model.state_dict())
 top_acc = 0.0 for epoch in range(num_epochs): for data_split in ['Train', 'Validation']: if data_split == 'Train':
    scheduler.step()
    model.train() else:
    model.eval() # Track running loss and correct predictions
   running_loss = 0.0
   running_correct = 0 # Move to device
   for inputs, labels in dataloaders[data_split]:
    inputs = inputs.to(device)
    labels = labels.to(device) # Zero out the gradient
    optimizer.zero_grad()# Forward pass
   # Gradient is turned on for train
    with torch.set_grad_enabled(data_split == "Train"):
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    _, preds = torch.max(outputs, 1)
    if data_split == "Train":
     loss.backward()
     optimizer.step()
    # Update running loss and correct predictions
    running_loss += loss.item() * inputs.size(0)
    running_correct += torch.sum (labels.data == preds)

   epoch_loss = running_loss / dataloader_sizes[data_split]
   epoch_acc = running_correct.double() / dataloader_sizes[data_split]
   print('{} Loss: {:.2f}, Accuracy: {:.2f}'.format(data_split,     epoch_loss, epoch_acc))
   # If this the top model, deep copy it
   if data_split == "Validation" and epoch_acc > top_acc:
   top_acc = epoch_acc
   top_model = copy.deepcopy(model.state_dict()) print("Highest validation accuracy: {:.2f}".format(top_acc)) # Load best model's weights
 model.load_state_dict(top_model)
 return model;

由于我们的重点是速度,我们选择了四个较小但性能良好的神经网络,并取得了以下结果:

迁移学习模型的准确性

大幅提升!但是我们能做得更好吗?

蒸馏

这是的第一步。

Jan Ranft 在 Unsplash 上拍摄的照片

蒸馏是一项前沿技术,它训练更小的模型来做出更快的预测。它从网络中提取知识。这非常适合我们的用例。

在蒸馏中,你从教师模型中训练学生。不是根据你的数据训练你的模型,而是根据另一个模型的预测训练它。因此,您可以用更小的网络来复制结果。

蒸馏的实施可能具有挑战性且需要大量资源。幸运的是, KD_Lib for PyTorch 提供了可作为库访问的研究论文的实现。下面的代码片段用于香草蒸馏。

import torchimport torch.optim as optimfrom torchvision import datasets, transforms
from KD_Lib.KD import VanillaKD# Define models
teacher_model = resnet
student_model = inception# Define optimizers
teacher_optimizer = optim.SGD(teacher_model.parameters(), 0.01)
student_optimizer = optim.SGD(student_model.parameters(), 0.01)# Perform distillation
distiller = VanillaKD(teacher_model, student_model, train_dataset_loader, val_dataset_loader,
teacher_optimizer, student_optimizer, device = 'cuda')
distiller.train_teacher(epochs=5, plot_losses=True, save_model=True)
distiller.train_student(epochs=5, plot_losses=True, save_model=True)
distiller.evaluate(teacher=False)
distiller.get_parameters()

在我们的 DenseNet 模型上使用香草蒸馏,我们用我们的基线 CNN 达到了 99.85%的准确率。在 V100 上,CNN 以每秒 775 次推理的速度超过了所有最先进型号的速度。CNN 用 15%的参数做到了这一点。

更加赫然, 再次运行蒸馏继续提高精度。例如,NoisyTeacher、SelfTraining 和 MessyCollab 的组合提高了结果。

边注: 自我训练 把你的模型既当老师又当学生,多爽!

结束语

创建一个正确使用面具的分类器既及时又紧迫。

构建这条管道的课程对你想做的任何图像分类任务都是有用的。希望这个管道有助于理解和解决你想要做的任何图像分类任务。祝你好运!

相关论文:【https://arxiv.org/pdf/2105.01816.pdf】

相关演示:https://www.youtube.com/watch?v=iyf4uRWgkaI

掩模分类器(单独的 YOLOv5 管道,在纸中)

用 GradioML 创建一个简单的机器学习演示

原文:https://towardsdatascience.com/creating-a-simple-image-classification-machine-learning-demo-with-gradioml-361a245d7b50?source=collection_archive---------7-----------------------

只需几行代码就可以在功能性用户界面中部署模型

作者图片

部署机器学习模型有时是数据科学中被忽视的一个方面。许多分析专业人员将大部分注意力集中在理论和应用上,以构建能够解决问题和满足目标的模型。这在项目的研究或原型阶段都是完全没问题的。但是,为了与其他职业的利益相关者或合作者分享这项工作,为这些用户和观众开发某种应用程序会很好。

然而,部署这些模型的任务并不总是那么简单。要完成这项工作,还需要掌握许多额外的技能和工具。传统上,机器学习工程师和 DevOps 专家等专家与数据科学家合作,将这些模型投入生产。

有时,一个简单的用户界面演示可以完成传达机器学习模型内容的工作,而不是全力以赴进行部署。在寻找可以帮助构建这个的工具时,我偶然发现了 GradioML ,一个符合这种描述的开源工具。

Gradio 是一个软件包,允许用户用几行代码创建简单的网络应用。它的基本用途与 Streamlight 和 Flask 相同,但使用起来更简单。许多类型的网络界面工具可以选择,包括画板,文本框,文件上传按钮,网络摄像头等。使用这些工具接收各种类型的数据作为输入,可以很容易地演示分类和回归等机器学习任务。(参考工具见官网及其 Github 页面)

在本演练中,我们将快速创建一个猫/狗图像分类模型,并部署一个简单的 Gradio 演示程序,我们可以在其中上传新图像以进行分类预测。该模型将是一个简单的 Keras 卷积神经网络(CNN) ,它将在作为特征的猫和狗的图像上进行训练,并将它们的类名作为标签。

有关 Jupyter 笔记本的完整代码,请参考此链接

必需品;要素

首先我们安装 Gradio

pip install gradio

接下来,我们导入依赖项。我们需要的一些工具将用于数值计算(Numpy)可视化/绘图(Matplotlib)图像数据争论(cv2)深度学习 (Tensorflow,Keras),当然还有构建 web 界面 (Gradio)

import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
import os
import cv2from sklearn.model_selection import train_test_split
from sklearn import metricsimport tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2Dimport gradio
import gradio as gr 

浏览和组织数据

然后我们看一下我们的数据。猫/狗图像来自发布在 Kaggle 中的数据集来源。我们将检查第一张图片

DATADIR = os.path.abspath(os.getcwd()) + '/PetImages'path = os.path.join(DATADIR, category)    #path to cats or dogs dir
first_img_path = os.listdir(path)[0]
img_array = cv2.imread(os.path.join(path, first_img_path), cv2.IMREAD_GRAYSCALE)
plt.imshow(img_array, cmap = "gray")
plt.show()#show image shape
print('The image shape is {}'.format(img_array.shape))

作者图片

因为这个练习是针对一个简单的 CNN 模型,我们将调整所有图像的大小为 shape (100,100 ),并将它们的颜色改为灰度。

要素和标注也将被分离并分别添加到列表 X 和 y 中

#create create array of data
data = []
def create_data():
    for category in CATEGORIES:
        path = os.path.join(DATADIR, category)  
        class_num = CATEGORIES.index(category)    
        for img in os.listdir(path):
            try: 
                img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE)
                new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))data.append([new_array, class_num])
            except Exception as e:
                pass
create_data()#randomly shuffle the images
random.shuffle(data)#separate features and labels
X = []
y = []for features, label in data:
    X.append(features)
    y.append(label)#neural network takes in a numpy array as the features and labels so convert from list to array and change shape
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
y = np.array(y)

调整后的特征图像示例如下所示

#show first feature image X
first_feature = X[0]
plt.imshow(first_feature, cmap = 'gray')
print('The image shape is {}'.format(first_feature.shape))

作者图片

最后,我们归一化图像以确保每个像素具有相似的数据分布(在训练卷积神经网络模型时允许更快的收敛)

#normalize images
X = X/255.0

建模

这里我们将训练(70%)和测试(30%)数据分开。总共会有 17462 个训练数据和 7484 个测试数据。

#separate training and test data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)print('the shape of training features is {}'.format(X_train.shape))
print('the shape of training labels is {}'.format(y_train.shape))print('the shape of test features is {}'.format(X_test.shape))
print('the shape of test labels is {}'.format(y_test.shape))

作者图片

我们现在创建我们的卷积神经网络(CNN)模型。它将由多个卷积层、最大池层和下降层组成。卷积层中的所有激活函数将是 relu,而输出密集层的激活函数将是 softmax。

#create model
model = Sequential()model.add(Conv2D(64, (3,3), activation = 'relu'))
model.add(MaxPooling2D(2,2))
model.add(Dropout(0.1))model.add(Conv2D(64, (3,3), activation = 'relu'))
model.add(MaxPooling2D(2,2))
model.add(Dropout(0.2))model.add(Conv2D(64, (3,3), activation = 'relu'))
model.add(MaxPooling2D(2,2))
model.add(Dropout(0.2))model.add(Flatten())model.add(Dense(128, input_shape = X.shape[1:], activation = 'relu'))#output layer
model.add(Dense(2, activation = 'softmax'))

使用以下参数编译模型:

#compile the model
model.compile(loss="sparse_categorical_crossentropy",
             optimizer="adam",
             metrics=['accuracy'])

使用 5 个时期和 0.1 的验证分割来训练模型

#fit model
history = model.fit(X_train, y_train, epochs=5, validation_split=0.1)

用 5 个时期训练模型:作者的图像

#show learning curves
#mean training loss and accuracy measured over each epoch
#mean validation loss and accuracy measured at the end of each epochpd.DataFrame(history.history).plot(figsize=(8,5))
plt.grid(True)
plt.gca().set_ylim(0,1) # set the vertical range to [0-1]
plt.show()

学习曲线;培训与验证:作者提供的图片

该模型似乎没有过度拟合训练数据,因为在训练和验证准确性/损失之间没有相当大的差距。验证精度略高于使用脱落图层时可能出现的训练精度。

我们预测测试数据的类别,并比较我们的准确度

#use predict_classes() to find the class with the highest probability
y_pred = model.predict_classes(X_test)print("Performance Summary of Sequential Neural Network on test data:")#show classification report
print(metrics.classification_report(y_test, y_pred))#show confusion matrix
print(metrics.confusion_matrix(y_test, y_pred))

分类报告和混淆矩阵:作者图片

虽然不令人惊讶,但在测试数据的 83%的总体准确率下,这是一个相当不错的模型

我们可以快速浏览前 5 个正确和不正确的分类

#show first 5 correctly identified test images with predicted labels and probabilities
fig, ax = plt.subplots(1,5,figsize=(20,20))class_names = ["Dog", "Cat"]for i, correct_idx in enumerate(correct_indices[:5]):
    ax[i].imshow(X_test[correct_idx].reshape(100,100),cmap='gray')
    ax[i].set_title("{} with probabililty of {}%".format(class_names[y_pred[correct_idx]], int(max(y_proba[correct_idx]

前 5 张正确识别的图片:作者图片

#show first 5 incorrectly identified test images with predicted labels and probabilities
fig, ax = plt.subplots(1,5,figsize=(20,20))for i, incorrect_idx in enumerate(incorrect_indices[:5]):
    ax[i].imshow(X_test[incorrect_idx].reshape(100,100),cmap='gray')
    ax[i].set_title("{} with probabililty of {}%".format(class_names[y_pred[incorrect_idx]], int(max(y_proba[incorrect_idx])*100)))

前 5 张识别错误的图片:作者图片

有趣的是,该模型已经正确识别了一些甚至人类都难以看到的图像。但是,它也错误地识别了一些明显的猫和狗的图片。

使用 Gradio 的模型演示

最后,我们准备使用 Gradio 来创建我们模型的演示。同样,目的是使用该模型在新上传的输入图像上预测猫或狗类别

#create a function to make predictions
#return a dictionary of labels and probabilities
def cat_or_dog(img):
    img = img.reshape(1, 100, 100, 1)
    prediction = model.predict(img).tolist()[0]
    class_names = ["Dog", "Cat"]
    return {class_names[i]: prediction[i] for i in range(2)}#set the user uploaded image as the input array
#match same shape as the input shape in the model
im = gradio.inputs.Image(shape=(100, 100), image_mode='L', invert_colors=False, source="upload")#setup the interface
iface = gr.Interface(
    fn = cat_or_dog, 
    inputs = im, 
    outputs = gradio.outputs.Label(),
)iface.launch(share=True)

这段代码中发生了以下情况:

  1. 我们首先创建一个名为 cat_or_dog()的函数,它将一个图像数组作为输入,利用模型进行预测,并返回一个字典,其中每个类名作为键,其各自的概率作为值(例如{Dog: 0.6,Cat: 0.4})
  2. 设置输入上传:转换输入图像以匹配模型被训练的输入形状,在我们的例子中是(100,100)。我们还将源设置为“上传”,这样我们就可以将自己的图像上传到 Gradio 中
  3. 编译接口;利用我们在上面创建的 cat_or_dog()函数,将 input 设置为输入上传器,并允许 Gradio 返回类及其概率作为输出

结果显示在下面的 gif 中:

Gradio 图像分类演示:按作者分类的图像

用户可以轻松地从本地拖放或上传图像,并单击“提交”以显示模型分类的输出。概率较高的类别(猫或狗)将显示为最终预测。

结论

在本练习中,使用 CNN 构建了一个影像分类模型,并使用一个名为 GradioML 的工具将其部署为一个简单的演示。然而,Gradio 可以用于更多的任务,如回归/数值预测和自然语言处理。Gradio 具有适合这些任务的各种界面选项,是一种可以作为呈现快速机器学习演示的快速高效解决方案的工具。

用 leav 和 Python 创建一个简单的地图

原文:https://towardsdatascience.com/creating-a-simple-map-with-folium-and-python-4c083abfff94?source=collection_archive---------1-----------------------

如何获得自行车租赁位置数据,创建一个简单的地图,并在 Python 中使用 Folium 为每个位置添加点。

由卡尔文·汉森在 Unsplash 拍摄的照片

通常,在处理数据时,您可以访问地理空间要素,如纬度和经度坐标。绘制这些图会很有趣,可以了解数据集的实例是如何分布在不同位置的。

在这篇短文中,我介绍了获取自行车租赁位置数据并在地图上显示这些位置的步骤。我使用 Dublin Bikes 数据(https://data.smartdublin.ie/dataset/dublinbikes-api)和叶库(https://python-visualization.github.io/folium/),正如文档所说,“建立在 Python 生态系统的数据角力优势和leaflet.js库的映射优势之上”。有关传单的更多信息,请参见此处的文档。

要求

我用的是 Python 3.7,叶子 0.12.1,熊猫 1.2.4。我也在 Anaconda Navigator 中使用 Jupyter 笔记本。

数据

我正在处理的数据来自都柏林自行车应用编程接口,特别是自行车租赁站的位置:

[https://data.smartdublin.ie/dataset/33ec9fe2-4957-4e9a-ab55-c5e917c7a9ab/resource/2dec86ed-76ed-47a3-ae28-646db5c5b965/download/dublin.csv](https://data.smartdublin.ie/dataset/33ec9fe2-4957-4e9a-ab55-c5e917c7a9ab/resource/2dec86ed-76ed-47a3-ae28-646db5c5b965/download/dublin.csv)

步骤 1-进口熊猫和叶子

和往常一样,第一步是导入库:

import pandas as pd
import folium

步骤 2-获取自行车站点位置并保存到熊猫数据框

使用 Pandas,我可以直接找到我想要的 CSV 文件的位置:

location = "[https://data.smartdublin.ie/dataset/33ec9fe2-4957-4e9a-ab55-c5e917c7a9ab/resource/2dec86ed-76ed-47a3-ae28-646db5c5b965/download/dublin.csv](https://data.smartdublin.ie/dataset/33ec9fe2-4957-4e9a-ab55-c5e917c7a9ab/resource/2dec86ed-76ed-47a3-ae28-646db5c5b965/download/dublin.csv)"bike_station_locations = pd.read_csv(location)

现在我有了自行车 _ 车站 _ 位置数据框架:

步骤 3 —仅保留我需要的列

我想保留位置的纬度经度名称。前两列将允许我映射位置,后一列将用于为每个位置引脚命名:

bike_station_locations = bike_station_locations[["Latitude", "Longitude", "Name"]]

步骤 4-创建地图

对于地图,第一步是创建一个我想要的位置的地图。使用位置参数,我传入纬度和经度坐标的平均值,我必须将地图放在那里。

map = folium.Map(location=[bike_station_locations.Latitude.mean(), bike_station_locations.Longitude.mean()], zoom_start=14, control_scale=True

这将给出一张空白地图,以先前给出的位置为中心,缩放至 14。

步骤 5-向地图添加点

现在,我将每个自行车站位置的点添加到地图上。遍历数据帧的每一行,我将位置纬度和经度传递给叶子。标记为列表,并将名称传递给 popup 参数。对于我添加到地图上的每个位置:

for index, location_info in bike_station_locations.iterrows():
    folium.Marker([location_info["Latitude"], location_info["Longitude"]], popup=location_info["Name"]).add_to(map)

然后我显示地图:

注意:默认情况下,地图使用 OpenStreetMap 切片,尽管在创建地图时可以通过添加参数切片参数和值来使用其他选项。这里的文档里有例子。

更多关于 OpenStreetMap 的信息,可以在这里找到。

结论

将 flour 与 Python 结合使用是开始绘制地理空间数据的一个很好的方式。只需几行代码,就可以组合出基本的地图。还有许多其他选项可用,文档也非常值得研究。

Jupyter 笔记本可用此处。

所有截图均为作者拍摄。由 Calvin Hanson 在 Unsplash 上制作的介绍性图片。

创造一个像你一样说话的智能聊天机器人

原文:https://towardsdatascience.com/creating-a-smart-chat-bot-that-talks-like-you-79bb700b288f?source=collection_archive---------19-----------------------

一种创建具有 RNN 编码解码器和预训练单词嵌入的聊天机器人的有效方法

来自 Pexels 的 Andrea Piacquadio 的照片

介绍

在这篇文章中,描述了一种创建聊天机器人的方法,该聊天机器人具有预训练的单词嵌入和具有编码器-解码器架构的递归神经网络。单词嵌入是预先训练的,这意味着它们不需要学习,而是简单地从文件加载到网络中。为了学习聊天机器人对某个请求的响应,实现了一个编码器-解码器网络。聊天机器人是使用 TensorFlow 和 Keras API 一起创建的。在本文中,您可以了解这些概念,以及如何使用它们来创建像您一样说话的聊天机器人。

应用人工智能技术简介

由于在这种方法中使用了单词嵌入,所以提供了对这种 AI 技术的以下简短介绍:单词嵌入是用实数来描述或表示某个单词的向量。通常,向量的大小为 50 到 300 个元素。在本文所示的例子中,每个单词都由一个 300 维向量表示。这个向量可以用作神经网络的输入。这就是为什么用字母书写的单词不会被输入到神经网络中,而是将其表示为单词嵌入。通过处理大量数据来学习单词嵌入(例如,某种语言的所有维基百科文章都可以用于此目的)。单词的单词嵌入是基于其上下文,即围绕它的单词来学习的。因此,具有相似上下文的单词具有相似的单词嵌入。由于训练这样的单词嵌入需要很大的努力和大量的数据,所以使用预训练的单词嵌入。由于需要用于特定语言的单词嵌入,所以应该确定用于期望语言的预训练单词嵌入的可用性。对于本文中描述的示例,使用了德语和德语单词嵌入的训练数据。这些可以在 deepset(https://deepset.ai/german-word-embeddingss,感谢 deepset 创造了单词 embedding 并让我使用它们)找到,并且是用德语维基百科的 GloVe 算法生成的。关于 GloVe 算法的详细描述和更多信息可以在[1]中找到。在本文中,您可以学习如何使用这种预先训练好的单词嵌入。这个过程被称为迁移学习,因为我们使用已经学习的向量,并且在训练过程中不改变它们。关于单词嵌入的更多信息可以在[2]中找到。

本文中另一项重要的人工智能技术是递归神经网络。递归神经网络通常用于处理数据序列。例如天气数据序列(30 天内每天的温度)或股票数据(一年内股票的每日价格)。递归神经网络可以输出单个值或另一个序列。在天气数据的情况下,这可以是未来 30 天的预测温度,或者对于股票数据,这可以是第二天股票的预期价格。主要有两种不同类型的单元用于构建递归神经网络:LSTMs(长短期记忆)和 GRUs(门控递归单元)。它们都有一个共同点,即它们计算一个内部状态,这个状态从一个 LSTM 或 GRU 单元传递到下一个。在本文展示的例子中,将使用 LSTMs。然而,所描述的方法也应该适用于 GRUs。LSTMs 首先由 Sepp Hochreiter 和 Jürgen Schmidthuber 提出。你可以找到更多关于他们的信息。gru 可以被视为 LSTMs 的简单版本。你可以在[4]中得到关于它们的进一步信息。

在下面的例子中,序列是对聊天机器人的请求。这个请求被分成几个单词。因此,该序列由几个单个单词组成。递归神经网络的输出序列是聊天机器人的响应。由于请求和响应不具有相同的字数,所以使用循环网络的特殊结构。这种架构被称为编码器-解码器网络。尽管这种方法最初是为语言翻译设计的,但它也适用于本文描述的情况。

编码器-解码器网络最初是在[5]中引入的,用于将英语句子翻译成法语。可以找到类似的方法[4]。基本上,我们在这个架构中有两个循环网络。第一个循环网络称为编码器。它将输入序列编码成内部状态,将其表示为固定长度的向量。该状态被用作第二递归网络(解码器)的初始状态。解码器的输出被馈送到具有 softmax 激活功能的简单神经网络。该神经网络的输出是由 softmax 激活函数在输出序列中的每个单词的整个词汇表上创建的概率分布。本文稍后将对此进行更详细的解释。

获取培训数据

因为我们希望聊天机器人像你一样说话,所以需要一些包含与你对话的训练数据。来自 messenger 应用程序的聊天协议是一个很好的来源。通常,您可以将聊天协议导出为 CSV 文件。这些 CSV 文件需要进行处理,以便有对您的请求和来自您的相应响应。请求是编码器-解码器网络的输入,而响应是预期的输出。因此,需要两个数组——一个包含请求(x_test_raw ),一个包含相应的响应(y_test_raw)。这些数组需要预处理,以便删除或替换任何标点符号、大写字母和特殊字符。

在下面的代码片段中,您可以看到如何预处理 CSV 文件以获取训练数据:

x_train_raw = []
y_train_raw = []

with open("drive/MyDrive/messages.csv") as chat_file:
  first_line = True
  is_request = True
  last_request = ""
  csv_chat_file = csv.reader(chat_file)
  for row in csv_chat_file:
    if first_line:
      first_line = False
      continue
    else:
      if row[CSV_IS_OUTGOING_ROW_INDEX] == "0":
        last_request = row[10]
        is_request = True
      if row[CSV_IS_OUTGOING_ROW_INDEX] == "1" and is_request:
        x_train_raw.append(re.sub(r"[^a-zäöüß ]+", "", last_request.lower()))
        y_train_raw.append(re.sub(r"[^a-zäöüß ]+", "", row[10].lower()))
        is_request = False

嵌入层和词汇表

为了实现单词嵌入,Keras API 提供了一个嵌入层。预训练的单词嵌入被加载到这个嵌入层中。这种方法被称为迁移学习,因为我们使用已经学会的单词嵌入。单词嵌入保存在文本文件中。因此,需要从该文件中加载单词 embedding,对其进行处理,使其符合 Keras 的预期数据结构,并将其加载到嵌入层中。随着单词嵌入的加载,需要定义词汇表。为了定义词汇表,创建了一个 Python 字典,其中包含每个单词的索引作为值,单词本身作为键。稍后将使用该字典将我们的训练数据转换成数组,该数组包含每个单词的索引,而不是书写单词的索引。嵌入层使用该索引来查找相应的单词嵌入。以下特殊单词也需要放入词汇表中:

这些的目的将在本文中进一步解释。

以下代码片段显示了如何从文件中加载单词嵌入,以及如何创建词汇表的字典:

word_embeddings = {}
word_index = {}

#Add special words to vocabulary
word_index[PAD_TOKEN] = PAD_INDEX
word_index[START_TOKEN] = START_INDEX
word_index[UNKNOWN_TOKEN] = UNKNOWN_INDEX

word_embeddings[PAD_TOKEN] = [0.0] * 300
word_embeddings[START_TOKEN] = [-1.0] * 300
word_embeddings[UNKNOWN_TOKEN] = [1.0] * 300

index = VOCAB_START_INDEX

with open("drive/MyDrive/vectors.txt") as vector_file:
  for line in vector_file:
    word, embedding = line.split(maxsplit=1)
    embedding = np.fromstring(embedding, sep=" ")
    word_embeddings[word] = embedding
    word_index[word] = index
    index += 1
    if index == VOCAB_SIZE:
      break

因为不希望加载整个文件,所以当达到词汇表中定义的单词数时,加载停止。由于单词是按照它们出现的频率排序的,所以只能加载一定数量的单词;例如前 20,000 个单词。因此,对于本文描述的情况,德语维基百科中最常见的 20,000 个单词被定义为我们的词汇表。

从文件中加载单词嵌入后,需要将其加载到 Keras 的嵌入层中。您可以在下面的代码片段中看到这一部分:

embedding_matrix = np.zeros((VOCAB_SIZE, embedding_dim))

for word, index in word_index.items():
  word_embedding = word_embeddings[word]
  embedding_matrix[index] = word_embedding

embedding_layer = Embedding(VOCAB_SIZE, 
                            embedding_dim,
                            embeddings_initializer=Constant(embedding_matrix),
                            trainable=False,
                            mask_zero=True,
                            name="embedding")

重要的是,可训练设置为假。否则,单词嵌入将在训练期间被改变,这是不期望的,因为它们已经被训练过了。另一个重要的参数是 mask_zero=True。此参数用索引零屏蔽单词,因此它不用于训练。索引为零的单词是特殊单词“”,用于填充。如何做到这一点,将在下一节中解释。

准备培训数据

一旦定义了词汇表,就可以最终处理训练数据,以便将其用于训练。为此,两个数组(x_test_raw 和 y_test_raw)中的每个单词都被替换为词汇表中相应的索引。由于编码器和解码器输入都需要固定的长度,所以字数高于输入大小的句子会被截断,而字数较少的句子会被填充。为此,使用了索引为零的特殊单词“”。在训练期间,预期输出也必须输入到解码器中,从而必须对其进行修改。为此,采用数组 y_test,其中的每一句都移动一位,并将索引“”插入到每一句的第一个元素中。如果在我们的词汇表中找不到一个单词,我们就用“”作为索引。由于解码器网络的响应不是索引数组,而是包含词汇表中每个单词的下一个单词的概率的向量,因此训练数据需要进一步转换。为此,可以使用 Keras API 函数 to _ categorical()。这个函数从带有索引的数组中生成一个一次性编码的向量。

def sentences_to_index(sentences, sentenc_length):
  sentences_as_index = np.zeros((len(sentences), sentenc_length), dtype=int)
  tmp_sentences_index = 0
  tmp_word_index = 0
  unknown_count = 0
  for sentence in sentences:
    words = sentence.split(" ")
    for word in words:
      current_word_index = word_index.get(word)
      if tmp_word_index == sentenc_length - 1:
        break
      if current_word_index != None:
        sentences_as_index[tmp_sentences_index, tmp_word_index] = current_word_index
      else:
        sentences_as_index[tmp_sentences_index, tmp_word_index] = UNKNOWN_INDEX #Word is not in vocabulary, use the index of the unkown toke
        unknown_count += 1
      tmp_word_index += 1
    tmp_sentences_index += 1
    tmp_word_index = 0
  print("Unknown count: " + str(unknown_count))
  return sentences_as_index

x_train_encoder = sentences_to_index(x_train_raw, MAX_INPUT_SENTENC_LENGTH)
y_train = sentences_to_index(y_train_raw, MAX_OUTPUT_SENTENC_LENGTH)
x_train_decoder = np.roll(y_train, 1)
x_train_decoder[:,0] = START_INDEX
y_train = to_categorical(y_train, num_classes=VOCAB_SIZE)

定义模型

在创建了嵌入层并将单词 embedding 加载到其中之后,就可以定义模型了。在这种方法中,需要三个模型。一个模型是将用于训练聊天机器人的训练模型。另外两个模型用于在训练完成后获得聊天机器人的响应。它们被称为推理模型。所有模型共享相同的层。因此,推理模型使用在训练期间学习的层的权重。首先,查看所需层的创建是有帮助的:

#Define the layers of the encoder
encoder_input = Input(shape=(MAX_INPUT_SENTENC_LENGTH), name="encoder_input")
encoder_lstm = LSTM(LSTM_UNITS_NUMBER, return_state=True, name="encoder_lstm")

#Connect the layers of the encoder
encoder_input_embedded = embedding_layer(encoder_input)
_, state_h, state_c = encoder_lstm(encoder_input_embedded)
encoder_state = [state_h, state_c]

#Define the layers of the decoder
decoder_input = Input(shape=(MAX_OUTPUT_SENTENC_LENGTH), name="decoder_input")
decoder_state_input_h = Input(shape=(LSTM_UNITS_NUMBER,), 
                              name="decoder_state_h_input")
decoder_state_input_c = Input(shape=(LSTM_UNITS_NUMBER,), 
                              name="decoder_state_c_input")
decoder_state_input = [decoder_state_input_h, decoder_state_input_c]
decoder_lstm = LSTM(LSTM_UNITS_NUMBER, 
                    return_sequences=True, 
                    return_state=True, 
                    name="decoder_lstm")
decoder_dense = Dense(VOCAB_SIZE, activation='softmax', name="decoder_dense")

#Connect the layers of the decoder
decoder_input_embedded = embedding_layer(decoder_input)
decoder_output, _, _ = decoder_lstm(decoder_input_embedded,
                                     initial_state=encoder_state)
decoder_output = decoder_dense(decoder_output)

为了更好地理解不同的层,体系结构如下图所示:

图 1:RNN 编码器-解码器网络的架构。作者创造的形象。

如图 1 所示,嵌入层是编码器模型和解码器网络的第一层。相同的嵌入层可以用于编码器和解码器网络,因为二者使用相同的词汇。嵌入层的输出被馈送到编码器网络,该网络包括具有 1024 个单元的 LSTM 层。return_state 设置为 True 很重要,因为该状态是解码器网络的必要输入。因此,编码器网络的状态作为初始状态被传递到解码器网络中。此外,解码器网络接收预期的输出序列作为输入。解码器网络的最后一层是具有 softmax 激活功能的密集层。这个密集层提供了词汇表中每个单词下一个出现的概率。因此,密集层的输出具有我们的最大输出句子长度的大小,并且对于句子中的每个元素,分别具有词汇的大小。

创建并连接所有层后,我们可以定义我们的训练模型,如下面的代码片段所示:

#Define the training model
training_model = Model([encoder_input, decoder_input], decoder_output)

图 2:培训模型的架构。作者创造的形象。

在图 2 中,显示了训练模型的结构图。该图表是在 Keras 函数 plot_model 的帮助下创建的。

由于在训练期间需要将目标句子作为输入提供给解码器,因此变量 decoder_input 是训练模型输入的一部分。

最后,创建了两个推理模型——编码器模型和解码器模型,如下面的代码片段所示:

#Define the encoder model
encoder_model = Model(encoder_input, encoder_state)

#Define the decoder model
decoder_output, state_h, state_c = decoder_lstm(decoder_input_embedded, 
                                                initial_state=decoder_state_input)
decoder_state = [state_h, state_c]
decoder_output = decoder_dense(decoder_output)
decoder_model = Model([decoder_input] + decoder_state_input, 
                      [decoder_output] + decoder_state)

编码器模型和解码器模型的结果结构分别如图 3 和图 4 所示。

图 3:编码器模型的架构。作者创造的形象。

图 4:解码器模型的架构。作者创造的形象。

训练模型

一旦定义了培训模型并且我们的培训数据准备好了,培训就可以开始了。以下代码片段显示了培训:

training_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
training_model.fit(x=[x_train_encoder, x_train_decoder], y=y_train, epochs=40)training_model.fit(x=[x_train_encoder, x_train_decoder], y=y_train, epochs=40)

经过 40 个时期的训练后,模型 s 的输出与训练数据的匹配精度约为 95%,这已经相当不错了。

使用推理模型

既然训练已经完成,推理模型终于可以用来和聊天机器人对话了。为此,首先将请求传递到编码器模型中,以计算内部状态。由于预期输出不可用,如在训练期间,用作编码器输入的目标序列仅由特殊单词“”组成。这个目标序列与计算出的编码器状态一起被传递到解码器模型中,以计算我们的响应的第一个字。当密集层为词汇表中的每个单词计算概率时,选择概率最高的单词。此后,根据解码器输出的状态更新初始状态,并根据该输出提供的第一个字更新目标序列。重复此操作,直到达到每个句子的最大字数,或者计算出的单词为“”。结果是一个列表,其中包含为响应中的每个单词计算的索引。最后,索引必须被翻译回文字,以获得聊天机器人的响应。

下面的代码片段显示了如何使用推理模型:

def talk_with_chat_bot(request):
  x_test_raw = []
  x_test_raw.append(request)
  x_test = sentences_to_index(x_test_raw, MAX_INPUT_SENTENC_LENGTH)
  state = encoder_model.predict(x_test)

  target_seq = np.zeros((1, MAX_OUTPUT_SENTENC_LENGTH))
  target_seq[0, 0] = START_INDEX

  output_index = []
  chat_bot_response = ""

  for i in range(MAX_OUTPUT_SENTENC_LENGTH-1):
    output_tokens, state_h, state_c  = decoder_model.predict([target_seq] + state)
    predicted_word_index = np.argmax(output_tokens[0, i, :])
    output_index.append(predicted_word_index)
    if predicted_word_index == PAD_INDEX:
      break
    target_seq[0,i+1] = predicted_word_index
    state = [state_h, state_c]

  for output_token in output_index:
    for key, value in word_index.items():
        if value == output_token \
          and value != PAD_INDEX \
          and value != UNKNOWN_INDEX:
          chat_bot_response += " " + key

  print("Request: " + request)
  print("Response:" + chat_bot_response)

talk_with_chat_bot("wo sollen wir uns treffen")
talk_with_chat_bot("guten tag")
talk_with_chat_bot("wie viel uhr treffen wir uns")

结果

聊天机器人用合理的句子和良好的语法进行回答,如聊天机器人的以下输出所示。对于不熟悉德语的人,括号中提供了翻译:

Request: wo sollen wir uns treffen (where should we meet)
Response: am haupteingang (at the main entrance)
Request: guten tag (good day)
Response: hey du wie läuft es bei dir (hey you how is it going)
Request: wie viel uhr treffen wir uns (what time do we meet)
Response: oh (oh)

经过合理的努力后,上述方法提供了良好的结果。由于已经学习了单词嵌入,训练不需要很长时间,你也不需要那么多的训练数据。

这是一个非常基本的方法,使用几种可能的改进可以获得更好的结果。例如,循环网络可以不只有一层,而是两层或四层。它们也可以被实现为双向循环网络。在这种情况下,递归神经网络不仅查看当前单词后面的单词,还查看它前面的单词。为了获得对同一请求的各种响应,可以改进选择下一个单词的算法(在上述情况下,选择概率最高的单词,这称为贪婪采样)。一些随机性可以应用于下一个单词的选择,即通过从具有最高概率的单词中随机选择一个单词(这被称为随机采样)。

摘要

您从本文中学到了什么:

  • 编码器-解码器网络和字嵌入的基础
  • 迁移学习的概念。具体地,如何将预训练的单词嵌入加载到 Keras 的嵌入层中。
  • 如何获取训练数据,准备制作一个像你一样说话的聊天机器人。
  • 如何为编码器-解码器网络建立和训练模型。
  • 推理模型如何被用来从你的聊天机器人那里产生回应。

参考

下面是一个资源列表,提供了关于本文主题的更多信息:

[1] Jeffrey Pennington 和 Richard Socher 和 Christopher D. Manning, GloVe:单词表示的全局向量 (2014),自然语言处理中的经验方法(EMNLP)

[2]托马斯·米科洛夫、程凯、格雷戈·科拉多和杰弗里·迪恩,《向量空间中词表征的有效估计》 (2013),arXiv

[3] Hochreiter,Sepp 和 Schmidhuber,于尔根,(1997),神经计算

[4]赵庆云和巴特·范·梅里恩博尔和卡格拉尔·古尔切雷和迪米特里·巴丹瑙和费特希·布加雷斯以及霍尔格·施文克和约舒阿·本吉奥,使用 RNN 编码器-解码器学习短语表示用于统计机器翻译 (2014),EMNLP 2014

[5] Ilya Sutskever 和 Oriol Vinyals 和 Quoc V. Le,用神经网络进行序列间学习 (2014),arXiv

使用 TigerGraph、Flask、Bootstrap、NLTK 和 SkLearn 创建“智能日志”

原文:https://towardsdatascience.com/creating-a-smart-journal-with-tigergraph-flask-bootstrap-nltk-and-sklearn-8b15e1465a3?source=collection_archive---------30-----------------------

我的 2020 年国会应用程序挑战获奖应用程序的逐步演练

什么是国会应用挑战?

每年,国会都会举办一项名为国会应用挑战(CAC) 的年度竞赛。每个众议院议员都会收到几个应用程序提交,他们会为获胜的团队选择最佳应用程序,在华盛顿 DC 进行展示。不幸的是,由于今年的疫情,DC 之行被取消了,但我得到了在网上展示我的项目的机会。

所以,事不宜迟,下面是我今年项目的一个预演。

目标

我项目的目标是创建一个“智能日志”我想让它成为一个分析一个人长期情绪的地方。我在想类似于《软禁》中的东西:一个人出于治疗的目的写下他们的情感。但是,如果使用得当,该杂志将能够追踪与不同事物的积极和消极联系,并可能在未来能够发现精神疾病的早期迹象,如倦怠、抑郁等。

技术堆栈+技术概述

下面来分解一下我是怎么做出来的。对于前端,我使用 Bootstrap 来轻松创建我的网站。我用 Python 后端的 Flask 使我的网站具有交互性。在 Python 中,我用 NLTK 和 Sklearn 处理数据,具体是整体内涵是正还是负。最后,我使用图形数据库来存储日记条目中的重要单词,并找到积极和消极的关联。

因此,我们总共有五个步骤:

  1. 从文本中抓取关键词。
  2. 确定一篇文章总体上是正面的还是负面的,以及它的“强度”。
  3. 创建一个图表模式并将数据插入图表。
  4. 编写查询来提取数据。
  5. 建立前端和连接一切与烧瓶。

第一步和第二步:抓住关键词,找到文本的情感

我保持了我的第一个原型的简单:我只是想知道某样东西是积极的还是消极的。因为时间关系,我做了一个简单的算法,不复杂,但是很简单。

首先,我提取了停用词和标点符号。

stopwords.words('english')
punc = [".", ",", "!", "?", ";", ":"]
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(inp)
arr1 = [w for w in word_tokens if not w in stop_words]
pain = " ".join([w for w in arr1 if not w in punc])

为了给积极/消极评分,我考虑过使用情绪分析,但我没有数据来训练它,而且我认为标准的 Twitter 版本不适合我的目的,所以我使用了一个非常基本的替身。我发现一个 txt 文件的积极的话和另一个消极的话。然后,我把每个单词分类,不包括停用词,分为积极的,消极的或中性的。最后,我使用(positive_count-negative_count) / (positive_count + negative_count)计算出最终分数。

接下来,我想提取关键词。为此,我使用了一个 TF-IDF 算法(来自 Sklearn)。

from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform([pain])
feature_names = vectorizer.get_feature_names()
dense = vectors.todense()
denselist = dense.tolist()
df = pd.DataFrame(denselist, columns=feature_names)

最后,我从关键词中过滤掉所有负面和正面的词(否则最常见的正面和负面联想就是这些词)。

all_neutral_words = [w for w in to_add_list if not w in neg]
all_neutral_words = [w for w in all_neutral_words if not w in pos]
emo = ["Positive" if score > 0 else "Negative"][0]

现在我已经准备好了我的话,我需要创建一个图表。

第三步:创建模式

首先,对于我的图表,我需要创建我的模式。我决定要一个时间树。

conn.gsql('''CREATE VERTEX Entry(PRIMARY_ID id STRING)
CREATE VERTEX Word (PRIMARY_ID word STRING) WITH primary_id_as_attribute="true"
CREATE VERTEX Emotion (PRIMARY_ID emotion STRING) WITH primary_id_as_attribute="true"
CREATE VERTEX Resource (PRIMARY_ID id STRING, url STRING)
CREATE VERTEX _Year(PRIMARY_ID year STRING) WITH primary_id_as_attribute="true"
CREATE VERTEX _Month(PRIMARY_ID year STRING) WITH primary_id_as_attribute="true"
CREATE VERTEX _Day(PRIMARY_ID year STRING) WITH primary_id_as_attribute="true"
CREATE VERTEX _Hour(PRIMARY_ID year STRING) WITH primary_id_as_attribute="true"CREATE UNDIRECTED EDGE ENTRY_WORD (FROM Entry, TO Word)
CREATE UNDIRECTED EDGE ENTRY_EMOTION (FROM Entry, TO Emotion, strength DOUBLE)
CREATE UNDIRECTED EDGE EMOTION_RESOURCE (FROM Emotion, TO Resource)
CREATE UNDIRECTED EDGE EMOTION_WORD (FROM Emotion, TO Word)
CREATE UNDIRECTED EDGE _YEAR_EMOTION (FROM _Year, TO Emotion)
CREATE UNDIRECTED EDGE _MONTH_EMOTION (FROM _Month, TO Emotion)
CREATE UNDIRECTED EDGE _DAY_EMOTION (FROM _Day, TO Emotion, strength DOUBLE)
CREATE UNDIRECTED EDGE _HOUR_EMOTION (FROM _Hour, TO Emotion)
CREATE UNDIRECTED EDGE _HOUR_ENTRY (FROM _Hour, TO Entry)
CREATE UNDIRECTED EDGE _YEAR_MONTH (FROM _Year, TO _Month)
CREATE UNDIRECTED EDGE _MONTH_DAY (FROM _Month, TO _Day)
CREATE UNDIRECTED EDGE _DAY_HOUR (FROM _Day, TO _Hour)''')

我有几个主要的顶点:入口、词和情感。接下来,我将所有东西都连接到时间树(年、月、日和小时),这样我就可以创建一个时间戳(打算在将来创建某种日历)。

接下来,我创建了我的图表并更新了我的连接:

print(conn.gsql('''CREATE GRAPH Diary(Entry, Word, Emotion, Resource, _Year, _Month, _Day, _Hour, ENTRY_WORD, ENTRY_EMOTION, EMOTION_RESOURCE, EMOTION_WORD, _YEAR_EMOTION, _MONTH_EMOTION, _DAY_EMOTION, _HOUR_EMOTION, _HOUR_ENTRY, _YEAR_MONTH, _MONTH_DAY, _DAY_HOUR)''', options=[]))  # Create the Graph # Update the Connection
conn.graphname = "Diary"
conn.apiToken = conn.getToken(conn.createSecret())

最后,如果我打开 GraphStudio,模式如下所示:

作者图片

第四步:上传数据

现在,图表已经创建,我需要添加我的数据。首先,每个条目都有一个惟一的 id,我将 entry_id 设为当前时间(用 datetime.now())。

entry_id = str(datetime.now())

接下来,我向上插入条目和情感顶点,并用一条边将其连接起来。

conn.upsertVertex("Entry", entry_id, attributes={})conn.upsertVertex("Emotion", emo, attributes={"emotion": emo})conn.upsertEdge("Entry", entry_id, "ENTRY_EMOTION", "Emotion", emo, attributes={"strength": score})

最后,我把日记条目中所有重要的单词向上插入,并连接到时间树。

for i in all_neutral_words:
   conn.upsertVertex("Word", i, attributes={"word": i})
   conn.upsertEdge("Emotion", emo, "EMOTION_WORD", "Word", i)
   conn.upsertEdge("Entry", entry_id, "ENTRY_WORD", "Word", i)
   conn.upsertVertex("_Day", datetime.today().strftime("%d"))
   conn.upsertEdge("_Day", datetime.today().strftime("%d"), "_DAY_EMOTION", "Emotion", emo, attributes={"strength": score})

接下来,我必须编写查询,然后我可以将 UI 组装在一起。

步骤五:编写查询

我决定让第一个原型总共有三种情绪:

  1. getmostconwordbyemotion—>简单来说,这是基于某种情绪获取最常见的单词。
  2. getEmotionByDay —>这衡量一天中的整体情绪。
  3. getTotalWords —>查看图表中的所有单词。

从最简单的开始,getTotalWords 就像它听起来的那样,获取图表中的所有单词并对它们进行计数。我是这样做的:

CREATE QUERY getTotalWords() FOR GRAPH Diary { 
  SumAccum<int> @@total = 0;
  Seed = {Word.*};
  Res = SELECT s FROM Seed:s
        ACCUM @@total+=1;
  PRINT @@total;
}

接下来,对于 getEmotionByDay,我查看输入的日顶点,然后使用 AvgAccum 查看当天的平均情绪。

CREATE QUERY getEmotionByDay(STRING day) FOR GRAPH Diary { 
  AvgAccum @@avgEmotion;
  Seed = {_Day.*};
  Res = SELECT e FROM Seed:s -(_DAY_EMOTION:d)-Emotion:e 
        WHERE s.year == day
        ACCUM @@avgEmotion +=d.strength;
  PRINT @@avgEmotion;
}

第六步:把它们放在一起(用烧瓶和自举!)

最后,我用 Flask 和 Bootstrap 把所有东西放在一起!烧瓶部分看起来像这样:

# Import Libraries
from flask import Flask, render_templateapp = Flask(__name__)@app.route('/')def index(): return render_template("index.html")@app.route('/<string:file>', methods=['GET', 'POST'])def diary(file): # Main code here

我创建了我的 Flask 应用程序。所做的工作全部进入@app.route('/ ')。如果打开 stats 页面,我需要运行所有的查询,所以我首先添加了一个 If,然后运行并呈现所有内容:

if file == "profile.html": ans = conn.runInstalledQuery("getMostCommonWordByEmotion", params={"emo": "Positive"})[0]["Res1"] pos1 = ans[0]["attributes"]["word"]
   pos2 = ans[1]["attributes"]["word"]
   pos3 = ans[2]["attributes"]["word"] ans = conn.runInstalledQuery("getMostCommonWordByEmotion", params={"emo": "Negative"})[0]["Res1"] neg1 = ans[0]["attributes"]["word"]
   neg2 = ans[1]["attributes"]["word"]
   neg3 = ans[2]["attributes"]["word"] return render_template(file, pos1=pos1, pos2=pos2, pos3=pos3, neg1=neg1, neg2=neg2, neg3=neg3, things=conn.runInstalledQuery("getTotalWords")[0]["@@total"], color=["red" if conn.runInstalledQuery("getEmotionByDay")[0]["@@avgEmotion"] < 0 else "green"][0])

接下来,我添加了一个简单的方法,如果该方法是一个 GET 来返回文件。

if request.method == 'GET': return render_template(file)

最后,如果方法是 POST,我添加了步骤 I、II 和 IV 中的代码。然后我用所有必要的数据渲染 profile.html。

if request.method == 'POST': inp = request.form['inp'] # Code from Steps I, II, and IV ans = conn.runInstalledQuery("getMostCommonWordByEmotion", params={"emo": "Positive"})[0]["Res1"] pos1 = ans[0]["attributes"]["word"]
   pos2 = ans[1]["attributes"]["word"]
   pos3 = ans[2]["attributes"]["word"] ans = conn.runInstalledQuery("getMostCommonWordByEmotion", params={"emo": "Negative"})[0]["Res1"] neg1 = ans[0]["attributes"]["word"]
   neg2 = ans[1]["attributes"]["word"]
   neg3 = ans[2]["attributes"]["word"] return render_template("profile.html", pos1=pos1, pos2=pos2, pos3=pos3, neg1=neg1, neg2=neg2, neg3=neg3, things=conn.runInstalledQuery("getTotalWords")[0]["@@total"], color=["red" if conn.runInstalledQuery("getEmotionByDay")[0]["@@avgEmotion"] < 0 else "green"][0])

从自举的角度来看,我在 journal.html 有一个输入,它导致了上插:

<div class = "container text-center"><form method="POST" action="/practice_place"><div class="form-group">
<label for="exampleFormControlTextarea1"></label>
<textarea name = "inp" class="form-control" style="height: 50vh;" id="exampleFormControlTextarea1" rows="3"></textarea>
</div><input type="submit" class="btn btn-primary btn-lg" href="info.html" value = "I'm Done for Today"></input></form><br><br></div>

然后,我在个人资料页面上有各种协会的卡片:

<div class="container text-center padding">
<h1>Here are Negative Associations</h1>
<div class="row"><div class="col-md-12 col-lg-4">
<div class="card">
<div class="card-body">
<h4>{{ neg1 }}</h4>
</div></div></div><div class="col-md-12 col-lg-4">
<div class="card">
<div class="card-body">
<h4>{{ neg2 }}</h4>
</div></div></div><div class="col-md-12 col-lg-4">
<div class="card">
<div class="card-body">
<h4>{{ neg3 }}</h4>
</div></div></div></div></div>

恭喜你!现在,您已经使用 Bootstrap、Flask、NLTK 和 TigerGraph 创建了一个应用程序!

第七步:下一步!

恭喜你。你完成了我的这个项目。接下来,你可以开始着手自己的项目了!要获得帮助,您可以加入 TigerGraph Discord:

https://discord.gg/gRHWBZNpxW

用 Python 创建 Snapchat 风格的过滤器

原文:https://towardsdatascience.com/creating-a-snapchat-style-filter-with-python-b42ecfd2ff54?source=collection_archive---------7-----------------------

哈尔级联和单应性的实际演示

Ethan Robertson 在 Unsplash 上拍摄的照片

智能手机中增强现实(AR)的引入开创了一种新的娱乐方式。从玩 Pokémon Go 这样的游戏到在 Snapchat 上做鬼脸,AR 已经成为一种司空见惯的现象。

虽然这些技术似乎先进到可以借用科幻小说,但用 Python 创建一个有趣的 Snapchat 风格的过滤器却出人意料地简单。在这种情况下,我将创建一个过滤器,将一副太阳镜放在脸上。

我为这个项目画了这副太阳镜。我不会辞掉日常工作去追求艺术。

与任何 AR 一样,这种过滤器依赖于两个基本步骤。首先,它必须确定在视频帧中的何处投影图像。在这个例子中,无论我使用什么算法,都必须正确识别我眼睛的位置。其次,它必须变换投影图像,使其与视频帧的其余部分成比例。在这种情况下,图像是一副在投影时必须适合一双眼睛的太阳镜。

虽然这两个挑战听起来令人生畏,但是 Python 对 OpenCV 的实现使之变得相当容易。

基本概述

要克服的第一个挑战是检测一双眼睛。面部检测和面部标志检测都是计算机视觉中的巨大课题,有许多独特的方法,但这种方法将使用哈尔级联。

由 Paul Viola 和 Michael Jones 在 2001 年的一篇论文中首次介绍的 Haar Cascades 是一种专门为快速面部检测设计的通用监督机器学习技术。然而,OpenCV 没有从头开始训练,而是提供了许多预先构建的模型,包括人脸和眼睛检测。

第二个挑战是转换投影图像,以确保它与人脸成比例。关注投影空间中同构的单应性提供了一个解决方案。虽然这个概念本身听起来很吓人,但我们将使用它来将太阳镜投影到视频帧上,以便它看起来自然。

显然,Haar Cascades 和 Homorgraphy 都是很深的概念,其细节超出了本文的范围,但是对它们是什么和它们做什么的基本理解将有助于理解代码实现。

检测眼睛

import numpy as np
import cv2# Import the pre-trained models for face and eye detection
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml")

在做很多之前,导入 NumPy 用于高效的数值计算,导入 OpenCV 用于图像处理。

接下来调用 OpenCV 内置的级联分类器方法。现在还没有分类,但是这可以用来初始化将要使用的模型。作为参数传递的 XML 文件实际上是预先训练好的模型,专门检测面部和眼睛的正面视图。

这些预先训练好的模型内置在 OpenCV 中,但是可以在这里单独下载。但是,请注意,这些预先训练的模型已授权给英特尔,可能有使用限制。

# Global variable to cache the location of eyes
eye_cache = None

声明一个全局变量来创建缓存。这样做有两个原因:

  1. Haar Cascades 分类器将无法在每一帧中识别眼睛,这将产生闪烁效果。然而,通过使用缓存,该程序可以参考上次成功识别的眼睛位置,并相应地放置眼镜。这将消除闪烁,使程序运行更流畅。
  2. 有时,哈尔喀斯会错误地识别两个以上的眼睛,这将打乱眼镜的位置。像以前一样,使用高速缓存,这可以通过参考眼睛的先前位置来校正。

虽然这使得程序运行更流畅,但这是有代价的。通过连续参考先前帧中眼睛的位置,眼镜的位置会滞后。对于平静地坐着甚至缓慢摇摆的人来说,这种影响不是很明显,但是快速移动的脸会看到这种影响。

# Capture video from the local camera
cap = cv2.VideoCapture(0)while True:

    # Read the frame
    ret, frame = cap.read() # Check to make sure camera loaded the image correctly
    if not ret:
        break

第一行捕捉视频。注意,传递 0 将使用电脑上的第 0 个摄像头。如果使用了 multiple,那么传递任何整数都会使用第 n 个相机。

此外,如果需要使用预先录制的视频,那么向视频的位置传递一个字符串也可以。

接下来,初始化一个无限循环,并读取来自摄像机的数据。变量“ret”只是一个布尔值,它表示视频是否实际上是从摄像机捕获的,而“frame”是来自摄像机的当前帧。如果“ret”为假,循环将会中断。

 # Convert to grayscale
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Detect faces
    faces = face_cascade.detectMultiScale(gray_frame, 1.3, 5)

该帧被转换成灰度,然后进入哈尔级联检测任何人脸。在眼睛之前检测到面部,因为检测到的任何眼睛都应该位于面部内。如果一只眼睛位于脸部之外,那么要么是有问题,比如假阳性,要么是有问题非常

被调用来检测面的方法将返回一个面的矩阵,带有它们自己的(x,y)坐标以及宽度和高度。

 for (x, y, w, h) in faces: # Draw a rectangle around the face
        roi_gray = gray_frame[y:y+h, x:x+w] # Detect eyes within the grayscale region of interest
        eyes = eye_cascade.detectMultiScale(roi_gray)

对于找到的每一张人脸,视频帧的一个子部分被提取出来,称为感兴趣区域。这个感兴趣的区域然后通过专门研究眼睛的 Haar Cascades 分类器。检测到眼睛后,可以进行下一步。

 # Only detect 2 eyes
        if len(eyes) == 2:
            # Store the position of the eyes in cache
            eye_cache = eyes
        # If 2 eyes aren't detected, use the eye cache
        elif eye_cache is not None:
            eyes = eye_cach

如前所述,如果没有检测到眼睛或者检测到两个以上的眼睛,将使用缓存。如果如预期的那样检测到两只眼睛,则相应地更新缓存。

将图像投影到框架上

要将太阳镜的图像投影到视频帧上,使它们成比例,需要两件事情:太阳镜的(x,y)坐标和它们将被投影到视频帧上的(x,y)坐标。两者都将被组织成简单的矩阵。前者将是源矩阵,因为它是图像的源,而后者将是目的矩阵,因为它是图像的目的。

一旦两个矩阵都被开发出来,第三个矩阵,即单应矩阵,将被计算出来,它给出了如何“拉伸”太阳镜的图像以使其适合一双眼睛的方向。

 # read the image and get its dimensions
    img = cv2.imread("glasses_transparent.png", -1)
    img_h = img.shape[0]
    img_w = img.shape[1] # Create source matrix
    src_mat = np.array([[0,0], [img_w, 0],  [img_w, img_h], [0, img_h]])

首先,太阳镜的图像被读入内存。通常,图像有三个通道:红色、绿色和蓝色。这些表示默认的色彩空间;然而,一些图像有第四个通道,称为 alpha 通道,它表示透明度。

当我画这副太阳镜时,我确保它包含一个透明的背景。通常,OpenCV 会忽略这一点,但是通过向 imread 方法传递-1,它会读取第四个通道。

读取图像后,标注尺寸,源矩阵由左上角、右上角、右下角和左下角的坐标组成。矩阵必须是这个顺序!

 # define the destination matrix based on eye detected order.
        # Order of points must be top-left, top-right, bottom-left,
        # and bottom-right
        if eyes[0][0] < eyes[1][0]:
            dst_mat = np.array([
                [x + eyes[0][0], y + eyes[0][1]],
                [x + eyes[1][0] + eyes[1][2], y + eyes[1][2]],
                [x + eyes[1][0] + eyes[1][2], y + eyes[1][1] + eyes[1][3]],
                [x + eyes[0][0], y + eyes[0][1] + eyes[0][3]] ])
        else:
            dst_mat = np.array([
                [x + eyes[1][0], y + eyes[1][1]],
                [x + eyes[0][0] + eyes[0][2], y + eyes[0][2]],
                [x + eyes[0][0] + eyes[0][2], y + eyes[0][1] + eyes[1][3]],
                [x + eyes[1][0], y + eyes[1][1] + eyes[1][3]] ])

这就是事情变得有点复杂的地方。当眼睛被检测时,没有办法预先知道眼睛的顺序。有时会先检测到右眼,有时会检测到左眼。为了测试,在两眼之间比较 x 坐标,然后可以组成适当的目的矩阵。

目标矩阵必须包含与源矩阵顺序相同的眼角坐标。换句话说,左上角、右上角、右下角和左下角的(x,y)坐标。

不这样做将会产生意想不到的结果。在我的第一次尝试中,眼镜自己折叠起来,看起来像是图形故障。

 # Get the dimensions of the frame
    face_h = frame.shape[0]
    face_w = frame.shape[1] # Find the Homography matrix
    hom = cv2.findHomography(src_mat, dst_mat)[0] # Warp the image to fit the homegraphy matrix
    warped = cv2.warpPerspective(img, hom, (face_w, face_h))

在快速获得视频帧的尺寸之后,使用内置的 OpenCV 方法找到单应矩阵。

接下来,源图像被扭曲,所以现在眼镜将与戴眼镜的脸成比例。现在唯一要做的就是将这个扭曲的图像投射到视频帧上并显示出来。

 # Grab the alpha channel of the warped image and create a mask
    mask = warped[:,:,3] # Copy and convert the mask to a float and give it 3 channels
    mask_scale = mask.copy() / 255.0
    mask_scale = np.dstack([mask_scale] * 3) # Remove the alpha channel from the warped image
    warped = cv2.cvtColor(warped, cv2.COLOR_BGRA2BGR)

图像的遮罩将原始图像的 alpha 通道。还可以通过使用阈值处理在不透明的图像上创建遮罩,但是使用透明的图像使得该过程更快更容易。

然后将掩码归一化,然后转换为三个通道,以便它可以与其他矩阵相乘。

在这一点上,阿尔法通道已经达到了它的目的,保持它实际上会导致比它解决的问题更多的问题。因此,最后一行将图像转换回正常的三通道图像。

 warped_multiplied = cv2.multiply(mask_scale, warped.astype("float"))
    image_multiplied = cv2.multiply(frame.astype(float), 1.0 -     mask_scale)
    output = cv2.add(warped_multiplied, image_multiplied)
    output = output.astype("uint8")

产生的遮罩与扭曲的图像相乘,这将在“透明”背景上创建一个扭曲的图像。然后,视频帧本身被放大,这在眼镜所在的图像中产生了一个间隙。这两幅图像加在一起,结果是一张戴着太阳镜的脸。

 cv2.imshow("SnapTalk", output)

    if cv2.waitKey(60) & 0xff == ord('q'):
        breakcap.release()
cv2.destroyAllWindows()

最后,显示图像。写一个退出条件,这样当“q”键被按下时,它中断循环。

一旦环路中断,摄像机将关闭,所有打开的窗口都将关闭。

结果呢

如果幸运的话,最终结果会是这样的:

我穿上了我最好的仿皮革夹克,以最大限度地提高这次展示的酷感

该程序自动准确地检测我的眼睛,并实时将眼镜投影到我的脸上。即使当我改变表情并在屏幕上移动我的头时,眼镜也没有太大问题。

因为我使用缓存来记录眼镜的位置,即使我的眼睛没有被检测到,眼镜仍然在屏幕上。因此,我可以在擦眼睛的时候假装拿着眼镜。

玻璃本身倾向于改变大小,这是哈尔级联分类器的结果。当它设法找到我的眼睛时,它不断地改变分类尺寸。与太阳镜的平面图像搭配,合成图像看起来滑稽可笑。额外的工作,如使用眼镜尺寸的滚动平均值,可能会适应这一点,但它确实会产生更多的滞后。

在快速运动中,程序的滞后变得相当明显。

随着程序的运行,当对象快速移动时会有明显的滞后。当我在屏幕上移动时,在程序再次找到我的眼睛之前,眼镜会暂时悬停。

然而,与之前的演示相比,我的动作比正常人自然会做的动作更快。理想情况下,即使在这种速度下,程序也能找到我的眼睛,但它最终足够好地服务于它的目的。

结论

虽然有许多关于人脸检测的教程和文章,但将它用于 AR 推动了这些技术的可能性。在本文中,Haar cascades 用于眼睛,但是对于身体的不同部分存在各种其他预训练模型,这增加了可能使用的应用数量。同样,作为一种通用的机器学习技术,定制的 Haar 级联可以被训练并用于尚不可用的东西。

再加上 AR 的新颖性,可以创建一个简单的 Snapchat 风格的过滤器。单应提供了一个很好的工具,可以将 2D 项目投射到视频静止图像中,产生有趣的效果。

用 Python 创建电报聊天机器人测验

原文:https://towardsdatascience.com/creating-a-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-chatbot-quiz-with-python-711a43c0c424?source=collection_archive---------6-----------------------

教程和一个真实的例子:“世界首都”聊天机器人测验

作者图片

丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 成为一个伟大的聊天机器人平台的特征之一是能够创建投票。这是在 2019 年推出的,后来通过添加问答模式进行了改进,最重要的是,通过将其提供给 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 Chatbot API。

可以在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 应用程序中直接创建投票(无需编码),但这里我们将探索如何使用 Python 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 Bot 库从头开始开发 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 聊天机器人测验。

首先做一些热身:玩一个真实的例子,测试你对世界各国首都的了解😎。使用/start命令(*)开始对话。

https://t.me/world_capitals_quiz_bot

(*)请耐心等待,它会按需运行,可能需要几秒钟才能醒来并开始聊天😊

聊天机器人设置

该设置包括 3 个步骤:

  • 交谈机器人父亲创建一个新的聊天机器人并获得授权令牌
  • 配置更新程序对象和方法处理程序
  • 启动聊天机器人(在本例中,在轮询模式下,但是可以使用 Webhook 代替)
defmain():
  updater = Updater('secret token', use_context=True)

  dp = updater.dispatcher

  *# command handlers* dp.add_handler(**CommandHandler**("help", help_command_handler))
  *# message handler* dp.add_handler(**MessageHandler**(Filters.text, main_handler))
  *# quiz handler* dp.add_handler(**PollHandler**(poll_handler, pass_chat_data=True, pass_user_data=True)) # start
  updater.start_polling()
  updater.idle()

理解上面定义的处理器负责处理“帮助”命令、简单的文本消息和投票回答是很重要的。

获取聊天 Id

我们将首先创建一个助手方法来获取聊天 id:这将在本教程中非常有用,而且如果你开发其他电报聊天机器人。

# extract chat_id based on the incoming object
def get_chat_id(update, context):
  chat_id = -1

  if update.**message** is not None:
    chat_id = update.message.chat.id
  elif update.**callback_query** is not None:
    chat_id = update.callback_query.message.chat.id
  elif update.**poll** is not None:
    chat_id = context.bot_data[update.poll.id]

  return chat_id

测验问题

使用send_poll方法可以创建测验答案

c_id = **get_chat_id**(update, context)q = 'What is the capital of Italy?'
answers = ['Rome', 'London', 'Amsterdam']message = context.bot.**send_poll**(chat_id=c_id, question=q, options=answers, type=Poll.**QUIZ**, correct_option_id=0)

type必须是Poll.QUIZ才能触发测验效果(选择正确答案后的纸屑)correct_option_id必须与answers提供的列表中的正确选项(位置)相匹配。

测验问题增强

让我们不要停留在基础知识上,而是让测验变得更有趣一点。

可以在中增加一个倒计时来让它更刺激:

message = context.bot.send_poll(chat_id=c_id, question=q, options=answers, type=Poll.QUIZ, correct_option_id=0, **open_period**=5)

超时 5 秒的问题—图片由作者提供

可以包括附加解释以在用户回答后提供额外信息:注意用户可用的灯图标。

message = context.bot.send_poll(chat_id=c_id, question=q, options=answers, type=Poll.QUIZ, correct_option_id=0, 
**explanation**= **'**Well, honestly that depends on what you eat**'**, **explanation_parse_mode** = 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.ParseMode.MARKDOWN_V2)

带附加“解释”的问题—作者图片

处理答案

了解如何处理用户答案很重要。

丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 BOT API 提供了方法和对象来呈现一个漂亮的界面,以及庆祝正确的答案(或标记错误的响应)。然而,开发人员需要跟踪成功的答案并构建必要的逻辑,例如计算分数、增加后续问题的复杂性等...

所有测验答案都被发送到PollHandler,在那里update对象将携带包含所有必要信息的有效载荷

# handling Poll answers
def poll_handler(update, context): # Quiz question
  question = update.poll.question
  # position of correct answer
  correct_answer = update.**poll.correct_option_id** # first option (text and voted yes|no)
  option_1_text = update.**poll.options[0].text**
  option_1_vote = update.**poll.options[0].voter_count**

有效载荷中的每个option指示它是否已经被投票(voter_count等于 1)。

# find the answer chosen by the user
def get_answer(update):
  answers = update.poll.options

  ret = ""

  for answer in answers:
    if **answer.voter_count == 1**:
      # found it
      ret = answer.text
      break return ret

使用correct_option_id可以确定用户给出的答案是否正确。

# determine if user answer is correct
def is_answer_correct(update):
  answers = update.poll.options

  ret = **False**
  counter = 0

  for answer in answers:
    if answer.voter_count == 1 and \
                update.poll.correct_option_id == counter:
      ret = **True**
      break

    counter = counter + 1 return ret

常规民意测验差异

可以创建一个常规投票来代替测验:逻辑和代码是相同的,但是有一些不同之处,使得标准投票更适合于调查和问卷:

  • 没有五彩纸屑庆祝
  • 允许多个答案
  • 让用户可以看到结果
message = context.bot.send_poll(chat_id=cid, question=q, options=answers, type=Poll.**REGULAR**, **allows_multiple_answers**=True,
**is_anonymous**=False)

定期投票-按作者分类的图片

结论

我们已经介绍了在 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 上开发一个测验的所有关键概念,查看 Github repo 从一个基本的测验实现开始,使用本文中提供的代码片段。

如果您正在开发电报聊天机器人,您可能会发现这很有用:

</bring-your-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-chatbot-to-the-next-level-c771ec7d31e4>

如有问题和建议,请在 Twitter 上找到我,如果你创建了一个电报问答聊天机器人,请与我分享!

利用 NOAA 卫星图像制作飓风视频

原文:https://towardsdatascience.com/creating-a-video-of-hurricane-from-noaa-satellite-images-ed39178d501c?source=collection_archive---------35-----------------------

使用 Wolfram 语言

(图片来自 NOAA,公共领域)

国家气象局提供由 T2 国家海洋和大气管理局 T3 运营的许多卫星的详细卫星图像。当出现严重的天气事件时,如飓风伊达,他们就训练一颗卫星跟踪这一事件,并在它的一生中跟踪它。这篇文章展示了如何使用 Wolfram 语言将这些图像转换成一个视频。这段视频让我们对艾达的演变有了有趣的了解,从一个小型热带低气压,到一场大飓风,再到美国东北部的一场主要造雨者:

图片来自 NOAA(公共领域)

用于生成上面显示的视频的图像存储在 NOAA 网络服务器上。以下代码为这些 NOAA 图像设置了基本 URL:

base = "https://cdn.star.nesdis.noaa.gov/FLOATER/data/AL092021/GEOCOLOR/"

此网页有许多不同大小(250x250、500x500、1000x1000 和 2000x2000)的特定图像的超链接:

(图片由作者提供)

为了从该页面获取图像链接,我们使用 Wolfram 语言将该页面作为 XMLObject 导入:

xml = Import[base, "XMLObject"];

使用这个 xml 对象,我们可以使用 Cases 和 Select 来提取我们感兴趣的图像(在这种情况下,我们想要 2000 x 2000 像素的图像):

files = Select[
  Cases[
    xml,
    XMLElement["a", {_, "href" -> href_}, _] :> href, 
    \[Infinity]
  ],
  StringContainsQ["_GOES16-ABI-FL-GEOCOLOR-AL092021-2000x2000.jpg"]
]

files 变量是我们感兴趣的所有图像文件的列表。

接下来,我们使用 CreateDirectory 创建一个目录来存储下载的图像:

CreateDirectory["ida-images"]

使用 URLDownload 我们可以将图像下载到本地硬盘:

downloads = URLDownload[
  URLBuild[{base, #}],
  FileNameJoin[{"ida-images", #}]
] & /@ files;

下载变量是所有本地图像文件的列表。

使用 SlideShowVideo ,我们现在可以从图像列表中创建一个视频。我们给每幅图像 0.3 秒的显示时间,即每秒三幅图像:

video = SlideShowVideo[downloads -> 0.3]

生成的视频以文件形式存储在本地计算机上,并准备上传到 YouTube :

那么现在我们有了这个视频,可以回放整个事件,我们能学到什么呢?令我震惊的是,国家气象局能够如此早地探测到这个热带低气压,并预测到它将转变为飓风。他们指示他们的一颗卫星,在很早的时候就聚焦在这个低气压上:在登陆前三天。

我发现早期的图像序列,直到眼壁的形成,是最有趣的观看。特别是在这段视频的第 45 秒,热带系统似乎在日落时爆发了。到了晚上,在清晨时分,这个系统已经变成了古巴北部的一个旋转的怪物。

眼墙也很迷人,令人惊讶的是它在陆地上能坚持多久。路易斯安那州的海岸大部分是沼泽,海水非常温暖,这可能有助于这种持久力。

该系统一直旋转,直到它完全覆盖田纳西州,之后它成为东北部各州的主要降雨者。据报道,纽约市在短短 3 小时内降雨量达到创纪录的 5 英寸,今年第二次关闭了地铁系统。

这个系统最终会消失,尽管一路追踪到欧洲并观察它是否也会在那里引发问题会很有趣。

要了解更多的细节和完整代码的 Wolfram 笔记本,请看这篇文章:【https://community.wolfram.com/groups/-/m/t/2358543

用风格创造抽象艺术

原文:https://towardsdatascience.com/creating-abstract-art-with-stylegan2-ada-ea3676396ffb?source=collection_archive---------11-----------------------

我如何使用自适应鉴别器增强和学习转移来生成具有人工智能的改进的抽象画。

style gan 2 ADA的输出样本,图片作者

回到 2020 年 8 月,我创建了一个名为 MachineRay 的项目,该项目使用 Nvidia 的 StyleGAN2 来创作基于 20 世纪早期公共领域绘画的新抽象艺术品。从那以后,Nvidia 发布了新版本的人工智能模型 StyleGAN2 ADA,旨在从有限的数据集生成图像时产生更好的结果[1]。(我不确定他们为什么不叫它 StyleGAN3,但为了节省几个字符,我将把新型号称为 SG2A)。在本文中,我将向您展示我如何使用 SG2A 来创建更好看的抽象画。

机器射线 2

概观

类似于原始的机器射线,我使用公共领域的抽象画作为我的源图像来训练 SG2A 系统。然后,作为后期处理的一部分,我改变了长宽比。这张图显示了系统的流程。

MachineRay 2 流程图,图片作者

一切都从我用自定义脚本从 WikiArt.org 收集的 850 张图片开始。图像经过预处理,作为“真实”图像输入鉴别器网络。一组 512 个随机数被选择并输入到样式映射器和生成器网络中,以创建“假”图像。真假图像都用自适应鉴别器增强进行了修改,这是 SG2A 的关键创新。我将在本文中进一步讨论这一点。鉴别器网络的工作是确定输入是真的还是假的。结果反馈到三个网络来训练它们。训练完成后,我对生成器网络的输出进行后处理,以获得最终的图像。

我将在下面的小节中更详细地介绍每个步骤。

收集源图像

我使用一个 Python 脚本来收集来自 WikiArt.org 的图像,这些图像被标记为“抽象的”并且在公共领域中,即在 1925 年之前创建的。这些图片来自蒙德里安、康定斯基、克利等人。收集图像的源代码是这里的。这里有一幅原画的样本。

WikiArt.org 抽象画的随机样本,在公共领域

预处理源图像

以下是我用来预处理图像的步骤:

  1. 移除框架:Python 脚本查找并移除图像周围的木制(或其他)框架。这里的代码是这里是。
  2. 调整到 1024x1024: GANs 最适合调整到 2 的幂的正方形图像,例如 2 ⁰ = 1024

这是一个预处理图像的例子。

预处理抽象画、作者图片

自适应鉴别器增强

SG2A 的主要改进之一是在训练期间动态地改变图像增强的数量。

图像增强已经存在一段时间了。这个概念相当简单。如果没有足够的图像来训练 GAN,可能会导致性能下降,如过拟合、欠拟合或可怕的“模型崩溃”,即生成器重复相同的输出图像。解决这些问题的方法是图像放大,你可以应用旋转、缩放、平移、颜色调整等变换。,为训练集创建附加图像。

图像增强的一个缺点是变换可能“泄漏”到生成的图像中,这可能是不希望的。例如,如果要生成人脸,可以使用 90°旋转来增加训练数据,但可能不希望生成的人脸被旋转。Nvidia 发现,在以非零概率跳过的条件下,增强可以被设计为不泄漏的。因此,如果输入鉴别器的大部分图像没有旋转以进行增强,生成器将学习不创建旋转的图像[1]。

…只要损坏过程由数据空间上概率分布的可逆变换来表示,训练就会隐式地撤销损坏并找到正确的分布。我们称这种增强操作器为非泄漏操作器。Tero Karras 等人。

新版本的 StyleGAN 具有一个名为自适应鉴别器增强(ADA)的功能,可以在训练期间执行非泄漏图像增强。一个新的超参数 p ,在 0 到 1 的范围内,确定在训练期间对真实图像和伪图像应用增强的程度和频率。

这里有一个示例,显示了不同的 p 值。

图片放大(上图)p=0.0,0.2,0.4(下图)p=0.6,0.8,1.0,图片作者

您可以看到随着 p 从 0.0 增加到 1.0,样本图像显示出更多的空间和颜色变化。(注意,SG2A 没有显示在训练期间对真实图像进行的增强。所以我在我的代码分支中添加了这个功能,这里是。你可以在谷歌实验室里运行一个测试,这里。)

当训练开始时,值 p 从 0 开始,然后如果系统在训练期间检测到过拟合或欠拟合,则增加或减少。

在处理一批生成的图像期间,系统中使用的试探基于鉴别器输出的符号(正或负)。如果正输出值比负输出值多,则趋势是朝向真实图像,这是过度拟合的指示。如果负值比正值多,则趋势是假图像,这是拟合不足的指示。批处理后,相应地上调或下调 p 的值——上调表示过拟合,下调表示欠拟合。

可以设置 p 的目标值,即 0.7,因此总是有非零概率可以跳过增加,这避免了泄漏。

你可以在 Mayank Agarwal 的帖子中阅读更多关于适应性鉴别器增强的信息。

训练系统

我用谷歌 Colab 训练了这个系统。跑了大概四天。该系统拥有 Nvidia Tesla V100 GPU,可运行高达 14 万亿次浮点运算(每秒 14 万亿次浮点运算)。因此,训练大约需要 4.6 万亿次浮点运算(大约 4.6 万亿次浮点运算)。这需要大量的数学运算。

这是我用来启动的 shell 命令。

python stylegan2-ada/train.py --aug=ada --target=0.7 \
--mirror=1 --snap=1 --gpus=1 \
--data='/content/drive/MyDrive/datasets/paintings' \
--outdir='/content/drive/MyDrive/results_stylegan2_ada'

aug 参数设置为 ada 可在需要时启用自适应鉴别器增强。将目标参数设置为 0.7 可防止 p 超过 0.7,这样可最大化动态增强,而不会将任何进一步增强泄露到最终图像中。

这是一张训练结果随时间变化的图表。我使用弗雷歇初始距离(FID)作为图像质量和多样性的衡量标准,分数越低越好[2]。你可以在 Cecelia Shao 的帖子中阅读关于 FID 分数的信息。

style gan 2 和 StyleGAN2 ADA 的训练结果——越小越好,图片作者

您可以看到在相同的迭代次数下,StyleGAN2 ADA 如何优于原始的 StyleGAN2。SG2A 的 FID 分数在大约 300 次迭代后降至 100 多一点。以下是一些结果示例。

style gan 2 ADA 的输出,图片作者

甘似乎创作出了各种各样的抽象画,有着有趣的构图和各种各样的配色方案。但是还有改进的余地。

迁移学习

这可能不直观,但可以通过首先在一组不同的更大的图像上训练 GAN,然后使用抽象绘画进一步训练模型来提高绘画的质量。这种技术被称为迁移学习。它在 1976 年首次被描述为一种训练神经网络的技术[3]。

迁移学习是一种使用为任务 1 训练的预训练神经网络的技术,用于在学习任务 2 中实现更短的训练时间。[4]斯特沃·博兹诺夫斯基

从风景画到抽象画

我记得在我的艺术史 101 课堂上学到,许多抽象画家是从画具象的主题开始的,比如人和风景。例如,这里是蒙德里安、克利和康定斯基的一系列绘画,展示了他们从风景到抽象艺术的进展。

皮埃特·蒙德里安:沿着阿姆斯特尔,未确定,灰色轮廓的浅色平面,来源:wikiart.org

《采石场、城堡和太阳、光和其他》,资料来源:wikiart.org

wikiart.org:《冬季景观》,《绿色住宅景观》,《构图研究 II》

从风景中学习

我想看看我是否能把从创作风景照片中学到的知识转移到提高它创作抽象画的能力上。

作为一项实验,我用来自 Flickr 的 4800 张公共领域的风景照片来训练 SG2A。Arnaud Rougetet 的数据集可以在 Kaggle 上找到,点击这里。

这是来自 Flickr 的照片样本。请注意,我将每张照片的大小调整为 1,024 x 1,024 像素。

Arnaud Rougetet 收集的实景照片公共领域图片

我使用另一个 Google Colab 训练 SG2A 系统来创建新的风景图像。开展培训也花了大约四天时间。下面是我使用的 shell 命令。

python stylegan2-ada/train.py --aug=ada --target=0.7 \
--mirror=1 --snap=1 --gpus=1 \
--data='/content/drive/MyDrive/datasets/landscapes' \
--outdir='/content/drive/MyDrive/results_stylegan2_ada_landscapes'

这个命令和我以前用抽象画训练的命令几乎一样。唯一的区别是 Google Drive 上风景文件夹的路径。这里有一个图表显示了景观训练的 FID 分数(绿线)。

抽象艺术和风景的培训结果——越小越好,作者图片

生成的风景比抽象画好得多。你可以看到,在大约 150 次迭代后,它在 25 左右触底。风景比抽象画得分高的原因可能是由于更大的训练集-4800 幅风景和 850 幅抽象画。

假风景

这里有一些生成的风景照片,是经过四天的 SG2A 训练后创作的。

生成的风景照片图片作者

这些看起来很不错。地平线有点扭曲,云看起来有点不可思议,但它们可以作为真实的风景照片。现在让我们看看这种学习是否有助于创造抽象艺术。

转移学习

实验的下一步是重新训练 SG2A 从之前在风景上训练的模型开始创作抽象艺术。这里有一个流程图显示了这一过程。

学习创作风景后学习绘画抽象艺术,作者图片

在甘人被训练去创造风景后,他们被进一步训练去利用先前的风景知识创造抽象画。我用第三个谷歌实验室训练了这个系统。下面是我使用的 shell 命令。

python stylegan2-ada/train.py --aug=ada --target=0.7 \
--mirror=1 --snap=1 --gpus=1 \
--data='/content/drive/MyDrive/datasets/paintings' \
--resume='/content/drive/MyDrive/results_stylegan2_ada/00006-landscapes-mirror-auto1-ada-target0.7-resumecustom/network-snapshot-000048.pkl' \
--outdir='/content/drive/MyDrive/results_stylegan2_ada_tl' 

我正在使用抽象画进行训练,但是恢复选项从用风景训练甘开始训练。最后的训练花了大约四天时间。这是一张 FID 分数的图表。新的结果是蓝色的。

采用迁移学习的抽象艺术培训结果——越小越好,作者图片

你可以看到迁移学习帮助提高了分数。最近一次训练的 FID 值稳定在 85 左右,比之前的 105 分要好。这里有一些受益于迁移学习的样本图片。

style gan 2 ADA 带迁移学习的输出,图片作者

这可能很微妙,但用迁移学习模型创建的图像看起来更精致,更令人愉快。请查看下面的附录中的样本库。

生成图像

一旦训练好 GAN,就可以使用这个命令行生成图像。

python stylegan2-ada/generate.py --seeds=1-4 --trunc=1.5 \
  --outdir results --network=network-snapshot-000188.pkl

这将使用随机种子 1、2、3 和 4 生成四幅图像。截断参数 trunc 将决定图像中的变化量。我发现默认值 0.5 太低了,1.5 给出了更多的变化。

创作你自己的画

一个用于生成各种长宽比的图像的 Google Colab 在这里可用。它可以生成 21 幅图像,并让你选择一幅以高分辨率观看。这是一个图像样本。

由 MachineRay 2 Google Colab 生成的样本图片,图片作者

后续步骤

额外的工作可能包括培训风景画,而不是照片的迁移学习。这可能有助于甘将绘画风格应用于抽象画。

感谢

我要感谢詹尼弗·林、奥利弗·斯特林佩尔、马赫萨·梅斯加兰和瓦希德·呼罗珊对这个项目的帮助和反馈。

源代码

我收集的 850 幅抽象画可以在 Kaggle 这里找到。这个项目的所有源代码都可以在 GitHub 上获得。这些源代码在 CC BY-NC-SA 许可下发布。

署名-非商业性使用-类似分享

参考

[1]t . Karras,m . Aittala,j . hells ten,Laine,s . lehti nen,j .和 Aila。用有限的数据训练生成性对抗网络。,2020 年 10 月 7 日,https://arxiv.org/pdf/2006.06676.pdf

[2] Eiter,t .和 Mannila,h .,“计算离散的 Fréchet 距离”,Christian Doppler labor für expertensyteme,1994 年 4 月 25 日,http://www . kr . tuwien . AC . at/staff/e ITER/et-archive/cdtr 9464 . pdf

[3] Bozinovskim S .和 ful gosi a .,“模式相似性和迁移学习对基本感知机 B2 训练的影响”信息研讨会会议录,3–121–5,1976 年

[4] Bozinovski,s .,“对神经网络中迁移学习的第一篇论文的提醒,1976 年”。informatica 44:291–302,2020,http://www . informatica . si/index . PHP/informatica/article/view/2828

附录 MachineRay 2 结果图库

创建与研究科学家一致的产品团队

原文:https://towardsdatascience.com/creating-aligned-product-teams-with-research-scientists-e4725ed735d7?source=collection_archive---------23-----------------------

当你的产品团队需要创新时,如何与研究科学家合作

在产品团队中建立产品管理、用户体验和工程之间的一致性是一项挑战。当你的产品依赖于创新技术时,在这种组合中包括研究科学家可能会产生额外的复杂性。

由兰迪父亲在 Unsplash 上拍摄的照片

在 IBM 的聊天机器人平台 Watson Assistant 的五年时间里,我与多个人工智能研究团队一起领导了各种产品任务。在这篇文章中,我将解释我们在产品和研究科学家团队之间经历的几种不同的合作模式。在我们成功地创建了一个团结的团队后,一些合作非常富有成效。在其他一些情况下,我们遭受了产生次优结果的跨学科冲突。

背景:我们的产品团队是如何工作的?

我们的产品团队围绕任务成果小队组织交付:

  • 一个 任务 是一个关注一些可测量的 结果 的交付。
  • A 小队 是拥有使命的跨职能团队,由产品经理、用户体验、工程经理领导。

我们为每个班配备完成特定任务所需的所有技能。理想情况下,每个小队都有一个任务,每个队员都被分配到一个小队。

例如,我们可能有一个“增加 20%上下文实体特性的参与度”的任务。这个任务的团队可能需要新用户体验的设计师,实现这些设计的 UI 开发技能,对我们的机器学习基础设施的改变(例如,减少训练时间),以及改进的机器学习模型(例如,在不影响训练时间的情况下提高算法性能)。

当我们需要人工智能创新时,协作面临挑战

围绕产品团队成员的任务创建团队是一项常规操作。当然,我们确实在努力应对典型的产品开发挑战:总是有优先级、路线图、运营和员工问题。当我们执行时,我们偶尔会遇到工程、产品管理和设计之间的跨学科分歧。

当产品团队与研究科学家合作解决人工智能难题时,额外的挑战出现了,特别是对于一个拥有大量客户的现有成功产品。

研究人员通常不属于产品组织,而是研究组织的成员。研究和产品组织之间的合作总是通过描述目标、计划和承诺的文档来计划和正式化。

要求研究人员“只是加入团队”并不总是奏效。属于不同组织的人通常有不同的文化、日常挑战、业务承诺和职业发展目标。

产品团队制定了严格的工程实践和团队仪式,以管理常规的跨学科冲突,避免客户不满。总有一些重要的里程碑、重要的客户和运营挑战需要担心。产品经理和设计师担心 A/B 测试、NPS、转化和参与度指标。工程团队筛选每一个拉动请求,担心缺陷或生产事故会影响生产。

另一方面,研究团队试图解决看似不可能的问题。他们创建各种原型,通常从事多个需要实验的开放式项目。客户压力、生产事故和业务目标对他们来说并不是常规挑战。然而,他们必须赶上技术趋势,发表论文,并为未来的研究项目争取资助。

三种合作模式

尽管理想的合作是创建一个来自所有学科的团队来交付一个结果,但上面概述的差异使这变得困难。团队成员或管理层对理想协作的愿景有时会被业务约束和个性所掩盖。

模式 1:通过依赖关系控制协作

开始协作的最快方式是将产品和研究团队分开,并通过依赖关系来管理协作。然而,团队经常在以后为这个初始速度买单。

模式 1:通过依赖关系控制协作

在这种模式下,在最初的启动研讨会之后,研究团队基本上独立于产品团队工作。产品管理描述业务目标,技术领导同意高级技术路线和时间表。然后,两个团队分开工作,除了技术领导和经理之间的定期检查点会议。代码工件可以保持分离,产品团队定期采用这些研究工件。

缺乏跨领域协作经验的团队倾向于默认这种方法,因为它的“快速启动”特性。孤立的团队在早期阶段似乎进步很快。然而,这种速度通常是一种错觉,随着失调和误解的出现,团队要付出很多倍的代价。

这种协作模式也将研究人员与客户需求隔离开来。通常,期望的用户体验、操作约束和业务需求对 AI 算法提出了要求。断开连接的研究团队无法获得 A/B 测试的实时更新、用户研究结果以及来自产品管理的更新。新的人工智能算法最终没有满足客户的需求,即使它击败了所有的研究基准。

如果两个团队开发的组件已经存在,或者如果它们有明确定义的边界和 API 契约,这种类型的合作可能会产生好的结果。如果存在团队和组织之间的功能失调,这种模式也往往会出现。这种隔离让双方都能取得进展,但也将冲突推迟到以后处理。

模式 2:单个班的部分合作,有行动限制

通过创建一个单独的团队,更紧密的合作是可能的,但对研究和产品团队如何在任务中合作有规则和限制。当研究团队需要或喜欢某种程度的独立性时,这种模式可以很好地用于面向客户的任务。

模式 2:单个班的部分合作,有行动限制

操作是这种协作中经常协商的要素。研究团队可能不具备部署、维护和寻呼机工作的技能或兴趣。类似地,模仿团队边界的源代码控制边界往往会形成,规则规定谁可以在相同的应用程序边界内交付、审查或合并不同组件的代码。

谁加入队伍仪式也可以被有意地限制。可能只有一两个研究负责人总是加入 scrums 和 playbacks,而其他人则远离这些活动。一些(或全部)研究团队在这种产品任务上的分配少于 100%也是很常见的。制定这些规则的原因通常是其他并行的产品或研究合作、会议以及出版所需的时间。

这种模式运作良好的先决条件是,至少有一名工程团队成员和一名研究团队成员不受任何限制地“无所不在”,并且 100%地参与任务,没有其他兼职。理想情况下,这些工程和研究领导作为所有工程师和研究人员的技术领导。他们主导端到端的产品功能,甚至参与运营。拥有两个这样的具有工程和学术/人工智能印章的模范领导,极大地帮助了产品和研究团队之间的沟通。

寻找具有如此广泛技能和动机的人才可能很难。除了系统招聘之外,一个组织需要有一个训练有素的方法在内部培养这样的人才。雇用合适的人的组织文化激励学习和“流动”对于培养和留住这样的人才至关重要。

模式 3:在一个小队中充分合作

这种模式是关于有一个班,每个人都 100%分配到任务,除了任务什么都没有,对任何一个队都没有特殊的规则或限制。

模式 3:在一个小队中充分合作

这种模式非常适合面向客户的任务。每个团队成员关注相同的结果,参加相同的会议,看到相同的实验结果,担心相同的用户角色。

当所需的创新受到明确定义的领域的限制时,这种模式也很有效。当研究和产品团队专注于客户驱动的结果时,开放式的研究挑战和“寻找将推动产品方向的算法”不会很好地工作。

当它起作用时,这种协作模式也是团队成员个体最满意的。研究团队喜欢看到他们的研究成果帮助实际客户。他们中的一些人欣赏他们在与工程师合作部署和扩展他们的解决方案时获得的新技能。产品团队成员非常喜欢成为创新研究的一部分,并对研究团队的工作方式有了更多的了解。

然而,“一个小队,一个任务”并不总是发生,即使是在标准的产品团队中。为了赶上最后期限,要求工程师或设计师“帮助另一项任务进行几个冲刺”的情况并不少见。研究人员也有类似的冲突。做“研究工作”、写论文、参加会议或参与其他合作所需的时间。

此外,如果产品和研究领导之间存在个人或激励冲突,早期阶段的“一个团队,一个任务”可能会混乱。

你该怎么办?

作为一个单一的以结果为导向的跨职能团队(或者它的老校名,“特色团队”)工作,虽然理想和有趣,但并不总是容易的。在产品团队中,作为一个单独的团队,成功地协作可能会遇到许多组织和个人的障碍。

如果你的产品团队没有在跨职能团队中工作的经验,从“单一团队,单一任务”开始可能会更难。尽管跨职能团队对于产品团队来说不是一个新概念,但是围绕组件和规程创建边界在许多产品组织中仍然很常见。随着研究人员的加入,拥有一些在跨职能团队中工作经验丰富的团队成员将有助于这种合作模式的成功。

最后,只是给团队时间来弄清楚他们应该如何合作有时是正确的策略。在我经历的早期,我们能够在大约 60%的时间里预先确定并执行我们希望如何与人工智能研究团队合作。在剩下的时间里,我们的协作方法随着时间的推移和实验而出现(在一些冲突和失败之后),并且主要由约束和个性形成。

然而,随着我们获得了更多的经验,随着产品和研究团队中更多的人在几个成功故事之后开始看到光明,我们的研究团队执行“单个团队,单个任务”方法的成功率显著增加。

用 Python 和 SQL 创建电子邮件解析器

原文:https://towardsdatascience.com/creating-an-email-parser-with-python-and-sql-c79cb8771dac?source=collection_archive---------2-----------------------

通过自动从电子邮件中提取数据来提高您的工作效率

Solen Feyissa 在 Unsplash 上拍照

嗯,那是什么?一个邮件解析器?

您可能想知道什么是电子邮件解析器,为什么您可能需要一个。

简而言之,电子邮件解析器是一种从入站电子邮件和附件中寻找和提取数据的软件。更重要的是,电子邮件解析器使用条件处理来提取对您重要的特定数据。

那么,为什么这很重要呢?如果你曾经从事过常规的办公室工作,你可能会非常熟悉报表,或者说,从 Microsoft Outlook 向 Excel 或 Word 复制粘贴文本行。

你甚至可能一周又一周地重复同样的报告。再加上格式和拼写检查,这会耗费你大量的时间,而你本可以专注于更重要的任务。

好消息是,您可以使用 Python 和 SQL 来自动化这个过程的大部分。

在这篇文章中,我将介绍如何用 Python 打开 Outlook 电子邮件,并将正文提取为 HTML。然后,我将介绍如何用 Python 解析这些数据,以及如何将最终数据上传到 SQL 数据库。从那里,您可以将这些数据写入 Excel 或将其转换成 Pandas 数据框架。

入门指南

我们将在这里使用几个关键的 Python 库,即ossqlite3pywin32

首先,我们需要决定我们想从邮件中提取什么。例如,假设我们有一堆电子邮件,每封邮件都包含一个新闻文章列表,如下所示:

假设我们想要提取每个要点的,它包括标题、出版物、媒体平台和 URL 链接。简而言之,我们希望将每个项目符号的整个标题提取出来,然后将其分成四个不同的部分。

我们要从中提取文本的示例标题

到目前为止,我们的伪代码应该是这样的:

1\. Create list of emails that we want to parse
2\. Open first email
3\. Iterate over each bullet point
4\. Extract data from bullet point
5\. Upload data from bullet point to a database
6\. Repeat until all data is parsed, then move to next email

创建 SQL 数据库

在解析我们的电子邮件之前,我们首先要用 Python 建立一个 SQL 数据库。我们将通过使用一个名为db的连接对象建立到 SQLite 数据库的连接来实现这一点。

# Create & connect to database
db = sqlite3.connect("emails.db")

如果它还不存在,一个新的数据库将被创建为emails.db。然后,我们可以在数据库中创建表,稍后电子邮件解析器可以写入这些表。

# Create empty tables
db.execute("""
CREATE TABLE IF NOT EXISTS "articles" (
"id" INTEGER,
"title" TEXT UNIQUE,
"publication" TEXT,
PRIMARY KEY("id" AUTOINCREMENT))
""")db.execute("""
CREATE TABLE IF NOT EXISTS "links" (
"article_id"    INTEGER,
"link0" TEXT,
"link1" TEXT,
"link2" TEXT,
PRIMARY KEY("article_id"))
""")db.execute("""
CREATE TABLE IF NOT EXISTS "platforms" (
"article_id"    INTEGER,
"platform0" TEXT,
"platform1" TEXT,
"platform2" TEXT,
PRIMARY KEY("article_id"))
""")

实质上,我们创建了三个表,其中我们的主表是“文章”,它与“平台”和“链接”有一对多的关系。换句话说,这反映了一篇文章可以有许多不同的平台和链接。

我们的数据库模式

在 Python 中访问您的电子邮件

您需要将希望解析的电子邮件从 Outlook 移动到一个文件夹中。最简单的方法是拖放。

拖放方法的演示

接下来,创建一个变量来存储电子邮件的文件夹路径。您可以手动操作,如folder_path = r‘C:\Users\Username\EmailFolder’或使用tkinteros,这将生成一个文件浏览器提示来选择一个文件夹。

# Create an folder input dialog with tkinter
folder_path = os.path.normpath(askdirectory(title='Select Folder'))

用 tkinter 获取我们的文件夹路径

这里,我们使用用tkinter创建的文件输入提示来保存我们的文件夹路径,然后用os规范化路径来删除任何多余的分隔符。

然后,我们希望获得每封电子邮件的路径标题。我们可以用os.listdir()来实现,它给出了指定目录中所有文件的列表。

# Initialise & populate list of emails
email_list = 
[file for file in os.listdir(folder_path) if file.endswith(".msg")]

这将保存列表中每个电子邮件的文件名,以便我们以后访问。

将 Outlook 连接到 Python

接下来,您将需要创建一个对象,允许我们从 Python 中控制 Outlook。这是通过pywin32库实现的,该库有助于通过微软 Outlook 消息传递 API (MAPI) 将 Python 连接到 Outlook。

# Connect to Outlook with MAPI
outlook = win32com.client.Dispatch(“Outlook.Application”)
                  .GetNamespace(“MAPI”)

这样,我们可以开始将每个项目作为 HTML 对象打开,并使用正则表达式即 Regex 来提取每封电子邮件的正文。

虽然传统观点认为不应该使用 Regex 来解析 HTML,但我们并不担心这一点,因为我们只希望从标准电子邮件格式中提取非常具体的文本片段(一些商业电子邮件解析器,如 Parseur 主要围绕 Regex 构建)。

从这一点来看,Regex 可以用来缩小您想要提取的特定数据的范围。

# Iterate through every email
for i, _ in enumerate(email_list): # Create variable storing info from current email being parsed
   msg = outlook.OpenSharedItem(os.path.join(folder_path,
   email_list[i])) # Search email HTML for body text
   regex = re.search(r"<body([\s\S]*)</body>", msg.HTMLBody)
   body = regex.group()

用 Python 解析电子邮件 HTML

这是我们的电子邮件的第一个要点可能看起来像 HTML:

我们的电子邮件片段的 HTML 视图

好的——我们可以看到这里有几个关键特征,即我们的数据以项目符号列表或li class=MsoListParagraph的形式存在。我们可以使用正则表达式来提取每个项目符号。

# Search email body text for unique entries
pattern = **r"li class=MsoListParagraph([\s\S]*?)</li>"**
results = re.findall(pattern, body)

每个项目符号都被提取为一个字符串,每个字符串都存储在一个列表中。我们的第一个要点应该是这样的:

用正则表达式(Regex101.com)缩小 HTML 正文的范围

为了检索我们的标题和出版物,我们可以再次使用 Regex。这一次,我们还将在文本上使用 call html.unescape()来帮助将 HTML 翻译成字符串,例如&8211;→-(unicode 破折号)。

regex = re.search(r**"[^<>]+(?=\(|sans-serif’>([\s\S]*?)</span>)"**, header)# HTML unescape to get remove remaining HTML
title_pub = html.unescape(regex.group())

我们的正则表达式返回高亮显示的文本作为上面的变量

从这里开始,它就像拆分我们的文本一样简单。我们可以用split_list = title_pub.split("–")给我们一个列表:["New Arrival: Dell G Series Gaming Computers", "Tech4tea"]

然后,我们可以删除任何多余的空白,并将每一项保存为一个变量。

title = split_list[0].strip()
publication = split_list[1].strip()

已经两次了!

为了获得我们的媒体平台,我们将使用一种更简单的方法。

# List of publications to check for
platform_list = ["Online", "Facebook", "Instagram", "Twitter", "LinkedIn", "Youtube"]# Create empty list to store publications
platform = []# Iterate and check for each item in my first list
for p in platform_list:
   if p in header:
      platform.append(p)

这将给我们一个出版物列表:["Online", "Facebook", "LinkedIn"]

现在来看看网址:

# Find all links using regex
links = re.findall(r"<a href=\”([\s\S]*?)\”>", header)

这将为我们提供下面以绿色突出显示的字符:

很漂亮,对吧?

到目前为止,我们的数据应该是这样的:

Title: New Arrival: Dell G Series Gaming Computers
Publication: Tech4tea
Platform: [‘Online’, ‘Facebook’, ‘LinkedIn’]
Links: [‘[http://tech4tea.com/blog/2020/06/26/new-arrival-dell-g-series-gaming-computers-monitors-keyboards/'](http://tech4tea.com/blog/2020/06/26/new-arrival-dell-g-series-gaming-computers-monitors-keyboards/'), ‘[https://business.facebook.com/gotech4tea/posts/4598490146843826'](https://business.facebook.com/gotech4tea/posts/4598490146843826'), ‘[https://www.linkedin.com/feed/update/urn:li:activity:6682511823100542976/'](https://www.linkedin.com/feed/update/urn:li:activity:6682511823100542976/')]

将数据上传到 SQL 数据库

这个过程的最后一步是将每条数据上传到我们的 SQL 数据库。

我们将从上传我们的标题和出版物数据开始。这可以通过下面的代码来实现:

# Insert title & pub by substituting values into each ? placeholder
db.execute("INSERT INTO articles (title, publication) 
VALUES (?, ?)", (title, publication))

上传我们的链接和平台有点棘手。首先,我们将从主表中复制主 id,然后逐个迭代每个平台和链接。

# Get article id and copy to platforms & links tables
article_id = db.execute(“SELECT id FROM articles WHERE title = ?”, (title,))for item in article_id:
   _id = item[0]for i, _ in enumerate(platform):
   db.execute(f”UPDATE platforms SET platform{i} = ? WHERE    
   article_id = ?”, (platform[i], _id))for i, _ in enumerate(links):
   db.execute(f”UPDATE links SET link{i} = ? WHERE article_id = ?”, 
   (links[i], _id))# Commit changes
db.commit()

这里的最后一步是将所有这些更改提交给数据库。完成后,我们的电子邮件解析器就完成了!如果您愿意,您可以使用类似于 DB 浏览器的工具来检查您的数据库内容是否已经成功更新。

使用数据库浏览器查看数据库

如果你需要的话,我已经在我的网站和 Github 上传了完整的代码。

在自动气象站上创造一个有气流和 DBT 的环境(第一部分)

原文:https://towardsdatascience.com/creating-an-environment-with-airflow-and-dbt-on-aws-part-1-ca13bc95f479?source=collection_archive---------8-----------------------

启动实例并安装气流

在 Unsplash 上万圣业拍摄的照片

在研究气流的时候,我试着用它来安排一些 DBT 的工作。虽然我在互联网上找到了一些关于它们的设置和一些关于它们的集成的资源,但我在设置我可以测试集成选项的整个环境时遇到了一些麻烦,比如 API 调用或 DBT 命令。

当我达到我所需要的时候,我必须做很多设置,安装操作系统库或 Python 库,以及诸如此类的事情。所以,我意识到从零开始再做一次有点难。此外,不仅我可能不得不再次这样做,而且有人可能会有同样的问题,并利用这些步骤。于是,我又做了一遍,记下了所有的事情。

本文的主要目标是展示如何配置同时具有气流和 DBT 的环境,并集成这两种工具。

我不会试图解释这两个工具到底是什么或者它们的更高级的资源。基本上,DBT 是一个使用 SQL 在数据仓库中转换数据的工具。Airflow 是一个基于 Python 的工具,用于编排和调度工作流。好吧,既然你在使用 Python,基本上你可以对各种东西进行编排。但是如果你看到了这个页面,你可能已经知道它们是什么以及它们是如何工作的了。我希望这篇文章可以帮助你作为一个起点,然后你可以延伸到你自己的需求。

还有,我不会用更复杂更合适的架构。因为我们的目标是集成气流和 DBT,所以我将在这个环境中使用最简单的配置。所以,我不会用其他像芹菜或 Kubernetes 的气流执行器。

为此,我们将启动一个 EC2 实例,安装这两个工具,对它们进行配置,并在这两个工具上创建一些东西,这样我们就可以集成它们。

1。在 AWS 上启动 EC2 实例

如果您知道如何在 EC2 上启动一个实例并连接到它,那么您可以按照自己喜欢的方式来做,然后跳到下一步。

我将在 AWS 上使用 t3a.medium EC2 实例。起初我试图使用 t2.micro,因为它在空闲层,但是一些命令冻结了机器。你可以尝试使用 t2.micro,但我不推荐。

要启动实例,我们可以使用 Amazon AMI OS 和所有默认设置。只要继续点击下一步,直到安全组页面。在此页面中,选择“创建新的安全组”。根据需要命名,并添加一个规则,选择“所有流量”类型和“我的 IP”源。点击查看并启动。这将允许您进行 SSH 连接(端口 22)并打开气流页面(端口 8080)。如果您愿意,您可以只创建这两条规则。

AWS 上的安全组。这就像它的防火墙

下一页显示了实例的摘要。当您单击 Launch 按钮时,您会收到一个弹出窗口,要求您设置密钥对。如果您没有或不确定要选择什么,请选择“创建新的一对”选项。给文件命名,然后按“下载密钥对”按钮。确保您下载了密钥对文件(一个带有。pem 扩展名),然后单击“启动实例”。

下载实例的密钥对文件的唯一机会

您可能需要等待几分钟才能运行实例。当新实例的状态为 Running 时,选择它并单击 Connect 按钮。选择 SSH 选项卡并复制 SSH 命令的示例(“SSH-I your-key . PEM ec2-user @ something”)。

要连接到实例,您可以直接使用终端或 Putty。但我将继续使用 Visual Code Studio,因为它是我们稍后也要使用的工具,我们可能会在 Windows 或 Linux 上使用相同的过程。

在 Visual Studio 代码上,转到左上角的扩展图标。搜索 SSH-Remote 扩展并下载它。

远程 SSH 扩展

安装后,按 F1,数字 SSH,你会看到新的扩展选项。选择“添加新的 SSH 主机”并粘贴 AWS 的示例。

将连接添加到实例中

添加连接后,将显示一个带有打开配置的弹出窗口(如果没有,请按 F1,编写 SSH 并选择“打开 SSH 配置文件”)。在该文件中,您将拥有一个主机,其主机和主机名与您在 AWS 上看到的 EC2 实例主机相同。您可以为 Host 使用更重要的文本。只是不要改变主机名。在“身份文件”字段中,您将只有。pem 文件。写入文件的完整路径(在 Windows 上,类似于“C:\ Users \ UserName \…\ name-of-the-file . PEM”);在 Ubuntu 上,类似“/home/users/UserName/…/name-of-file . PEM”的东西。保存文件。

SSH 配置文件,其中包含。pem 文件

现在,按 F1,写 SSH,选择“连接到主机”。选择您用作主机的名称。如果一切正常,您将有一个新的 VSCode 窗口连接到 EC2 实例。如果文件有错误。pem,您可能需要在路径中从“/”切换到“\”,反之亦然。现在,我们必须修改。pem 文件。

打开终端(菜单终端>新建终端,或点击终端选项卡),转到保存有 cd 的文件的目录。

现在,如果您使用的是 Linux,请使用以下命令:

$ sudo chmod 400 name-of-the-file.pem

如果您使用的是 Windows:

$ path = ".\name-of-the-file.pem"
$ icacls.exe $path /reset
$ icacls.exe $path /GRANT:R "$($env:USERNAME):(R)"
$ icacls.exe $path /inheritance:r

考虑到您现在已经连接到 EC2 实例,打开终端菜单,然后打开新建终端。使用下面的命令确保实例的操作系统得到更新。

$ sudo yum -y update

我们将使用的终端

2.安装气流及其要求

首先,让我们安装操作系统的先决条件。经过一些实验后,下面命令上的包似乎是必要的并且足以做我们想做的一切:

$ sudo yum -y install wget tar intltool icu4c gettext icu libicu-devel gcc-c++ python3-devel redhat-rpm-config gcc libffi-devel python-devel openssl-devel gzip gcc make expect openssl-devel bzip2-devel libffi-devel

在我们安装 Airflow 之前,我们需要升级 sqlite 版本。以下是命令。如果你对 sqlite 的链接有错误,请查看它的页面,因为它可能会被更新。

$ wget [https://www.sqlite.org/src/tarball/sqlite.tar.gz](https://www.sqlite.org/src/tarball/sqlite.tar.gz)
$ tar xzf sqlite.tar.gz
$ cd sqlite/
$ export CFLAGS="-DSQLITE_ENABLE_FTS3 \
-DSQLITE_ENABLE_FTS3_PARENTHESIS \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_JSON1 \
-DSQLITE_ENABLE_LOAD_EXTENSION \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_STAT4 \
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \
-DSQLITE_SOUNDEX \
-DSQLITE_TEMP_STORE=3 \
-DSQLITE_USE_URI \
-O2 \
-fPIC"
$ export PREFIX="/usr/local"
$ LIBS="-lm" ./configure -disable-tcl -enable-shared -enable-tempstore=always -prefix="$PREFIX"
$ make
$ sudo make install

现在,打开/etc/environment 文件:

$ sudo vi /etc/environment

并添加这些行,这样就加载了正确版本的 SQLite。当您执行上面的命令时,终端中会打开一个空白文件。如果您使用 vi(如上面的命令)进入编辑模式,请按“I”。然后,给下面的线编号或粘贴。按 ESC 退出编辑模式。然后数字':w '和回车保存文件。现在,数字':q '和回车退出文件。一开始可能有点棘手,但你会习惯的。

export LD_LIBRARY_PATH="/usr/local/lib"
export LD_RUN_PATH="/usr/local/lib"

并运行以下命令来加载修改后的文件:

$ source /etc/environment

使用以下命令检查操作系统上的 sqlite 版本和 Python 识别的版本:

$ sqlite3 --version
$ python3 -c "import sqlite3; print(sqlite3.sqlite_version)"

如果一切正常,两者都将返回版本 3.36(或更高版本,取决于您何时执行该过程)。

在操作系统和 Python 上检查 SQLite 版本

现在,让我们创建一个拥有气流装置的用户:

$ sudo adduser airflow

并使用以下命令为用户定义密码:

$ sudo passwd airflow

我继续使用“气流”这个密码,但是你可以随意选择一个更好的。请注意,如果我在某个地方使用了密码,而你有不同的密码,请用你的密码交换。

使用下面的命令编辑文件,将新用户添加到 sudoers 文件中:

$ sudo vi /etc/sudoers

搜索“root ALL=(ALL) ALL”行。将这一行复制粘贴到下面,将“根”部分切换为“气流”(该行将是:气流全部=(全部)全部)。

将 airflow 用户添加到 sudoers 文件中

使用命令切换到新用户,然后输入密码:

$ su airflow -

让我们为 airflow 安装创建一个目录,为虚拟环境创建一个目录,然后创建一个 venv 来安装 airflow:

$ mkdir ~/airflow
$ mkdir ~/.venv
$ python3 -m venv ~/.venv/airflow

通过以下方式激活新环境:

$ source ~/.venv/airflow/bin/activate

现在,运行这两个命令来安装更多 Airflow 需要的依赖项:

$ sudo python3 -m pip install -U pip
$ sudo python3 -m pip install -U setuptools

现在,我们要安装气流。从 Apache Airflow 页面中的命令,我们必须将 python 改编为 python3,将 pip 改编为 pip3。因此,我们有以下内容:

$ AIRFLOW_VERSION=2.0.1
$ PYTHON_VERSION="$(python3 --version | cut -d " " -f 2 | cut -d "." -f 1-2)"
$ export AIRFLOW_HOME=~/airflow
$ CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt"
$ pip3 install --upgrade "apache-airflow[postgres,google]==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}"

现在,转到 Airflow 主目录并初始化 airflow 元数据数据库:

$ cd ~/airflow
$ airflow db init

如果一切正常,您应该会看到类似 airflow.cfg 和 airflow.db 的文件。

气流目录中的文件,在我们初始化它之后

现在,要以最简单的方式运行气流,我们需要运行两个服务。其中一个是调度器。为此,只需在终端上运行以下命令:

$ airflow scheduler

当您运行这个命令时,您的终端将被该服务的所有输出“锁定”。因为我们仍然需要运行第二个服务,所以我们需要打开第二个终端。在 VSCode 中,我们只需进入终端菜单,选择新终端。第一个航站楼将继续运行,并将开通一个全新的航站楼。如果您从一开始就遵循了整个过程,那么将再次与 ec2 用户建立远程 ssh 连接。我们需要切换到 airflow 用户并激活我们创建的虚拟环境:

$ sudo su airflow -
$ cd ~
$ source ~/.venv/airflow/bin/activate

最后,运行我们需要的第二个服务:

$ airflow webserver

我们有足够的证据来检查气流是否流动。转到您的浏览器,使用端口为 8080 (http://#的实例的 IP 或主机名作为 URL。##.###.###:8080).可能需要几秒钟才能访问应用程序。如果您在使用此地址时遇到一些错误,请检查您的浏览器是否正在尝试使用 https 而不是 http。必须是 http。

气流初始页面

现在,即使气流页面正确打开,我们仍然无法登录。为此,我们需要创建一个用户。因为我们使用的两个终端正在运行服务,所以我们需要再打开一个,以便再次在实例上运行命令。打开新的终端,回到我们的用户和 python 环境:

$ sudo su airflow -
$ cd ~
$ source ~/.venv/airflow/bin/activate

现在运行下面的 airflow 命令来创建用户:

$ airflow users create -u admin -p admin -f FirstName -l LastName -r Admin -e name@mail.com

在这里,您可以将参数切换到您喜欢的用户名、密码等。

现在,回到您的浏览器,使用您选择的登录名和密码。您将看到示例 Dag 列表。

3.测试气流装置

转到 VSCode。考虑到您仍然连接到实例,激活了 Airflow 用户和虚拟环境(确保在每个命令的开头都有“(airflow)”。转到 Airflow 安装文件夹,创建 Airflow DAGs 的目录,并转到该目录:

$ cd ~/airflow
$ mkdir dags
$ cd dags

创建新文件:

$ vi test.py

并添加以下代码:

from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from datetime import datetimedefault_args = {'start_date': datetime(2021,1,1)}def test():
    print('Success')with DAG('test_dag', default_args=default_args, schedule_interval='@daily', catchup=False) as dag: task_1 = PythonOperator(task_id='task_1', python_callable=test)

回到你的浏览器,在气流页面。

刷新页面并检查 Dag 列表中的新文件。加载 DAG 可能需要几分钟时间。

我们在狗狗列表中的新狗狗

打开新的 DAG。打开 DAG 名称左侧的开关。刷新页面。

打开 DAG 的开关

转到图表视图。检查任务是否标记为绿色。

像往常一样,绿色是一个好信号

点击它并进入日志。用我们打印的文本检查这一行。“成功”。

我们想要的信息

仅此而已。

在本文的下一部分中,我们将在这个实例上安装 DBT,进行一些设置以简化一些事情,在 AWS 上启动一些实验所需的其他资源,配置 DBT 并使用 Airflow 来调度 DBT。

阅读本文的所有部分:

第 1 部分:启动一个实例并安装气流
第 2 部分:安装 DBT 和一些设置使工作更容易
第 3 部分:使用 DBT 云并将气流与 DBT 集成

参考

https://docs.aws.amazon.com/ https://airflow.apache.org/ https://air flow . Apache . org/docs/Apache-air flow/stable/installation . htmlhttps://charlesleifer . com/blog/compilating-SQLite-for-use-with-python-applications/

对我在这里所做的大部分事情有帮助的来源: https://www.datascienceacademy.com.br【葡萄牙语】 https://academy.astronomer.io/https://www . udemy . com/course/the-complete-hand-on-course-master-Apache-air

在自动气象站上创造一个有气流和 DBT 的环境(第二部分)

原文:https://towardsdatascience.com/creating-an-environment-with-airflow-and-dbt-on-aws-part-2-a23617d56eeb?source=collection_archive---------11-----------------------

安装 DBT 和一些设置,使工作更容易

在 Unsplash 上由 Boitumelo Phetla 拍摄的照片

在本文第 1 部分的中,我们启动了一个 EC2 实例,安装了一些操作系统需求,然后是气流。现在,我们将安装 DBT。但是首先让我们做一些设置来简化一些事情。

1。使用 airflow 用户连接到 ec2 实例

到目前为止,我们使用默认用户 ec2-user 连接到 EC2 实例。然后我们转向用户气流,我们装置的所有者。我们可以简化连接步骤,允许与气流用户直接连接。为此,首先转到 VSCode,连接到 EC2 实例并切换到 airflow 用户。现在,我们需要创建一个目录来存储 ssh 授权的密钥,复制包含它们的文件(该文件允许使用。pem 文件在我们启动实例时生成)并调整一些权限。以下是命令。

$ mkdir ~/.ssh
$ sudo cp /home/ec2-user/.ssh/authorized_keys ~/.ssh/authorized_keys
$ sudo chown airflow:airflow ~/.ssh/authorized_keys
$ sudo chmod 700 ~/.ssh
$ sudo chmod 600 ~/.ssh/authorized_keys

在 VSCode 中,按 F1,键入 SSH 并选择“添加新的 SSH 主机”。现在,使用我们在第 1 部分中使用的相同命令,但是改变用户。

ssh -i airflow_server.pem airflow@myinstancehost

按照第 1 部分的相同说明调整的路径。pem 文件在 SSH 配置文件中,为新连接选择一个名称,然后保存文件。

带有新连接的 SSH 配置文件

之后,再次按 F1,选择连接到主机,并选择新的连接。现在,您已连接到带有气流用户的实例。每当您需要停止实例并再次连接时,您可以考虑对这个用户使用这个连接。

2.自动启动气流服务

要像第 1 部分那样启动 airflow,我们只需运行 Airflow 命令(webserver 和 scheduler)。但是我们必须打开两个终端,并让它们在 VSCode 上打开。我们可以使用 nohup 从终端分离命令。更好的选择是将这些服务作为守护进程运行。这不仅可以更容易地启动/停止服务,还可以更容易地自动启动服务和实例。

为此,我们将使用 Airflow github 中的可用文件,并做一些调整。

首先,在/etc/sysconfig 中创建一个文件,名为 airflow:

$ sudo vi /etc/sysconfig/airflow

而内容:

AIRFLOW_CONFIG=/home/airflow/airflow/airflow.cfg
LD_LIBRARY_PATH=/usr/local/lib

这定义了运行 airflow 命令时将使用的两个环境变量,以及 Airflow 配置文件的路径和 sqlite 正确版本的目录。

现在,在/usr/lib/systemd/system 中创建一个名为 airflow-webserver.service 的文件:

$ sudo vi /usr/lib/systemd/system/airflow-webserver.service

内容如下。请注意,我正在传递端口,尽管我使用的是默认值 8080。如果您打算让其他应用程序使用 8080 端口在同一服务器上运行,您可以更改为使用另一个端口:

[Unit]
Description=Airflow webserver daemon
After=network.target postgresql.service mysql.service redis.service rabbitmq-server.service
Wants=postgresql.service mysql.service redis.service rabbitmq-server.service[Service]
PIDFile=/run/airflow/webserver.pid
EnvironmentFile=/etc/sysconfig/airflow
User=airflow
Group=airflow
Type=simple
ExecStart=/usr/bin/bash -c 'source /home/airflow/.venv/airflow/bin/activate; airflow webserver -p 8080 --pid /run/airflow/webserver.pid'
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-failure
RestartSec=5s
PrivateTmp=true[Install]
WantedBy=multi-user.target

在同一个目录中创建另一个文件,名为 airflow-scheduler.service:

$ sudo vi /usr/lib/systemd/system/airflow-scheduler.service

而内容:

[Unit]
Description=Airflow scheduler daemon
After=network.target postgresql.service mysql.service redis.service rabbitmq-server.service
Wants=postgresql.service mysql.service redis.service rabbitmq-server.service[Service]
PIDFile=/run/airflow/webserver.pid
EnvironmentFile=/etc/sysconfig/airflow
User=airflow
Group=airflow
Type=simple
ExecStart=/usr/bin/bash -c 'source /home/airflow/.venv/airflow/bin/activate; airflow scheduler --pid /run/airflow/webserver.pid'
KillMode=process
Restart=always
RestartSec=5s[Install]
WantedBy=multi-user.target

最后,创建一个文件/usr/lib/tmpfiles . d/air flow . conf,包含:

$ sudo vi /usr/lib/tmpfiles.d/airflow.conf

以及下面的内容:

D /run/airflow 0755 airflow airflow

现在创建一个目录,归 airflow 所有:

$ sudo mkdir /run/airflow
$ sudo chown -R airflow:airflow /run/airflow

好了,现在两个服务 Scheduler 和 Webserver 能够作为守护进程运行了。要让它们自动启动,只需运行以下命令:

$ sudo systemctl enable airflow-webserver.service
$ sudo systemctl enable airflow-scheduler.service

如果在启动实例后还没有启动 Airflow,现在只需运行:

$ sudo systemctl start airflow-webserver.service
$ sudo systemctl start airflow-scheduler.service

要检查服务的状态,可以运行以下命令

$ sudo systemctl status airflow-webserver.service
$ sudo systemctl status airflow-scheduler.service

绿色消息,显示服务正在运行

我们期望的结果是绿色的“活动(运行)”状态。如果您遇到不同的情况,显示服务没有运行,您可以使用命令检查服务的输出(100 是我想要显示的行数,您可以更改):

$ journalctl -u airflow-webserver -n 100
$ journalctl -u airflow-scheduler -n 100

3.安装 DBT

现在,是时候安装 DBT 了。由于我们将使用 Airflow 来编排 DBT 作业,并希望进行简单而廉价的配置,因此我们将把它安装在同一台服务器上。

如果您遵循了本文的第 1 部分,那么您已经安装了所有的操作系统需求。现在我们只需要安装 Python 包。首先,激活我们创建的 python 环境:

$ source ~/.venv/airflow/bin/activate

现在,安装安装 DBT 所需的这两个包

$ pip3 install pyicu-binary pyicu

最后,我们现在可以安装 dbt,命令如下:

$ pip3 install dbt

几秒钟后,您将看到成功的消息。如果在安装 dbt 的过程中,您收到一些失败的消息,告知您。h 文件没有找到,这可能是因为 gcc 包只寻找/usr/include 文件夹。如果发生这种情况,运行下面的命令来创建指向 gcc 试图找到的文件夹中的标题的符号链接:

$ sudo ln -sv /usr/include/python2.7/* /usr/include/

然后,您可以使用以下命令检查一切是否正常:

$ dbt --version

该命令将显示 dbt 及其插件的版本。

检查 dbt 版本时的输出

4.在 RDS 上启动数据库

DBT 是一个运行在数据仓库上的工具。虽然它与红移兼容,但也与 Postgres 兼容。为了避免一些意外的红移计费(由于空闲层周期过期或群集配置的资源/时间超过空闲层),这可能非常昂贵,我们将在 RDS 上使用 Postgres。您可以选择使用红移,只需注意我们将要进行的配置,您可能会在需要时进行切换。还要记住使用端口 5439,而不是 5432。

首先,转到 AWS 管理控制台并访问 RDS 页面。选择创建数据库。在配置页面,选择'标准创建',选择' PostgreSQL ',就可以保留 12.5-R1 版本。

创建数据库

选择自由层模板,以便更容易配置此数据库。为您的实例选择任意名称,主用户名和一些密码。

在“公共访问”选项中,您需要选择“是”,这样您就可以从您的网络进行连接。

您不需要更改此页面中的任何其他选项,只需单击“创建数据库”即可。

您将被重定向到数据库列表。选择您刚刚创建的那个。等待几分钟,直到您看到状态为“可用”。

点击数据库名称,进入配置页面。在“连接和安全”选项卡中,单击“VPC 安全组”中的链接。

打开安全组规则的链接

您将向数据库打开安全组规则。在页面的底部,有一些选项卡。选择入站规则,然后选择“编辑入站规则”。

向安全组添加新规则

单击“添加规则”。在类型中,选择“PostgreSQL”,在源中,使用 EC2 实例的私有 IP。然后,点击“保存规则”。如果您找不到这个 IP,您只需在一个新的选项卡上打开 EC2 页面,选择您的实例,并在“私有 IPv4 地址”中复制该 IP。

允许您的实例连接到数据库

现在,连接到您的新数据库(我建议使用 DBeaver,但是您可以自由选择您自己的工具)。

在 DBeaver 上创建连接非常简单

在默认数据库 postgres 中,创建两个模式,一个名为“data_warehouse ”,另一个名为“data_lake”。如果您愿意,也可以创建一个特定的数据库来完成这项工作,但是我将保持简单,使用 postgres 数据库。

Dbeaver 上的数据库连接,带有两个新模式

此外,在数据库上创建一个表并添加一些数据。只需在 DBeaver 上运行:

create table data_lake.user (name varchar(256), birth_date DATE, email varchar(256));insert into data_lake.user values
('Ted Mosby', '1978-07-04', 'ted.mosby@mosbiusdesign.com'),
('Robin Scherbatsky', '1980-12-04', 'bus.lady@world.com'),
('Barney Stinson', '1976-11-02', 'suitup@gnb.com'),
('Marshall Eriksen', '1978-03-16', 'fudge@supreme.com'),
('Lily Aldrin', '1979-09-22', 'comisisoner@slapbet.com');

5.配置 DBT

我们需要配置的第一件事是概要文件。在这个文件中,我们将信息连接到我们的数据仓库,所以当我们有不同的基础和模式时,这里是我们将要添加它们的地方。
存储该文件的默认路径是在一个名为. dbt 的隐藏文件夹中。您也可以更改权限以避免对该文件的未授权访问,因为现在,我们将把密码保存在该文件中。因此,要创建目录和文件:

$ mkdir ~/.dbt
$ vi ~/.dbt/profiles.yml

并添加信息以连接到您的数据库,在这种情况下切换到您自己的信息:

dw_dev:
  target: data_warehouse
  outputs:
    data_warehouse:
      type: postgres
      host: your-db-host
      user: postgres
      pass: postgres
      port: 5432
      dbname: postgres
      schema: data_warehouse
      threads: 4
      keepalives_idle: 0

现在,我们需要创建 dbt_project 文件。该文件包含有关项目的信息。让我们也创建一个文件夹来保存我们将与 DBT 一起使用的文件:

$ mkdir ~/dbt
$ cd ~/dbt
$ vi ~/dbt/dbt_project.yml

在 DBT 页面,你可以找到这个文件的例子。现在,我们将只添加一些属性。在提高 DBT 的使用后,您可以添加其他属性。因此,将以下内容添加到该文件中:

name: 'project_dbt_airflow'
config-version: 2
version: 1.0profile: dw_devsource-paths: ['source']
data-paths: ['data']
test-paths: ['test']
analysis-paths: ['analysis']
macro-paths: ['macro']
snapshot-paths: ['snapshots']models: +materialized: table
    +enabled: true

现在,创建文件夹来存储模型。sql 文件)。正如你在前面文件的内容中看到的,我们还可以有其他目录(用于测试、宏等。),但是我们现在不打算使用它们。此外,创建一个文件来运行我们在 DBT 的第一个模型:

$ mkdir ~/dbt/source
$ vi ~/dbt/source/user.sql

加上这一行:

select * from data_lake.user

现在,我们准备第一次运行 dbt。转到 dbt 项目文件夹并运行 dbt 命令:

$ cd ~/dbt
$ dbt run

运行 dbt run 命令后的输出

DBT 现在所做的是运行查询,然后用查询的结果创建一个模型(在本例中是一个表)。如果您有一个可以从数据仓库连接访问源数据的架构(就像 s3 上的数据湖,由带有 Spectrum 的 Redshift 上的数据仓库访问),您可以像这样运行模型查询您的源数据。如果不是这样,您首先必须将数据从您的源移动到您的数据仓库(正如 DBT 文档中所指定的,它只适用于 ETL 的 T)。但是你总是可以在气流上增加一些步骤来做这件事,作为你管道的一部分。

无论如何,您可以在 DBeaver 上检查数据仓库中的数据,使用:

select * from data_warehouse.user;

现在,我们已经在实例上安装了 DBT 和气流。在接下来的部分中,我们将集成它们,使用 Airflow 来编排 DBT 的作业,还将使用 DBT 云来检查其他集成选项。

阅读本文的所有部分:

第 1 部分:启动一个实例并安装气流
第 2 部分:安装 DBT 和一些设置使工作更容易
第 3 部分:使用 DBT 云并将气流与 DBT 集成

参考资料:

https://www.getdbt.com/
https://airflow.apache.org/
https://github . com/Apache/air flow/tree/master/scripts/systemd
https://docs.getdbt.com/reference/dbt_project.yml

对我在这里所做的大部分事情有帮助的来源: https://www.datascienceacademy.com.br
https://docs.getdbt.com/docs/introduction

在自动气象站上创造一个有气流和 DBT 的环境(第三部分)

原文:https://towardsdatascience.com/creating-an-environment-with-airflow-and-dbt-on-aws-part-3-2789f35adb5d?source=collection_archive---------11-----------------------

使用 DBT 云和 DBT 整合气流

田宽在 Unsplash 上拍照

在 part1 和 part2 中,我们创建并配置了我们的 EC2 实例,使用 DBT 和气流,并为两者创建了一个初始项目来测试它们。现在,我们将最终一起使用气流和 DBT,首先在我们的实例上,然后将 DBT 切换到云版本,也在那里创建一个项目。

1。使用气流运行 dbt 命令

正如我们已经看到的,基本上,气流调度和编排我们可以用 Python 运行的任何类型的任务。我们还看到了如何用命令 dbt run 运行 DBT。因此,我们可以集成它们的一种方法就是简单地创建一个 DAG,在我们的操作系统上运行这个命令。

假设您连接到 EC2 实例并使用 airflow 用户,创建一个 DAG 文件:

$ vi ~/airflow/dags/load_users.py

现在,添加以下代码:

from airflow import DAG
from airflow.operators.bash import BashOperatorimport datetimedefault_args = {
    'start_date': datetime.datetime(2021,1,1)
}def run_dbt(task_id, command):
    return BashOperator(
        task_id=task_id,
        bash_command='cd /home/airflow/dbt; ' + command,
        do_xcom_push=False
    )with DAG('load_user',
    schedule_interval="@daily",
    default_args=default_args, catchup=False) as dag: load_user = run_dbt('load_user', 'dbt run')

DAG 内的任务运行 bash 命令 dbt 运行,使用 Airflow 的 BashOperator。就像我们在终端上执行了命令一样。这里,我们必须从 DBT 文件夹(包含 dbt_project.yml 和其他目录的文件夹)运行这个命令,因此我们创建一个函数(run_dbt)来返回一个操作符,该操作符添加了移动到目录(' cd /home/airflow/dbt ')所需的命令。我们可以在运行 dbt run 时使用'- project-dir '来指定正确的路径,但我认为如果您有其他 dbt 命令来运行您的任务,这种方式会更简单。

保存文件后,您所要做的就是等待,直到新的 DAG 加载到 web 服务器中(在您的 web 浏览器中运行的气流)。当它是,打开开关和 DAG 将被执行。

我们的 DAG 运行 DBT(只有一个 DAG,因为我按名称过滤,好吗?)

单击 DAG 名称并转到图表视图。您的任务可能正在执行中(标有浅绿色)。几秒钟后,该任务将被标记为深绿色,表示成功。

我们的 dbt 任务由气流执行

如果您单击该任务并打开日志,您将看到与从终端运行 DBT 相同的输出:

输出显示了我们拥有的每个模型的执行情况(由 DBT 创建的每个表/视图)

由于 DBT 安装在 Airflow 的同一台机器上,我们可以只运行 dbt 命令来调用这个实例中的操作系统。如果您在另一台计算机上安装了 DBT,您还可以使用不同的方法来远程运行该命令,例如,使用 Airflow SSH Operator。

2.在 DBT 云上创建项目

现在,我们还可以选择不安装 DBT。使用 DBT 云,我们可以在那里创建我们的项目,并使用他们的基础设施运行我们的工作。为此,你必须在 DBT 页面(https://cloud.getdbt.com/login)上创建一个账户。

在登录之前,我们需要做两件事。

首先,转到 RDS 数据库使用的安全组的规则。编辑入站规则并添加另外三个规则,所有规则的类型都是 PostgreSQL,使用 IP 52.45.144.63、54.81.134.249 和 52.22.161.231。这些 IP 是 DBT 云使用的 IP,需要允许 DBT 连接到我们的数据库:

添加规则,以便 DBT 可以在我们的数据库中运行作业

我们必须做的另一件事是创建一个模式和一个用户来开发我们的 DBT 云项目。该用户将仅用于开发。它必须能够访问模式 data_lake 中的源表。此外,它将在新模式上创建表和视图(这个模式是专门为这个用户创建的),所以它也需要拥有这个权限。因此,使用 admin 用户运行下面的 SQL 代码:

create user dev_user with password '1234';
create schema dbt_dev;
grant all privileges on schema dbt_dev to dev_user;
grant usage on schema data_lake to dev_user;
grant select on all tables in schema data_lake to dev_user;

好,现在回到 DBT·佩奇。创建帐户后,当您第一次登录时,您会看到如下内容:

让我们用它来配置我们的项目。单击继续。在下一页中,您将选择数据库类型。在我们的例子中,PostgreSQL,所以选择它。在下一页中,您必须建立与我们数据库的连接。选择任何你想要的名字。在 PostgreSQL 设置中,您将使用该信息连接到 RDS 数据库(与您用于连接 DBeaver 或 SQL 工具的值相同)。在开发证书中,使用我们的新用户和模式。

建立连接,在 DBT 云上开发我们的 DBT 项目

点击继续。在下一页中,您可以选择使用 Github/Bitbucket/Gitlab 上的存储库。或者你可以使用由 DBT 管理的存储库。我们将使用后一种选择。因此,选择一个名称,单击创建,然后继续:

下一页允许您邀请人们在项目中与您一起工作。现在,你可以点击跳过并完成。

我们已经创建了我们的项目,DBT 将显示此页面:

点击开始开发,一个类似于 IDE 的页面就会打开。你需要做的第一件事是点击“初始化你的项目”。这将创建我们在 DBT 上运行作业所需的文件夹和文件。

开发页面,初始化项目后

现在,删除 models 中的 example 文件夹。在 models 中添加一个名为 user.sql 的新文件。

我们在 EC2 实例上创建的相同模型,现在在 DBT 云上

select * from data_lake.user

保存文件。在页面底部有一个运行命令的字段。键入“dbt run”并单击 Enter(您可以在上图底部看到该字段),您将得到以下输出:

在 DBT 云 IDE 上运行作业

这就是我们如何通过 DBT 开发我们的数据转换。现在,假设我们想在生产环境中使用这段代码。仍然在开发页面中,单击提交并添加一些消息。现在,我们的代码在主分支中(请记住,您可以使用 Github/Bitbucket/Gitlab 并以更好的方式管理存储库和分支)。

我们可以一直使用我们的数据库主用户,但是为了更真实,在上一部分中,我们使用了一个用户,该用户只具有从我们的源模式(data_lake)读取数据的权限,并且对它自己的模式 dbt_dev 具有所有特权。

现在,为了在“生产”环境中运行我们的作业,让我们创建另一个具有必要权限的用户。我们需要从模式 data_lake 中读取数据的权限,就像前面的用户一样。我们还需要在模式 data_warehouse 中创建对象的权限(我们的模型将在那里创建)。最后,由于在第 2 部分中我们已经创建了 data_warehose.user 表,现在我们将删除它,这样 DBT 重新创建它不会有任何问题。因此,使用 admin 用户运行以下 SQL 代码:

create user prd_user with password '1234qwer';
grant all privileges on schema data_warehouse to prd_user;
grant usage on schema data_lake to prd_user;
grant select on all tables in schema data_lake to prd_user;
drop table data_warehouse.user;

接下来,单击左上角的菜单,选择“环境”,然后单击“新建环境”。为环境选择一个名称,并使用我们的新用户、密码和模式 data_warehouse 配置连接(记住,在这个模式中,我们将使用查询结果创建对象)。不要更改其他选项。但是请注意,这里 DBT 云派上了用场,因为您可以选择一个自定义分支,并在将代码推送到主服务器之前运行作业。

DBT 云使创建新环境、与分支机构合作变得更加容易

创建环境后,您将看到 environment 页面,其中还没有作业。点击新工作。

为作业选择一个名称。在环境选项中,选择您将拥有的唯一选项。在线程中,我使用的是 10,但是现在这并没有什么区别。不要更改其他选项。

创造我们的工作

向下滚动,我们看到了将要运行的命令。由于我们的项目只有一个模型,当我们运行 DBT 时,这是唯一要处理的文件。但是如果您有一个更大的项目,并且只想运行您的模型的一部分,您可以过滤路径、标签和其他选项。请查阅 DBT 文档来探索这一点。

该页面中还有一个选项是调度作业。我们将使用气流来完成这项工作,因此您可以取消选中“按计划运行?”。

您可以通过 DBT 云直接安排工作,但只能安排您管道中的 DBT 部分

之后,点击页面顶部的保存。在下一页中,单击立即运行。您可能需要等待一段时间才能让您的工作正常运行。DBT 将在 10 秒内从 10 重新加载页面。过一会儿,您的作业将运行并显示以下结果:

作业在 DBT 云上运行(在 dbt 运行之前有几个步骤)

这些步骤的最后一步是 dbt run 命令。单击它,您将看到我们已经知道的输出:

dbt 运行命令的相同输出

我们已经看到了如何在我们的实例上运行 DBT,如何使用气流来调度它,以及如何在 DBT 云上运行 DBT。唯一缺少的部分是如何使用气流来运行 DBT 云作业。

3.使用气流在 DBT 云上运行作业

为了用气流运行我们的工作,我们将使用 DBT 云 API。因此,我们需要做的就是将适当的代码放在我们的 DAG 上,并像以前一样执行相同的调度。

首先,让我们得到一些我们需要的数据。在我们使用的最后一个页面中,通过我们的作业,单击作业名称。

工作页面的链接,在这里我们可以找到工作 id

现在,通过浏览器上的 URL,检查您的帐户和该作业的 id。例如,在我的例子中,URL 是https://cloud . get dbt . com/#/accounts/19964/projects/32821/jobs/25507/。意思是我的账号 id 是 19964,工作 id 是 25507。

现在,转到右上角的菜单,单击个人资料。然后选择 API 访问。然后点击显示。这是您的 API 密钥,将用于向 DBT API 发出请求。

这是您找到 API 密钥的地方

接下来,使用 VSCode 通过 airflow 用户连接到您的 EC2 实例。转到文件>打开文件夹。选择气流,你会有路径'/home/airflow/airflow '。按回车键。

右键单击 dags 文件夹,创建一个名为 load_users_cloud.py 的新文件:

您可以使用 VSCode 的接口而不是终端来创建项目文件

现在,复制下面的代码,需要时使用自己的 API 键(而不是*****)、帐户 id 和作业 id。

from airflow import DAG
from airflow.providers.http.operators.http import SimpleHttpOperatorimport datetime, jsondefault_args = {
  'start_date': datetime.datetime(2021,1,1)
}
dbt_header = {
  'Content-Type': 'application/json',
  'Authorization': 'Token *****'
}def getDbtMessage(message):
  return {'cause': message}def getDbtApiLink(jobId, accountId):
  return 'accounts/{0}/jobs/{1}/run/'.format(accountId, jobId)def getDbtApiOperator(task_id, jobId, message='Triggered by Airflow', accountId=19964):
  return SimpleHttpOperator(
    task_id=task_id,
    method='POST',
    data=json.dumps(getDbtMessage(message)),
    http_conn_id='dbt_api',
    endpoint=getDbtApiLink(jobId, accountId),
    headers=dbt_header
  )with DAG('Our_medium_project',
  schedule_interval="@daily",
  default_args=default_args,
  catchup=False) as dag: load_user_cloud = getDbtApiOperator('load_users', 25507)

这里,我们使用 SimpleHttpOperator 向 API 发出 POST 请求。getDbtApiOperator 函数简化了我们创建操作符的方式。我们只需要为任务和作业 id 定义一个名称。如果我们在单个 DAG 中使用多个 DBT 云帐户,我们还可以定义一条在 DBT 上显示的作业执行消息,不过我使用的是默认值和 accountID。

保存文件并在浏览器上打开 Airflow。转到管理>连接。单击+添加新连接。

在 Conn Id 中,使用 dbt_api(如果使用不同的名称,还必须在上面的代码中切换名称)。在连接类型中,选择 HTTP。在主机中,使用“【https://cloud.getdbt.com/api/v2/】T2”(不带引号)。保存连接。

设置与 DBT API 的连接

现在,转到 DAGs 页面。为我们的新 DAG 打开开关。几秒钟后,你会看到深绿色的指示器,显示我们的任务被执行了。

我们负责 DBT 任务的狗

回到 DBT 云页面,到求职页面。您将在作业历史记录中看到一条新记录,其中包含我们在 DAG 中定义的消息。

作业历史,手动执行和从气流

好了,现在我们可以使用气流来运行我们的 DBT 作业,无论是在服务器上使用 DBT 云还是 DBT。尽管我使用的例子非常简单,但这里的重点是两种工具之间的集成。

如果您已经使用了 DBT,那么您应该知道如何处理您的作业,因此您可以简单地包含 Airflow 来调度作业,并集成与 DBT 无关的其他步骤,比如将数据移动到数据仓库。
如果您已经使用了 Airflow,并且需要在您的数据仓库中转换数据,您可以使用 DBT 来利用它在模型之间创建的引用来完成这项工作,而不是使用 Airflow 运行所有的 SQL 命令,创建临时表并使用它们。
不管怎样,我希望这能有点用。

阅读本文的所有部分:

第 1 部分:启动一个实例并安装气流
第 2 部分:安装 DBT 和一些设置以简化工作 第 3 部分:使用 DBT 云和将气流与 DBT 集成

参考资料:

https://www.getdbt.com/ https://airflow.apache.org/ https://docs.getdbt.com/dbt-cloud/api https://docs.getdbt.com/reference/node-selection/syntaxhttps://air flow . Apache . org/docs/Apache-air flow-providers-http/stable/operators . html

对我在这里所做的事情最有帮助的来源: https://www.datascienceacademy.com.br(葡萄牙语)
https://docs.getdbt.com/docs/introduction

创建以太坊令牌以支持分散的“租赁-拥有”网络

原文:https://towardsdatascience.com/creating-an-ethereum-token-to-enable-a-decentralized-rent-to-own-network-cc3786cf1142?source=collection_archive---------14-----------------------

加密货币最可持续的应用包括重新思考我们如何在日常关系中建立信任。

图片作者。

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

介绍

随着房地产价格飙升至创纪录的高度,获得抵押贷款资格从未如此困难。即使那些有稳定、高薪工作的人也很难证明自己的信誉,也很难攒够钱开始购买房产。顾名思义,先租后拥有(Rent-to-Own)是获得房屋所有权的另一种途径,租房者可以选择在租约到期时购买房屋。虽然协议的条款可能会有所不同,但这基本上意味着每份租金支票的某一部分将用于最终的首付款。理想情况下,这种安排是双赢的:房东受益于动力十足的租户,可靠的租户因其财务责任而获得回报。然而,在实践中,先租后拥有远非完美。决定搬家的租房者不得不放弃他们应得的付款,重新开始。掠夺性房东在最后一刻改变条款,双方必须相互依赖,保持诚实准确的记录。

幸运的是,分散金融创新为这些问题提供了一个潜在的解决方案。使用智能合同,我们可以将租赁到拥有协议的业务逻辑编程为不可变分类帐中可独立验证的交易。我们甚至可以创建一个基于加密货币的激励系统,奖励租房者和房东。这些是 RTO T21 令牌背后的原则,这是一种不可转让的资产类别,它驱动着“先租后拥有”参与者的潜在网络。在深入技术细节之前,让我们先从(初步)经济学的概念概述开始。

动机

RTO 系统要发挥作用,必须让所有利益相关方受益。首先,通过任何“先租后拥有”计划挂牌出售房屋的房东,都希望在出售前的租赁期内赚取一定的现金。通常,这代表了财产评估价值的一部分。一旦达到这个门槛,他们就想卖给一个有动力、有信誉的买家。但是你如何找到这样的买家呢?信用评分并不能说明全部情况,推荐信也很容易伪造。由于难以通过这些不完善的指标建立信任,房东通常别无选择,只能允许每个租户通过第一手经验(即多年的按时付款)来证明自己。出于这个原因,大多数从租到拥有的协议是不可转让的,这意味着如果租户决定搬家,他们必须回到原点。

因此,一个无处不在的出租房屋和参与者的网络将是有利的。物业管理公司是实现这一目标的一种方式,但这种集中化的选择剥夺了个人的自主权,以换取标准化和共享基础设施,如安全支付平台和数据库。RTO 提供了一个分散的选择。我们首先利用已经融入以太坊生态系统的安全、稳定和不可变的金融交易,将我们的业务逻辑包装在智能合约中,以在分布式网络参与者之间建立信任。

RTO 智能合同

我们的智能合同简单,但功能强大。要在 RTO 网络上列出出租房屋,房东必须首先通过合同管理员的验证。一旦获得批准,他们可以添加他们的租赁财产,这是由租赁者的 ETH 地址、收入阈值(代表他们在出售房屋之前希望收回的美元金额)和收入百分比(每笔租金付款中对收入阈值有贡献的部分)定义的。新房和租房者被初始化为一个空的 RTO 余额,的房屋将不会被出售,直到买方卖方的 RTO 余额都超过收入阈值。这一条件确保了房东有一定的利润保证,而租房者证明了自己的信誉。

每次通过这种智能合同支付租金时,租户家庭都会获得不可转让的、美元标准化的 RTO。获得的 RTO 的确切数量由以下公式确定:

amountToMint = rentAmountEth * earningsPercent * usdPriceEth

因此,假设一个家庭的月租金为 2000 美元(撰写本文时的市值约为 1 ETH),收益百分比为 20%,收益阈值为 20,000 美元。每次付款时,1 ETH * 20% *(2000 美元/ETH) = 400 RTO 会添加到租房者和住房的余额中。按照这种利率,租房者将有机会在大约 4 年的稳定付款后购买房子。如果他们决定搬家,租户和家庭都会保留他们的 RTO 余额。需要注意的是,有效的租金支付是获得 RTO 的唯一途径— 代币不可转让、不可燃烧,并且不能在二级市场上交换,这与标准的 ERC20 硬币不同。像信用评分一样,建立良好的财务状况没有捷径可走。

通过公开关键信息,RTO 网络创建了一个竞争性市场,除了便利设施和面积,参与者还可以比较和协商收入协议的条款。即使在契约的相对简单的界限内,也可以自然地出现许多独特的、互利的场景,例如:

  • 租户和住宅均以 0 RTO 开始,租户不移动:这代表传统的“从租到拥有”结构。两个实体同时达到收入门槛,在这一点上,租房者可以购买房屋。
  • 租房者 RTO >收益阈值&住宅 RTO <收益阈值:租房者准备好了,但房东还没准备好。当这两个条件都满足时,租房者可能有足够的筹码来争取更有利的抵押贷款(例如 20 年而不是 30 年)。
  • 家庭 RTO >收益&租户 RTO <收益阈值:与上一种情况相反。在这里,租房者仍然需要证明自己,但他们可能希望通过谈判获得更高的收入百分比来加速他们的收入。

代码和教程

如果您想直接观看分散式应用的演示,请跳过本节。

部署智能合同

上面讨论的业务逻辑在下面用 Solidity 编写的 smart contract 中进行了编码。

如果你熟悉面向对象编程语言,大部分代码应该非常简单。我想强调几个关键功能:

  • getThePrice() : RTO 应该与美元挂钩,以考虑到 ETH 价格的波动性。为了使 ETH 支付正常化,我们需要一种访问当前美元/ETH 市场价格的方法。不幸的是,我们不能在 Solidity 中调用 CoinGecko API,但是我们可以访问一个“价格 Feed ”,它通过一个 Chainlink 聚合器接口巧妙地将价格存储在链上。点击此处了解更多信息。
  • payRent(address _to) :这是智能合约的核心,所以值得特别考虑。首先,我们确保付款是由房屋的承租人支付给经过核实的房东。接下来,作为一个可支付的功能,我们还促进了 ETH (L119)的转移,其金额存储在交易数据中。最后,我们计算 amountToMint(见上面的等式),并相应地更新 home 和 renter 的余额。

我使用 Remix IDE 和我的 Metamask wallet 将智能合约部署到 Ropsten Testnet。这里有更详细的说明,如果你感兴趣的话。在我们进入应用程序之前,我们(作为合同部署者)需要添加一个经过验证的房东,并使用部署合同的同一个帐户(代表一个受信任的管理员)签署交易。我们可以在混音中做到。

图片作者。

我们还可以在 Etherscan 上查看我们的合同和所有相关交易。

应用基础设施和元掩码集成

该应用程序为我们提供了通过支付门户式界面使用智能合同功能的方法。我使用 Python 的 FastAPI 来创建 API 端点,使用 Web3.py 库来准备以太坊事务(但不是 sign,稍后会详细介绍),并使用一个基本的 PostgreSQL 数据库来存储一些链外数据,比如房屋图像的 URL。我们使用流行的 Metamask 浏览器扩展来签署交易,而不是要求用户将他们的私钥硬编码到应用程序本身中(这是一个严重的安全风险)。例如,我们为 payRent 函数生成如下事务数据:

# from transactions.pydef payRent(landlord, amount_eth):
    txn_dict = to_contract.functions.payRent(w3.toChecksumAddress(landlord)).buildTransaction({
                'chainId': 3,
                'value': w3.toWei(float(amount_eth), 'ether'),
                'gas': 2000000,
                'gasPrice': w3.toWei('2', 'gwei')
    })
    return txn_dict

然后,我们可以用几行 JavaScript 将这些数据发送给 Metamask:

# from confirm_transaction.html***sendTxnButton***.addEventListener('click', () => {
  ***sendTxnButton***.disabled = true;
  ***sendTxnButton***.innerHTML = "Connecting to Metamask...";
  ethereum
    .request({
      method: 'eth_sendTransaction',
      params: [
        {
          from: ethereum.selectedAddress,
          to: "{{contract_address}}",
          value: "{{value}}",
          gasPrice: '0x4A817C800',
          gas: '0x1E8480',
          data: "{{txn_data}}",
          chainId: '0x3'
        },
      ],
    })
    .then((txHash) => logTransaction(txHash))
    .catch((error) => ***console***.error);
});

完整的项目代码,以及如何运行演示应用程序的说明,可以在这里访问。

演示

现在是一个快速演示,从房东和租户的角度演示功能。在租户和房屋可以开始赚取 RTO 之前,我们的房东必须将他们的财产添加到智能合同中。他们可以通过导航到“查看列表”选项卡并填写一个快速表格来完成。

角色:房东

在 RTO 网络上列出新的租赁信息。图片作者。

其中一些值,如街道地址和描述,将存储在我们的外链数据库中。其他的,像首付(也叫收入阈值)和收入百分比,将被存储在智能合同中。该页面只是准备了功能细节,但随后会要求他们使用元掩码钱包对交易进行显式签名。

用元掩码签署事务。图片作者。

一旦异步执行的事务被批准,我们就可以查看我们漂亮的新清单,以及直接从分类帐中读取的不可变细节。

图片作者。

现在我们的家已经增加了,让我们降低收入门槛,开始挖掘一些 RTO。

角色:租赁者

点击“连接钱包”按钮,我们将进入如下页面:

图片作者。

亮橙色的“连接 Metamask”按钮将从浏览器扩展中打开一个提示,通知我们我们的应用程序想要(目前)简单地读取我们的钱包地址。当我们接受申请时,我们的有效 ETH 地址会神奇地出现在我们的申请页面上。让我们继续检查这个钱包的 RTO 余额。

图片作者。

因为我们没有付任何租金,我们当然没有代币。为此,我们导航到“支付租金”选项卡,填写我们的付款金额(以 ETH 为单位),以及我们房东的 ETH 地址。

图片作者。

同样,实际的事务签名和私钥管理与应用程序本身是分离的。

图片作者。

在这种情况下,我们的模拟租金支付额为 0.01 ETH,或大约 20 美元(也许它更像一个帐篷,而不是一个家)。给定 30%的收益百分比,我们应该为此交易挖掘大约 6–7 个 RTO。让我们继续检查我们的余额:

图片作者。

同样的金额也适用于住宅列表(参见已付余额):

图片作者。

有趣的是,像任何 ERC20 令牌一样,我们也可以通过添加智能合约地址在 Metamask 中查看我们的余额!

在 Metamask 中查看我们的 RTO 平衡。图片作者。

最后的想法

这个应用程序开发起来相对简单,但是它展示了一些重要的概念。除了稳定支付租金之外,租户不能伪造 RTO 余额或通过任何其他方式获得代币。同样,虽然房东有强烈的动机参与这个网络(有动机的租户,有保证的预售收入,不需要参与集中的物业管理),但他们的 RTO 余额也是公开的。在传统的框架下,建立这种不信任的互动将需要艰苦的记录和强烈后果的威胁,以抑制欺诈行为。但是在一个强大的公共区块链,获得这些好处是微不足道的。我们经常听到“产量农业”、杠杆交易和其他复杂的 DeFi 工具,但加密货币最可持续的应用涉及重新思考我们如何在日常关系中建立信任。

所有代码都可以在 Github 上获得。

参考

用 Python 创建影像分类 Slackbot

原文:https://towardsdatascience.com/creating-an-image-classification-slackbot-in-python-99ea461331e0?source=collection_archive---------30-----------------------

带 Python 代码的 Slackbot 教程

图片来自来源

聊天机器人是一种软件,被编程为围绕某个主题与人类进行对话,并带有动机以实现既定目标。它们可以帮助我们自动完成任何特定的任务,或者触发一次普通的聊天,允许以文本或语音作为交流媒介。

现实世界聊天机器人部署的一些流行示例包括—

  • 允许顾客使用机器人点餐的餐馆。
  • 帮助客户进行电子商务购买的机器人。
  • 等等……

有许多平台可以部署你的机器人,并让公众使用它。其中比较突出的有 Facebook Messenger、Slack、Kik 等。上述每个平台都有其局限性和优势。在这篇博客中,我们将学习如何在 Slack 上构建一个图像分类机器人,因为它提供了相对更好的交互选项。

附言 本博客假设用户知道如何在 Slack 上设置你的 bot 首字母(令牌等)。

Slack 机器人

Slack 机器人有两种类型

  1. 用户机器人——用户机器人是最自然的一对一聊天方式之一,就像我们和人类聊天一样。这种机器人类型有许多现成的功能。更多详情可以阅读
  2. 斜线命令——这些命令就像是对任何 API 的简单调用,用来满足用户的请求。这里斜杠命令被映射到一个可以处理特定类型查询的服务器 URL。查看* 基于斜线的命令 了解更多详情。*

在这篇博客中,我们将讨论用户机器人,其中的高级流程如下所示——即,我们向我们的机器人提供一幅图像,它试图预测该图像的类别,并以自然语言返回给我们。(我们把我们的 bot 命名为* 全知 【无所不知】)😛*

作者图片

完全流通

让我们深入了解更多细节,看看它到底是如何连接 Slack 和我们的分类模型的。

完整流程图|作者图片

上图显示了整个流程的端到端流程——我们将图像上传到 Slack 上的 bot 用户界面,然后通过公共链接将图像保存在磁盘上。然后,我们应用必要的预处理转换,然后将它们传递给我们预先训练的图像分类模型。一旦我们得到了预测,然后使用模板槽技术围绕预测构建自然语言,并将其返回给 slack 接口。我用了一个预训练的 VGG16 模型同样,请参考这个有趣的论文来了解更多关于模型的信息。此外,以监督方式建模,它只能从训练集中存在的一组给定的可能类别中进行预测。

下面的代码片段包含了这个项目的全部代码—

项目代码

你也可以在这里签出整个代码— 来源

测试

以下是我尝试过的一些例子—

示例 1 |作者图片

示例 2 |作者图片

我们的机器人能够正确地执行上面提出的管道,并成功地以模板格式返回其输出,使其感觉像一次自然的对话。类似地,以类似的方式构建令人兴奋的用例的可能性是无穷无尽的,看看您能想到什么会很有趣。😃

这个周末对我来说是一次很棒的学习经历。欢迎分享和评论您的想法——谢谢!

使用犯罪数据创建交互式仪表盘

原文:https://towardsdatascience.com/creating-an-interactive-dashboard-with-dash-plotly-using-crime-data-a217da841df3?source=collection_archive---------4-----------------------

我的上一篇文章简单介绍了如何用 Dash 开发一个简单的仪表盘。作为一个视觉化的狂热爱好者,那样的仪表板不会让我高兴。本周我做了进一步的探索,我想做一个交互式仪表盘,就像我们通常用 PowerBI 或 Tableau 做的那样。

鸣谢:本作品基于/包括 Stats NZ 的数据,这些数据由 Stats NZ 根据 知识共享署名 4.0 国际 许可证授权重用。

这是仪表板的样子。然后,我将解释实现这一点的方法:

来自作者仪表板的 Gif

如果你想从一个简单的仪表板开始,你可能想看看这篇文章。

先决条件:

  • 数据:

本文中使用的数据来自新西兰统计局,如开头致谢部分所述。我从新西兰统计局下载了数据,然后转换成可视化的数据帧。

数据框架包括六列,[犯罪]是关于不同类型的犯罪;[位置]是关于犯罪发生的地区;[年份]是犯罪发生的时间;[措施]是罪行是否已经解决;[场景]是犯罪发生的地方;[总数]是犯罪次数。

表 1:数据帧

  • 套餐:

Pandas、numpy、plotly.express、plotly.graph_objects 用于数据清理和可视化; dash,dash_core_components,dash_html_components 用于创建仪表板。

import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as goimport dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

第一步:可视化准备

对于这个仪表板,我计划有四个图表:

fig1 = px.bar(
    offence_district, ***#dataframe***
    x=offence_district.groupby("Offence")["Total"].agg(sum), ***#x***
    y=offence_district["Offence"].unique(),***#y***
    labels={"x": "Total Recorded", "y": "Offence"}, ***#define lable***
    color=offence_district.groupby("Offence")["Total"].agg(sum),
    color_continuous_scale=px.colors.sequential.RdBu,***#color***
    text=offence_district.groupby("Offence")["Total"].agg(sum),***#text***
    title="Recorded Crime by Offence", ***#title***
    orientation="h"  ***#horizonal bar chart***
)
fig1.update_layout(
    title=dict(x=0.5), ***#set title in the center***
    margin=dict(l=550, r=20, t=60, b=20) ***#set margin of the chart***
    paper_bgcolor="#D6EAF8", ***#set the background color of the chart***
)
fig1.update_traces(texttemplate="%{text:.2s}") ***#formart the text***

图 1:条形图

*Plotly 有很大范围的颜色设置,例如离散颜色和连续颜色,我发现这在可视化中非常有助于突出显示一些信息或进行比较。查看来自 ploty 的指令以获得更多信息。

fig2 = px.scatter(
    offence_district, ***#dataframe***
    x="Location", ***#x***
    y="Offence", ***#y***
    size="Total", ***#bubble size***
    color="Total",***#bubble color***
    color_continuous_scale=px.colors.sequential.Plotly3, ***#color theme***
    title="Offences by Location", ***#chart title***
)
fig2.update_layout(
    xaxis_tickangle=30,***#angle of the tick on x-axis***
    title=dict(x=0.5), ***#set the title in center***
    xaxis_tickfont=dict(size=9), ***#set the font for x-axis***
    yaxis_tickfont=dict(size=9), ***#set the font for y-axis***
    margin=dict(l=500, r=20, t=50, b=20), ***#set the margin***
    paper_bgcolor="LightSteelblue", ***#set the background color for chart***
)

图 2:气泡图——按地点和场景划分的犯罪

在第三个图表中,我想比较“已解决”和未解决记录的数量。所以首先我把原始数据帧分成两部分。

s1 = offence_district[offence_district['Measure']=='Resolved']
s2 = offence_district[offence_district['Measure']=='Unresolved']

然后我使用 plotly.graph_objects 来构建图形:

trace1 = go.Bar(    ***#setup the chart for Resolved records***
    x=s1["Location"].unique(), ***#x for Resolved records***
    y=s1.groupby("Location")["Total"].agg(sum),***#y for Resolved records***
    marker_color=px.colors.qualitative.Dark24[0],  ***#color***
    text=s1.groupby("Location")["Total"].agg(sum), ***#label/text***
    textposition="outside", ***#text position***
    name="Resolved", ***#legend name***
)
trace2 = go.Bar(   ***#setup the chart for Unresolved records***
    x=s2["Location"].unique(),
    y=s2.groupby("Location")["Total"].agg(sum),
    text=s2.groupby("Location")["Total"].agg(sum),
    marker_color=px.colors.qualitative.Dark24[1],
    textposition="outside",
    name="Unresolved",
)data = [trace1, trace2] ***#combine two charts/columns***
layout = go.Layout(barmode="group", title="Resolved vs Unresolved") ***#define how to display the columns***
fig3 = go.Figure(data=data, layout=layout)
fig3.update_layout(
    title=dict(x=0.5), ***#center the title***
    xaxis_title="District",***#setup the x-axis title***
    yaxis_title="Total", ***#setup the x-axis title***
    margin=dict(l=20, r=20, t=60, b=20),***#setup the margin***
    paper_bgcolor="aliceblue", ***#setup the background color***
)
fig3.update_traces(texttemplate="%{text:.2s}") ***#text formart***

图 3:柱形图—已解决与未解决

fig4= px.bar(offence_district, 
             x = offence_district.groupby('Scene')['Total'].agg(sum), 
             y = offence_district['Scene'].unique(), 
             labels={
                     "x": "Total Recorded",
                     "y": "Scene"
                 },
              color = offence_district.groupby('Scene')['Total'].agg(sum),
              color_continuous_scale=px.colors.sequential.Sunset,
              #color_discrete_sequence=['rgb(253,180,98)','rgb(190,186,218)'],
              text = offence_district.groupby('Scene')['Total'].agg(sum),
             title = 'Recorded Crime by Scene',
              #,barmode = 'group'
              orientation = 'h'
             )
fig4.update_layout( title = dict(x=0.5), paper_bgcolor="#BDBDBD")
fig4.update_traces(texttemplate = '%{text:.2s}')

图 4:条形图——犯罪现场

步骤 2:设置仪表板布局

一旦我们准备好了所有的图表,下一步就是设置仪表板的布局。换句话说,你希望你的仪表板是什么样子。

例如,在我的仪表板中,我希望在顶部中间有一个标题,然后接着有四个 图形,两个一排。此外,我希望所有四个图表能够通过“年份”过滤。

为了实现我上面提到的,在我的布局设置中,需要对标题、四个图形和一个下拉菜单(过滤器)进行编码。

app = dash.Dash(__name__)app.layout = html.Div(
    children=[ html.Div(
            children=[
                html.P(children="🚓", style={'fontSize': "30px",'textAlign': 'center'}, className="header-emoji"), ***#emoji***
                html.H1(
                    children="Crime Analytics",style={'textAlign': 'center'}, className="header-title" 
                ), ***#Header title***
                html.H2(
                    children="Analyze the crime records"
                    " by district in New Zealand"
                    " between 1994 and 2014",
                    className="header-description", style={'textAlign': 'center'},
                ),
            ],
            className="header",style={'backgroundColor':'#F5F5F5'},
        ), ***#Description below the header***

        html.Div(
            children=[
                html.Div(children = 'Year', style={'fontSize': "24px"},className = 'menu-title'),
                dcc.Dropdown(
                    id = 'year-filter',
                    options = [
                        {'label': Year, 'value':Year}
                        for Year in offence_district.Year.unique()
                    ], ***#'Year' is the filter***
                    value ='2010',
                    clearable = False,
                    searchable = False,
                    className = 'dropdown', style={'fontSize': "24px",'textAlign': 'center'},
                ),
            ],
            className = 'menu',
        ), ***#the dropdown function***

        html.Div(
            children=[
                html.Div(
                children = dcc.Graph(
                    id = 'scatter',
                    figure = fig2,
                  #  config={"displayModeBar": False},
                ),
                style={'width': '50%', 'display': 'inline-block'},
            ),
                html.Div(
                children = dcc.Graph(
                    id = 'bar',
                    figure = fig1,
                    #config={"displayModeBar": False},
                ),
                style={'width': '50%', 'display': 'inline-block'},
            ),
                html.Div(
                children = dcc.Graph(
                    id = 'bibar',
                    figure = fig3,
                    #config={"displayModeBar": False},
                ),
                style={'width': '50%', 'display': 'inline-block'},
            ),
                html.Div(
                children = dcc.Graph(
                    id = 'barscene',
                    figure = fig4,
                    #config={"displayModeBar": False},
                ),
                style={'width': '50%', 'display': 'inline-block'},
            ),
        ],
        className = 'double-graph',
        ), 
    ]
) ***#Four graphs***

步骤 3:设置回拨

为了能够将下拉(过滤)值传递给仪表板中的图形,我们需要设置“回调”,以便图形可以是交互式的。下面我分别为每个图形设置回调

[@app](http://twitter.com/app).callback(
    Output("scatter", "figure"), ***#the output is the scatterchart***
    [Input("year-filter", "value")], ***#the input is the year-filter***
)
def update_charts(Year):
    filtered_data = offence_district[offence_district["Year"] == Year] ***#the graph/dataframe will be filterd by "Year"***scatter = px.scatter(
        filtered_data,
        x="Location",
        y="Offence",
        size="Total",
        color="Total",
        color_continuous_scale=px.colors.sequential.Plotly3,
        title="Offences by Location",
    )
    scatter.update_layout(
        xaxis_tickangle=30,
        title=dict(x=0.5),
        xaxis_tickfont=dict(size=9),
        yaxis_tickfont=dict(size=9),
        margin=dict(l=500, r=20, t=50, b=20),
        paper_bgcolor="LightSteelblue",
    )
    return scatter ***#return the scatterchart according to the filter***[@app](http://twitter.com/app).callback(
    Output("bar", "figure"),
    [Input("year-filter", "value")],
)
def update_charts(Year):
    filtered_data = offence_district[offence_district["Year"] == Year]
    bar = px.bar(
        filtered_data,
        x=filtered_data.groupby("Offence")["Total"].agg(sum),
        y=filtered_data["Offence"].unique(),
        color=filtered_data.groupby("Offence")["Total"].agg(sum),
        color_continuous_scale=px.colors.sequential.RdBu,
        text=filtered_data.groupby("Offence")["Total"].agg(sum),
        title="Recorded Crime by Offence",
        orientation="h",
    )
    bar.update_layout(
        title=dict(x=0.5), margin=dict(l=550, r=20, t=60, b=20), paper_bgcolor="#D6EAF8"
    )
    bar.update_traces(texttemplate="%{text:.2s}")
    return bar[@app](http://twitter.com/app).callback(
    Output("bibar", "figure"),
    [Input("year-filter", "value")],
)
def update_charts(Year):
    filtered_s1 = s1[s1["Year"] == Year]
    filtered_s2 = s2[s2["Year"] == Year]
    trace1 = go.Bar(
        x=filtered_s1["Location"].unique(),
        y=filtered_s1.groupby("Location")["Total"].agg(sum),
        text=filtered_s1.groupby("Location")["Total"].agg(sum),
        textposition="outside",
        marker_color=px.colors.qualitative.Dark24[0],
        name="Resolved",
    )
    trace2 = go.Bar(
        x=filtered_s2["Location"].unique(),
        y=filtered_s2.groupby("Location")["Total"].agg(sum),
        text=filtered_s2.groupby("Location")["Total"].agg(sum),
        textposition="outside",
        marker_color=px.colors.qualitative.Dark24[1],
        name="Unresolved",
    )
    data = [trace1, trace2]
    layout = go.Layout(barmode="group", title="Resolved vs Unresolved")
    bibar = go.Figure(data=data, layout=layout)
    bibar.update_layout(
        title=dict(x=0.5),
        xaxis_title="District",
        yaxis_title="Total",
        paper_bgcolor="aliceblue",
        margin=dict(l=20, r=20, t=60, b=20),
    )
    bibar.update_traces(texttemplate="%{text:.2s}")
    return bibar[@app](http://twitter.com/app).callback(
    Output("barscene", "figure"),
    [Input("year-filter", "value")],
)
def update_charts(Year):
    filtered_data = offence_district[offence_district["Year"] == Year]
    barscene = px.bar(
        filtered_data,
        x=filtered_data.groupby("Scene")["Total"].agg(sum),
        y=filtered_data["Scene"].unique(),
        labels={"x": "Total Recorded", "y": "Scene"},
        color=filtered_data.groupby("Scene")["Total"].agg(sum),
        color_continuous_scale=px.colors.sequential.Sunset,
        # color_discrete_sequence=['rgb(253,180,98)','rgb(190,186,218)'],
        text=filtered_data.groupby("Scene")["Total"].agg(sum),
        title="Recorded Crime by Scene",
        # ,barmode = 'group'
        orientation="h",
    )
    barscene.update_layout(title=dict(x=0.5), paper_bgcolor="#BDBDBD")
    barscene.update_traces(texttemplate="%{text:.2s}")
    return barscene

一旦我们得到了 dash 布局回调,我们就可以运行仪表板并玩它了。

结论:

虽然我不认为用 Dash 开发 dashboard 是一个容易的开始,但 Dash 为用户提供了定制或个性化 dashboard 的灵活性,非常有趣。要开始构建自己的仪表板,请记住 Dash 的三个组成部分:1)图形;2)布局;以及 3)回调。

布局部分对我来说不是那么简单,因为我对 html 或 css 语言一无所知。这是链接到 css intro,如果你和我有类似的问题。

***##if not using virtual environment***
if __name__ == '__main__':
    app.run_server()***##if using virtual environment*** if __name__ == '__main__':
    app.run_server(debug = True)

这就是创建交互式仪表板所需的全部内容。我们开始吧!

如果有任何问题,请在 Linkedin 上给我发短信,或者打个招呼🤪!

参考

https://realpython.com/python-dash/ https://github.com/gsuijker/avocado_dashboard

用 Pandas 和 Streamlit 创建交互式日期时间过滤器

原文:https://towardsdatascience.com/creating-an-interactive-datetime-filter-with-pandas-and-streamlit-156e1ea12e90?source=collection_archive---------10-----------------------

用 Python 实现时序数据的可视化日期时间过滤器

作者视觉。

介绍

也许我们每天处理的最激增的数据类型是时间序列数据。基本上,任何使用日期、时间或两者索引的东西都可以被视为时间序列数据集。通常情况下,你可能需要用日期和时间来过滤时间序列数据。基于任何其他形式的索引过滤数据框是一项相当简单的任务;然而,datetime 的情况就不一样了,尤其是当日期和时间出现在不同的列中时。即使您成功过滤了它们,将它们应用到您的数据框并即时可视化它们也是另一项任务。

幸运的是,我们有 Pandas 和 Streamlit 在这方面帮助我们,以便创建和可视化交互式日期时间过滤器。我假设我们大多数人都非常熟悉 Pandas,并可能在我们的数据生活中经常使用它,但我怀疑许多人不熟悉 Streamlit,因为它是这个街区的新成员。无论如何,我将提供一个快速的介绍,以免有人问。

熊猫

在处理 Python 中的数据时,Pandas 可以说是最敏捷、高效、灵活、健壮、有弹性和用户友好的绑定。如果你认为我在前面的句子中加入了太多的夸张,那么你大大低估了熊猫。这个强大的工具包让您能够操纵、变异、转换,甚至是可视化框架中的数据,所有这些都只需要几行代码。在这个应用程序中,我们将使用 Pandas 从/向 CSV 文件中读取/写入数据,并根据选定的开始和结束日期/时间调整数据框的大小。

细流

正如其创始人自己所描述的那样,Streamlit 是一个纯 Python API,允许您创建机器学习应用程序。不对。实际上远不止这些。Streamlit 是一个 web 框架、一个准端口转发代理服务器和一个前端 UI 库,所有这些都混合在一个 bundle of good 中。简而言之,你可以开发和部署无数的 web 应用程序(或本地应用程序),用于各种用途。对于我们的应用程序,我们将利用 Streamlit 为我们的时间序列数据呈现一个交互式滑动过滤器,该过滤器也将被即时可视化。

包装

事不宜迟,让我们继续插入我们将要使用的软件包。

如果您需要安装上述任何软件包,请在 Anaconda 提示符下使用‘pip install’继续。

pip install streamlit

资料组

我们将使用这个随机生成的数据集— CC0(无版权保留,公共领域)[1],它有一个日期、时间和值的列,如下所示。

图片作者。

日期格式如下:

YYYYMMDD

而时间的格式为:

HHMM

您可以根据自己的需要使用任何其他格式来设置日期时间的格式,但是您必须确保按照上一节中的说明在脚本中声明它。

日期时间过滤器

为了实现我们的过滤器,我们将使用下面的函数作为参数— messagedf ,它们对应于 slider 小部件显示的消息和需要过滤的原始数据帧。

最初,我们将调用 Streamlit slider 小部件,如下所示。

streamlit.slider(标签,最小值,最大值,值,步长)

参数

标签 (str 或 None)——向用户解释该滑块用途的简短标签。

min _ value(支持的类型或无)—最小允许值。如果值为 int,则默认为 0,如果值为 float,则默认为 0.0,如果值为 date/datetime,则值为 timedelta(days=14),如果值为 time,则值为 time . min

(支持的类型或无)—最大允许值。如果值是 int,则默认为 100;如果是 float,则默认为 1.0;如果是 date/datetime,则默认为 value+time delta(days = 14);如果是 time,则默认为 time . max

value (一个支持的类型或者一个支持的类型的元组/列表或者无)——滑块第一次呈现时的值。如果在这里传递一个由两个值组成的元组/列表,那么就会呈现一个带有上下边界的范围滑块。例如,如果设置为(1,10),滑块将有一个介于 1 和 10 之间的可选范围。默认为最小值。

步进(int/float/time delta 或 None) —步进间隔。如果值为 int,则默认为 1;如果值为 float,则默认为 0.01;如果值为 date/datetime,则默认为 time delta(days = 1);如果值为 time,则默认为 timedelta(minutes=15)**

请注意,我们的滑块将返回两个值,即开始日期时间和结束日期时间值。因此,我们必须使用数组将滑块的初始值声明为:

*[0,len(df)-1]*

我们必须将小部件等同于如下所示的两个变量,即用于过滤数据帧的开始和结束日期时间索引:

*slider_1, slider_2 = st.slider('%s' % (message),0,len(df)-1,[0,len(df)-1],1)*

随后,我们需要从开始/结束时间列中删除任何尾随的小数位,并添加前导零以防时间少于一个整小时,即 12:00AM 引用为 0,如下所示:

*while len(str(df.iloc[slider_1][1]).replace('.0','')) < 4:
    df.iloc[slider_1,1] = '0' + str(df.iloc[slider_1][1]).replace('.0','')*

然后,我们需要将我们的日期添加到时间中,并通过使用 Python 中的 datetime.strptime 绑定,以可理解的格式解析我们的日期时间,如下所示:

*start_date = datetime.datetime.strptime(str(df.iloc[slider_1][0]).replace('.0','') + str(df.iloc[slider_1][1]).replace('.0',''),'%Y%m%d%H%M%S')*

为了显示我们选择的日期时间,我们可以使用 strftime 功能来重新格式化开始/结束,如下所示:

*start_date = start_date.strftime('%d %b %Y, %I:%M%p')*

为了使用其他日期时间格式,请参考这篇文章。最后,我们将显示选定的日期时间,并将过滤后的索引应用于数据集,如下所示:

*st.info('Start: **%s** End: **%s**' % (start_date,end_date))                filtered_df = df.iloc[slider_1:slider_2+1][:].reset_index(drop=True)*

下载 CSV

您可能会发现将过滤后的数据框下载为 CSV 文件非常方便。如果是这样,请使用以下功能在您的 Streamlit 应用程序中创建一个可下载的文件。

该函数的参数— namedf 分别对应需要转换为 CSV 文件的可下载文件和数据帧的名称。

简化应用程序

最后,我们可以以 Streamlit 应用程序的形式将所有内容绑定在一起,该应用程序将呈现日期时间过滤器、数据框和折线图,当我们移动滑块时,这些内容都会即时更新。

您可以通过在 Anaconda 提示符下键入以下命令来运行您的最终应用程序。首先,将根目录更改为保存源代码的位置:

*cd C:/Users/...*

然后键入以下内容运行您的应用程序:

*streamlit run file_name.py*

结果

现在你有了它,一个交互式的仪表板,允许你可视化地过滤你的时间序列数据,同时可视化它!

作者照片。

如果您想了解更多关于数据可视化和 Python 的知识,请随时查看以下(附属链接)课程:

使用 Streamlit 开发 Web 应用程序:

*https://www.amazon.com/Web-Application-Development-Streamlit-Applications/dp/1484281101?&linkCode=ll1&tag=mkhorasani09-20&linkId=a0cb2bc17df598006fd9029c58792a6b&language=en_US&ref_=as_li_ss_tl

使用 Python 实现数据可视化:

https://www.coursera.org/learn/python-for-data-visualization?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW2aEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

面向所有人的 Python 专业化:

https://www.coursera.org/specializations/python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW16Ewvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

GitHub 资源库:

https://github.com/mkhorasani/interactive_datetime_filter

参考资料:

[1] Khorasani,M. K. (2021 年 12 月 28 日)。交互式日期时间过滤器(版本 1)【随机生成的数据集】。https://github . com/mkhorasani/interactive _ datetime _ filter/blob/main/data . CSV

新到中?你可以在这里订阅和解锁无限文章。*

使用 Python 创建和管理弹性搜索索引

原文:https://towardsdatascience.com/creating-and-managing-elasticsearch-indices-with-python-f676ff1c8113?source=collection_archive---------3-----------------------

从 CSV 文件创建 ES 索引以及使用 Python Elasticsearch 客户端管理数据的实践指南

保罗·格伦在 Unsplash 上拍照

E lasticsearch (ES)是一个分布式搜索引擎,旨在实现可扩展性和冗余性。它速度很快,适合存储和处理大量数据,用于分析、机器学习和其他应用。ES 在最近几年获得了发展,对于任何数据科学家(和数据工程师)的工具箱来说,它都是一项重要的技术。在这篇博文中,我们将使用 Bonsai 提供我们自己的(免费)ES 集群,并使用 Python Elasticsearch 客户端来建立索引,并写入和查询数据。这篇博文的所有代码都可以在 GitHub 上找到。

设置您的弹性搜索集群

第一步,我们将建立一个弹性搜索集群。你可以通过一个托管的弹性搜索服务提供商来完成这项工作,比如 AWS 的亚马逊弹性搜索服务。您如何决定供应、部署和管理您的集群(以及在哪里)取决于您正在构建哪种解决方案以及哪些功能对您来说是重要的。

在这里,我们将使用 Bonsai ,它为我们提供了一个免费的“沙盒”层,具有 125mb 的存储空间和 35,000 个文档的存储限制。首先,在 Bonsai 上为注册一个帐户,然后按照网站上的步骤来设置和部署您的集群。如果您已经在 Heroku 上拥有一个帐户,您也可以通过选择 Bonsai 作为应用程序资源标签中的附加组件,直接为您的应用程序提供一个 ES 集群,而无需在 Bonsai 上注册帐户(见下文)。

通过 Heroku 附加组件提供 Bonsai Elasticsearch 集群(图片由作者提供)

在您设置您的 Bonsai 帐户并部署您的集群(或通过 Heroku 为您的应用程序提供 Bonsai 集群)后,转到您的 Bonsai 集群概览仪表板左侧栏中的“凭证”页面,并复制您的主机 URL、访问密钥和访问密码。稍后,我们将使用这些信息通过 Python Elasticsearch 客户端建立一个连接。

从Bonsai Cluster overview dashboard中的“凭证”页面获取 ES 集群的主机 URL、访问密钥和访问密码(图片由作者提供)

Bonsai 的沙盒层不是生产级部署,有一些限制。例如,沙箱层不允许您为用户设置有限的权限(例如,只读权限),因此,如果您希望将此设置用于向互联网公开的应用程序,请记住这一点。Elastic.co 提供了一个 14 天的免费试用版,如果你想探索 es 所提供的全部功能的话,你可以使用这个试用版。

完成上述步骤后,您可以使用 Elasticsearch 的Compact and Aligned Text(CAT)API从控制台检查集群健康状况和索引。卡特彼勒 API 旨在为您提供人类可读的输出。因此,它们不是打算由应用程序使用;相反,他们应该从终端或在基巴纳控制台使用。

在控制台上(直接在 Kibana 和 Bonsai 上),下面的 GET 请求将返回关于集群健康的信息(一个“绿色”状态意味着您的所有碎片都已分配):

使用卡特彼勒健康 API 在 Kibana 控制台上检查您的 ES 集群的健康状况(图片由作者提供)

定义您的 ES 索引映射

现在我们已经有了一个集群,让我们看看 es 中数据和索引的基础。

Elasticsearch 中的数据是以名为“ 文档 ”的 JSON 对象的形式存在的。一个文档包含字段,它们是键值对,可以是一个值(如布尔值或整数)或一个嵌套结构。文档被组织在 索引 中,它们既是遵循模式的数据的逻辑分组,也是通过碎片的数据的物理组织。

每个索引由一个或多个物理碎片组成,这些物理碎片形成一个逻辑组。每个碎片依次是一个“自含索引”。索引中的数据跨这些碎片进行分区,而碎片分布在各个节点上。每个文档都有一个“主碎片”和一个“副本碎片”(也就是说,如果索引已经被配置为有一个或多个副本碎片)。

驻留在不同碎片中的数据可以并行处理。在您的 CPU 和内存允许的范围内(即,取决于您拥有的 ES 集群的类型),更多的碎片意味着更快的搜索。但是请注意,碎片会带来开销,您应该仔细考虑集群中碎片的适当数量和大小。

既然我们已经学习了 ES 的基础知识,让我们尝试建立一个我们自己的索引。这里,我们将使用 Kaggle 上提供的关于网飞演出的数据。该数据集采用 CSV 格式,包含网飞上可用的电影和电视剧的信息,包括元数据,如上映日期、片名和演员阵容。

我们将首先为我们的索引定义一个 ES 映射。在这种情况下,我们将使用相对简单的字段类型,将所有字段定义为text,除了release_year(我们将其定义为integer)。

虽然 Elasticsearch 能够在您编写文档时使用动态字段映射来推断文档的映射,但它不一定能达到最佳效果。通常,您需要花一些时间来定义映射,因为字段类型(以及各种其他选项)会影响索引的大小以及查询数据的灵活性。例如,text字段类型在索引时被分解成单独的术语,允许部分匹配。keyword类型也可以用于字符串,但是在索引时不进行分析(或者说:“标记化”),只允许精确匹配(在本例中,我们可以将它用于type字段,它取两个值之一——“电影”或“电视节目”)。

这里要记住的另一件事是 es 没有数组字段类型:如果你的文档包含一个由整数数组组成的字段,那么 ES 的等价数据类型就是integer(关于 ES 字段类型的完整概述,请参见本页)。以下面的文件为例:

{
    "values": [1,2,3,4,5]
}

该数据的底层映射将简单地将values字段类型定义为一个整数:

mapping = {
    "mappings": {
        "properties": {
            "values": {
                "type": "integer"
            }
        }
    }
}

现在我们已经定义了我们的映射,我们可以使用 Python Elasticsearch 客户端在 ES 上设置我们的索引。在下面的 Python 代码中,我设置了一个名为 [EsConnection](https://github.com/ngoet/es_demo/blob/main/es_connection.py)的类,带有一个 ES 客户端连接属性(es_client)。注意,为了方便起见,我将我的访问凭证存储在环境变量中(也是为了避免在将代码推送到 GitHub 时意外地共享它们)。对于真正的应用程序,你必须使用更安全的方法,比如 AWS Secrets Manager 。

EsConnection类还包括两个方法,一个基于映射创建索引(create_index),另一个(populate_index)获取 CSV 文件,将其行转换为 JSONs,并将每个条目(“文档”)写入 es 索引。这里,我们将只使用第一个函数来创建我们的netflix_movies索引:

现在,我们可以使用下面的代码检查索引的映射,该代码将返回我们刚刚编写的映射:

将数据写入 ES

现在我们已经定义了我们的映射,我们可以使用下面的代码将网飞电影数据写入我们的 es 索引(请注意,这段代码期望本文前面讨论的来自 Kaggle 的网飞数据可以在名为“data”的子目录中获得):

当这段代码运行时,我们可以通过查看 Bonsai 仪表板中的日志来检查数据是否通过。日志应该显示对netflix_movies索引的 POST 请求(见下文)。

检查日志中对 Bonsai 索引的 POST 调用(图片由作者提供)

我们还可以使用count方法检查netflix_movies索引中的条目数量,例如:

最后,我们可以使用 Kibana 控制台中的CAT indexes API来检查索引中的文档数量、它们的大小、主碎片和复制碎片的数量以及它们的健康状态:

使用 CAT 索引 API 在 Kibana 控制台上检查 es 集群中的索引(图片由作者提供)

在上面显示的输出中,store.size字段显示了主碎片和复制碎片的总大小,而pri.store.size只显示了主碎片的大小。在这种情况下,store.size将是主碎片大小的两倍,因为我们的碎片健康是“绿色的”,这意味着副本碎片被正确分配。

如果你喜欢全程使用 Python,Python Elasticsearch 客户端也可以直接与 CAT API 一起使用。

从 ES 查询数据

现在我们已经建立了集群并编写了文档,让我们简单地看一下从 Elasticsearch 查询数据。ES 查询是用 Elasticsearch 领域特定语言(DSL) 编写的。正如在 ES 文档中所描述的,DSL 是基于 JSON 的,应该被认为是查询的抽象语法树(AST)。DSL 查询由两种类型的子句组成:

  1. 叶查询子句,查找特定字段中的特定值(如matchrange);和
  2. 复合查询子句用于逻辑组合多个查询(如多叶或复合查询)或改变这些查询的行为。

当您对您的索引运行查询时,ES 按照代表匹配质量的相关性分数(一个浮点数)对结果进行排序(该值在与“命中”相关联的_score字段中报告)。ES 查询有一个查询和一个过滤上下文。过滤器上下文——顾名思义——过滤掉不符合语法条件的文档。但是,这不会影响相关性分数。布尔上下文中的匹配对相关性分数有贡献。

让我们看一个带有查询和过滤上下文的查询示例。下面的例子根据发行年份进行过滤,但是根据电影类型进行匹配。

{
    "query": {
        "bool": {
            "must": [
                {"match": {"type": "TV Show"}},
            ],
            "filter": [
                {"range": {"release_year": {"gte": 2021}}}
            ]
        }
    }
}

我们可以直接使用我们的 ES 控制台或者通过 Python 在我们的索引上运行这个查询。下面的例子使用了后一种方法。这段代码首先设置 ES 客户端。随后,它定义查询,最后,它针对netflix_movies ES 索引运行查询。代码的最后一行打印与我们的查询相匹配的电影的标题。

请记住,对于常规搜索,每个查询最多有 10,000 次命中。如果您需要在单个查询中提取更多内容(即“深度分页”),您可以使用 search_after 选项(您也可以使用滚动搜索,但 ES 不再推荐这种方式)。还要注意,因为我们知道“TV Show”是type字段可以取的值,所以我们也可以使用过滤器上下文。我将把 DSL 的这些和其他复杂之处留到以后的博客文章中。

就是这样!我们已经配置了一个 ES 集群,检查了集群的健康状况,定义了一个索引,编写了文档,并对我们的索引运行了一个简单的查询。请继续关注 Elasticsearch 上的未来博客文章,在那里我将深入探讨 DSL 和索引存储大小优化的细节。

感谢阅读!

支持我的工作: 如果你喜欢这篇文章,愿意支持我的工作,请考虑 通过我的推荐页面 成为付费媒体会员。如果你通过我的推荐页面 注册 ,订阅的价格是一样的,但是我会收取你每月的部分会员费。

如果你喜欢这篇文章,这里还有一些你可能喜欢的文章

[## 优化弹性搜索中的磁盘使用

towardsdatascience.com](/optimising-disk-usage-in-elasticsearch-d7b4238808f7)

免责声明:“elastic search”和“Kibana”是 Elasticsearch BV 在美国和其他国家的商标。本文中对任何第三方服务和/或商标的描述和/或使用不应被视为对其各自权利持有人的认可。

在依赖 中的任何内容之前,请仔细阅读 本免责声明 【我的 Medium.com 文章】

用 PyTorch 为 2D 创建和训练一个 U-Net 模型& 3D 语义分割:推理[4/4]

原文:https://towardsdatascience.com/creating-and-training-a-u-net-model-with-pytorch-for-2d-3d-semantic-segmentation-inference-4-4-e52b074ddf6f?source=collection_archive---------20-----------------------

PyTorch 和 U-Net 语义分割指南

作者图片

在之前的章节中,我们构建了一个数据加载器,创建了一个可配置的 U-Net 模型,并开始使用 Carvana 数据集的样本进行训练。现在让我们用这个训练好的模型来预测一些网络没有看到的图像的分割图。你可以在这里找到 Carvana 数据集的三幅图像。这部分的 Jupyter 笔记本可以在这里找到,GitHub repo 这里找到。

推理

为了进行推理,我们需要在数据通过网络之前对其进行一些转换。这包括线性缩放,改变维度的顺序(我们想要[C,H,W]而不是[H,W,C])和调整图像的大小。因此,我可以编写一个简单的predict()函数,它将图像作为np.ndarray、模型、预处理和后处理函数以及应该在其上执行推理的设备。输入图像经过预处理(第 11 行),转换成torch.tensor,然后发送到设备(第 12 行)。然后通过输出逻辑的模型发送(第 14 行)。请注意,在 UNet 模型的末尾没有应用 Softmax 激活函数,因此必须添加它来进行推断(第 16 行)。结果应在之后进行处理(第 17 行),以便可以在 napari 中或使用 matplotlib 可视化。

让我们首先加载我们训练好的模型

import torch
from unet import UNet
# device
if torch.cuda.is_available():
    device = torch.device('cuda')
else:
    torch.device('cpu')

# model
model = UNet(in_channels=3,
             out_channels=2,
             n_blocks=4,
             start_filters=32,
             activation='relu',
             normalization='batch',
             conv_mode='same',
             dim=2).to(device)

model_name = 'carvana_model.pt'
model_weights = torch.load(pathlib.Path.cwd() / model_name)

model.load_state_dict(model_weights)

并用它来推断:

skimage.io.imread()读取get_filenames_of_path得到的输入和目标路径,并存储在一个列表中:imagestargets。因为训练是在缩小的图像上进行的,所以我将假设推理在类似的输入/质量下会工作得最好。因此,大小为 1918x1280x3 的输入和目标图像被调整为 128x128x3。在预处理函数中,我们只执行与对训练/验证数据执行的步骤相同的步骤,但没有增加。在后处理函数中,我们对输出执行argmax,因为我们不需要每个类的概率(软最大逻辑数),而是预测类,即概率最高的类。我们依次使用模型进行推理来处理我们的图像,并将结果存储在列表outputs中。然后,我们可以再次使用 napari 来可视化结果,并将其与实际情况进行比较。

import napari

viewer = napari.Viewer()

idx = 0
img_nap = viewer.add_image(images_res[idx], name='Input')
tar_nap = viewer.add_labels(targets_res[idx], name='Target')
out_nap = viewer.add_labels(output[idx], name='Prediction')

预测不算太差,但也不算好。所以还有很大的提升空间!但是你能做些什么来改进你的模型呢?这是我想到的一些建议,当然这不是一个完整的列表:

  • 应该对所有可用的数据进行训练,而不仅仅是我从数据集中挑选的 96 张图像。
  • 每辆车有 16 幅图像,它们都应该出现在训练或验证数据集中,而不是两者都出现!请记住,验证数据集的目的是确定停止训练的时间。实施提前停止以找到合适的时间。
  • 提高图像的分辨率。一般来说,更高分辨率的图像可以提取更多的特征。
  • 增加更多的增强,而不仅仅是水平翻转。这人为地扩展了训练数据集的大小,这可能会使您的模型更健壮,更容易概括。
  • 试验超参数!尝试不同的优化器,如 Adam 而不是 SGD,使用不同的激活函数,增加内核数量,使用不同的标准化层,不同的上采样方法等。
  • 尝试骰子损失,而不是标准的 CrossEntropyLoss。或者两者结合使用!
  • 考虑使用迁移学习来更快地学习任务。将 UNet 替换为在此处找到的分段模型之一。这些模型(包括 UNet)可以有不同的主干,并在例如 ImageNet 上进行预训练。
  • 使用联合交集(IoU)等评估指标来衡量特定数据集上模型的准确性。除了可视化结果,这将让你对你的模型有多好有更好的感觉。
  • 尝试混合精度学习,以便能够增加批量大小,或者在处理很快填满内存的高分辨率图像时考虑使用梯度累积。

摘要

在这最后一部分,我们使用我们训练的模型对网络没有看到的图像进行预测(分割图)。推断基本上只是将图像数据传递给网络,而不计算梯度。人们只需确保输入满足网络要求。结果看起来很有希望,但还有改进的余地。

本教程旨在作为深度学习语义分割项目的起点和示例。我建议你去 Kaggle 下载完整的数据集,亲自看看你能训练你的模型到什么程度。你也可以使用现有的数据集,如 Cityscapes (2D),2019 年肾脏肿瘤分割挑战(KiTS19,3D)等,启动自己的语义分割项目。或者创建您自己的数据集,您必须为其提供标签。正如您在本教程中所看到的,训练可以在简单的 PyTorch 中非常容易地进行。但是只有当你想学 PyTorch 的时候,你才应该这么做。一般建议使用更高级别的 API,如闪电、 Fast.ai 或 Skorch 。但是为什么呢?这个在这篇文章里解释的很好。

你或许可以想象,如果你想将功能和特性,如日志记录、度量、提前停止、混合精度训练等整合到你的训练循环中,你最终会做别人已经做过的事情。然而,有可能你的代码不会像他们的一样好和稳定(hello spagetthi code),你会花太多时间在集成和调试这些东西上,而不是专注于你的深度学习项目(hello me)。尽管学习一个新的 API 可能需要一些时间,但从长远来看,它可能会给你很大的帮助。

如果你想实现你自己的特性,看看这篇文章,使用回调和钩子。对于这个系列,我试图保持它非常简单,不使用开箱即用的解决方案。我已经用良好的 ol' PyTorch 实现了一个非常基本的数据处理管道/训练循环,它适用于 2D 和 3D 数据集。

好了,这个小教程就到这里。我希望你喜欢它,学到一些新的东西,并希望我可以让你更容易地开始你自己的深度学习细分项目。感谢您的阅读!

如果您有任何问题,请随时在 LinkedIn 上联系我,或者在 GitHub 上公开问题!

https://johschmidt42.medium.com/membership

在 TensorFlow 2 中创建和训练自定义图层

原文:https://towardsdatascience.com/creating-and-training-custom-layers-in-tensorflow-2-6382292f48c2?source=collection_archive---------18-----------------------

学习创建自己的自定义图层,并在 TensorFlow 2 中对其进行培训

  1. 之前我们已经看到了如何创建自定义损失函数— 使用 TensorFlow 2 创建自定义损失函数
  2. 接下来,我写了使用 Lambda 层创建自定义激活函数— 在 TensorFlow 2 中使用 Lambda 层创建自定义激活函数

这是该系列的第三部分,我们创建自定义的密集层,并在 TensorFlow 2 中训练它们。

简介:

Lambda 层是 TensorFlow 中的简单层,可用于创建一些自定义激活函数。但是 lambda 层有许多限制,尤其是在训练这些层的时候。因此,我们的想法是使用 TensorFlow 中的可继承 Keras 层来创建可训练的自定义层,特别关注密集层。

什么是层?

图一。图层-密集图层表示(来源:作者创建的图像)

层是一个类,它接收一些参数,通过状态和计算传递这些参数,并根据神经网络的要求传递输出。每个模型架构都包含多个层,无论是顺序的还是功能的 API。

状态——主要是在“model.fit”期间训练的可训练特征。在密集层中,状态构成权重和偏差,如图 1 所示。这些值会随着模型的训练而更新,以提供更好的结果。在某些层中,状态还可以包含不可训练的特征。

计算 —计算帮助将一批输入数据转换成一批输出数据。在该层的这一部分中,进行计算。在密集层中,计算执行以下计算—

Y = (wX+c)* ,返回 Y。

y 是输出,X 是输入,w =权重,c =偏差。

创建自定义密集层:

现在我们知道了密集层内部发生了什么,让我们看看如何创建我们自己的密集层并在模型中使用它。

 **import tensorflow as tf
from tensorflow.keras.layers import Layer

class SimpleDense(Layer):

    def __init__(self, units=32):** *'''Initializes the instance attributes'''* **super(SimpleDense, self).__init__()
        self.units = units

    def build(self, input_shape):***'''Create the state of the layer (weights)'''* *# initialize the weights* **w_init = tf.random_normal_initializer()
        self.w = tf.Variable(name="kernel",   initial_value=w_init(shape=(input_shape[-1], self.units),
                 dtype='float32'),trainable=True)** *# initialize the biases* **b_init = tf.zeros_initializer()
        self.b = tf.Variable(name="bias",initial_value=b_init(shape=(self.units,), dtype='float32'),trainable=True)

    def call(self, inputs):***'''Defines the computation from inputs to outputs'''* **return tf.matmul(inputs, self.w) + self.b**

上图 代码解释——类命名为 SimpleDense。当我们创建一个自定义层时,我们必须继承 Keras 的层类。这是在“class SimpleDense(Layer)”行中完成的。

'init' 是类中第一个帮助初始化类的方法。“init”接受参数并将它们转换成可在类中使用的变量。这是从“层”类继承的,因此需要一些初始化。这种初始化是使用“super”关键字完成的。“units”是一个局部类变量。这类似于致密层中的单元数量。默认值设置为 32,但在调用该类时总是可以更改。

‘建’是类中的下一种方法。这用于指定状态。在密集层中,对于权重和偏差,所需的两个状态是“w”和“b”。当创建密集层时,我们不只是创建网络隐藏层的一个神经元,而是一次创建多个神经元(在这种情况下将创建 32 个神经元)。该层中的每个神经元都需要初始化,并被赋予一些随机权重和偏差值。TensorFlow 包含许多内置函数来初始化这些值。

为了初始化权重,我们使用 TensorFlow 的“random_normal_initializer”函数,它将使用正态分布随机初始化权重。“self.w”包含张量变量形式的权重状态。这些状态将使用“w_init”进行初始化。作为权重包含的值将采用“float_32”格式。它被设置为“可训练”,这意味着每次运行后,这些初始权重将根据损失函数和优化器进行更新。添加了“内核”这个名称,以便以后可以很容易地跟踪它。

为了初始化偏差,使用 TensorFlow 的“zeros_initializer”函数。这将所有初始偏置值设置为零。self . b’是一个张量,其大小与单元的大小相同(这里是 32),并且这 32 个偏置项中的每一个最初都被设置为零。这也被设置为“可训练”,因此偏差项将随着训练的开始而更新。添加“偏差”这个名称是为了以后能够跟踪它。

【call】是执行计算的最后一个方法。在这种情况下,由于它是一个密集图层,它将输入乘以权重,加上偏差,最后返回输出。由于 self.w 和 self.b 是张量,而不是单个数值,因此使用“matmul”运算。

*# declare an instance of the class* **my_dense = SimpleDense(units=1)** *# define an input and feed into the layer* **x = tf.ones((1, 1)) 
y = my_dense(x)** *# parameters of the base Layer class like `variables` can be used* **print(my_dense.variables)**

输出:

[<tf.Variable 'simple_dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[0.00382898]], dtype=float32)>, <tf.Variable 'simple_dense/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]

对上面 代码的解释——第一行创建了一个仅包含一个神经元(unit =1)的密集层。x(输入)是值为 1 的形状(1,1)的张量。Y = my_dense(x),帮助初始化密集层。。“变量”帮助我们查看密集层内部初始化的值(权重和偏差)。

“my_dense.variable”的输出显示在代码块下方。它表明‘simple _ dense’中有两个变量叫做‘kernel’和‘bias’。内核‘w’被初始化为值 0.0038,一个随机正态分布值,偏差‘b’被初始化为值 0。这只是层的初始状态。一旦被训练,这些值将相应地改变。

**import numpy as np***# define the dataset* **xs = np.array([-1.0,  0.0, 1.0, 2.0, 3.0, 4.0], dtype=float) 
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)  ** *# use the Sequential API to build a model with our custom layer* **my_layer = SimpleDense(units=1) 
model = tf.keras.Sequential([my_layer])** *# configure and train the model* **model.compile(optimizer='sgd', loss='mean_squared_error') model.fit(xs, ys, epochs=500,verbose=0) ** *# perform inference* **print(model.predict([10.0]))** *# see the updated state of the variables* **print(my_layer.variables)**

输出:

[[18.981567]][<tf.Variable 'sequential/simple_dense_1/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[1.9973286]], dtype=float32)>, <tf.Variable 'sequential/simple_dense_1/bias:0' shape=(1,) dtype=float32, numpy=array([-0.99171764], dtype=float32)>]

上面代码的解释—上面使用的代码是一种非常简单的检查自定义层是否工作的方法。设置输入和输出,使用自定义层编译模型,最后训练 500 个历元。重要的是要看到,在训练模型之后,权重和偏差的值现在已经改变了。最初设置为 0.0038 的权重现在是 1.9973,而最初设置为零的偏差现在是-0.9917。

向自定义密集层添加激活函数:

以前我们创建了自定义密集层,但我们没有添加任何激活随着这一层。当然,要添加激活,我们可以在模型中单独写一行激活,或者添加一个 Lambda 层激活。但是,我们如何在上面创建的同一个自定义层中实现激活呢?

答案是对自定义密集层中的“init”和“call”方法进行简单的调整。

**class** **SimpleDense(Layer):**

    *# add an activation parameter* **  def __init__(self, units=32, activation=None):
        super(SimpleDense, self).__init__()
        self.units = units**

        *# define the activation to get from the built-in activation layers in Keras* **self.activation = tf.keras.activations.get(activation)**

    **def** **build(self, input_shape):** **w_init = tf.random_normal_initializer()
        self.w = tf.Variable(name="kernel",
            initial_value=w_init(shape=(input_shape[-1], self.units),dtype='float32'),trainable=True)** **b_init = tf.zeros_initializer()
        self.b = tf.Variable(name="bias",
            initial_value=b_init(shape=(self.units,), dtype='float32'),trainable=True)
        super().build(input_shape)**

 **def call(self, inputs):**

        *# pass the computation to the activation layer* **  return self.activation(tf.matmul(inputs, self.w) + self.b)**

上图 的代码解释——大部分代码和我们之前用的代码一模一样。

要添加激活,我们需要在“init”中指定我们需要激活。一个字符串或者一个激活对象的实例可以被传递到这个激活中。它默认设置为 None,所以如果没有提到激活函数,它不会抛出错误。接下来,我们必须将激活函数初始化为“TF . keras . activations . get(activation)”。

最后的编辑是在“调用”方法中,在计算权重和偏差之前,我们需要添加自激活来激活计算。所以现在回报是计算和激活。

在 mnist 数据集上激活的自定义密集层的完整代码:

 **import** **tensorflow** **as** **tf**
**from** **tensorflow.keras.layers** **import** **Layer****class** **SimpleDense(Layer):** **def __init__(self, units=32, activation=None):
        super(SimpleDense, self).__init__()
        self.units = units**

        *# define the activation to get from the built-in activation layers in Keras***self.activation = tf.keras.activations.get(activation)**

    **def** **build(self, input_shape):****w_init = tf.random_normal_initializer()
        self.w = tf.Variable(name="kernel",
            initial_value=w_init(shape=(input_shape[-1], self.units),dtype='float32'),trainable=True)****b_init = tf.zeros_initializer()
        self.b = tf.Variable(name="bias",
            initial_value=b_init(shape=(self.units,), dtype='float32'),trainable=True)
        super().build(input_shape)**

 **def call(self, inputs):**

        *# pass the computation to the activation layer***return self.activation(tf.matmul(inputs, self.w) + self.b)****mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0**# build the model **model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),***# our custom Dense layer with activation* **SimpleDense(128, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
])***# compile the model* **model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])***# fit the model* **model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**

使用我们的自定义密集层和激活来训练模型,训练准确率为 97.8%,验证准确率为 97.7%。

结论:

这是在 TensorFlow 中创建自定义图层的方法。尽管我们只看到密集层的工作,但它可以很容易地被任何其他层所取代,例如执行以下计算的二次层——

它有 3 个状态变量 : a,b,c,

计算:

用二次层替换密集层:

**import** **tensorflow** **as** **tf**
**from** **tensorflow.keras.layers** **import** **Layer****class** **SimpleQuadratic(Layer):**

    **def __init__(self, units=32, activation=None):** *'''Initializes the class and sets up the internal variables'''*

       ** super(SimpleQuadratic,self).__init__()
        self.units=units
        self.activation=tf.keras.activations.get(activation)**

   ** def build(self, input_shape):** *'''Create the state of the layer (weights)'''*

        **a_init = tf.random_normal_initializer()
        a_init_val = a_init(shape=(input_shape[-1],self.units),dtype= 'float32')
        self.a = tf.Variable(initial_value=a_init_val, trainable='true')

        b_init = tf.random_normal_initializer()
        b_init_val = b_init(shape=(input_shape[-1],self.units),dtype= 'float32')
        self.b = tf.Variable(initial_value=b_init_val, trainable='true')

        c_init= tf.zeros_initializer()
        c_init_val = c_init(shape=(self.units,),dtype='float32')
        self.c = tf.Variable(initial_value=c_init_val,trainable='true')**

   ** def call(self, inputs):** *'''Defines the computation from inputs to outputs'''* **    x_squared= tf.math.square(inputs)
        x_squared_times_a = tf.matmul(x_squared,self.a)
        x_times_b= tf.matmul(inputs,self.b)
        x2a_plus_xb_plus_c = x_squared_times_a+x_times_b+self.c

        return self.activation(x2a_plus_xb_plus_c)****mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  SimpleQuadratic(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**

这个二次层在 mnist 数据集上给出了 97.8%的验证准确率。

因此,我们可以实现我们自己的层,并根据需要激活 TensorFlow 模型,以编辑甚至提高整体精度。

创建和使用分位数规格化器

原文:https://towardsdatascience.com/creating-and-using-a-quantile-normalizer-5f4ea0332b6f?source=collection_archive---------34-----------------------

创建并使用分位数规格化器,然后将其性能与 z 分数规格化器进行比较。

(src =https://pixabay.com/images/id-937884/

介绍

在数据科学和数据工程的奇妙世界中,能够处理数据的概念非常重要。典型格式的数据是不干净的,几乎任何模型都难以处理。这是数据科学缺乏自动化的一个重要因素,因为需要大量的观察来诊断和反复修复数据。此外,问题有时写得不清楚,很难发现数据中的一些问题。

经常观察到的连续值的一个问题是方差和数据的数量。当然,有几个很好的方法可以纠正甚至注意到这个问题。然而,我今天想看的方法是分位数法。我认为这是一个非常不寻常的方法,但我不认为这样做是正确的。

笔记本

什么是分位数?

当然,为了使用分位数转换器或分位数规格化器,我们首先需要理解什么是分位数。分位数是数据中基于数字索引位置的逻辑点。考虑到这一点,这与用平均方法做同样的事情有着显著的区别和有趣的关系。最熟悉的分位数的一个例子是中位数。中位数也称为第二分位数。有两个额外的标记分位数,分位数 1,记录在 25%的指数上,同样记录在 75%的指数上。因为我们没有计算这种东西的函数,所以我们需要写一个。我将通过创建两个新参数来开始一个函数,x,它将是我们想要找到其分位数的数组,然后 q. Q 将是数据中的分割点。我还允许为这个参数提供一个数字和一个浮点数。

function quantile(x::Array, q::Real = .5)

接下来,我将为 Q1–Q3 创建一个带有数字键的新字典。这将允许我们简单地索引我们的字典,因此用户可以在这里提供整数和浮点数。当然,这也可以用多重分派来解决,但是我认为重要的是要注意,我们只是使用字典将这些数字转换成浮点数。

qdict = Dict(1 => .25, 2 => .5, 3 => .75)if q >= 1tryq = qdict[q]catchthrow(ArgumentError(" The quantile parameter is not set to a percentage, or quantile!"))endend

现在,如果我们的数字恰好在“qdict”中,我们的 q 参数将被设置为等于给定分位数的正确对应分数。如果这个值不在我们的字典中,但也大于 1,那么我们将抛出。基本上,使用这部分代码是为了既可以调用分位数 2–4,也可以调用具有任何特定级别的未标记分位数的浮点数。接下来,我们将对数组进行排序,这对于获得正确的数值距离至关重要。之后,我们会得到数组的长度。

sorted = sort(x)div = length(x)

最后,我们将索引我们的长度和我们选择的舍入长度的乘积,以便找到数组位置的特定部分:

return(x[Int64(round(div * q))])end

我们的最终分位数函数看起来有点像这样:

function quantile(x::Array, q::Real = .5)qdict = Dict(1 => .25, 2 => .5, 3 => .75)if q >= 1tryq = qdict[q]catchthrow(ArgumentError(" The quantile parameter is not set to a percentage, or quantile!"))endendsorted = sort(x)div = length(x)return(x[Int64(round(div * q))])end

现在我们可以通过调用第二个分位数或. 5 来创建一个中值函数:

median(x) = quantile(x, .5)

分位数标准化器

在我们使用分位数规格化器之前,我们需要了解它是如何工作的。这个规格化器背后的原理是,设置在第三分位数和第一分位数以下的值可能有点像异常值。我还将使用参数使位置可编辑。然后我会把这些数字插入到我们的分位数方法调用中。

mutable struct QuantileNormalizer <: LatheObjectq1q3function QuantileNormalizer(x::Array, lower::Float64 = .25, upper::Float64 = .75)q1 = quantile(x, lower)q3 = quantile(x, upper)endend

现在让我们修改这个内部构造函数来实际创建这个类型,以及一个真正的函数来计算一些东西。考虑到这一点,我向我们的 struct 添加了一段新数据,然后通过调用所述函数来完成这个构造函数,然后将它放入我们的 new()方法中。

mutable struct QuantileNormalizer <: LatheObjectq1::Realq3::Realpredict::Functionfunction QuantileNormalizer(x::Array, lower::Float64 = .25, upper::Float64 = .75)q1 = quantile(x, lower)q3 = quantile(x, upper)predict(x::Array) = qn_pred(x, q1, q3)new(q1, q3, predict)end

最后,最后一个组件是在新的 qn_pred()函数中规范化数据。下面是我想到的函数,它使用一个带有条件语句的迭代循环:

function qn_pred(x, q1, q3)[if i > q3 x[current] = q3 elseif i < q1 x[current] = q1else x[current] = i end for (current, i) in enumerate(x)]end

让我们快速检查一下这实际上会对一些数据产生什么影响:

x = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]5
 10
 15
 20
 25
 30
 35
 40
 45
 50

第一步是用这个数据做一个规格化器,像这样:

normalier = QuantileNormalizer(x)

最后,我们将它预测回我们的阵列:

normaledx = normalier.predict(x)10
 10
 15
 20
 25
 30
 35
 40
 40
 40

我们看到我们较低的数字变成了较大的数字,而我们较高的数字变成了最小的数字。这将有助于保持数据集中。这使我们能够显著改变数据的方差,而对平均值基本没有影响,这对于保持连续数据的一致性是不可或缺的:

using Lathe.stats: meanprintln(mean(x))println(mean(normaledx))26.5
26.5

结论

在统计和度量的世界中,分位数度量是一个非常酷的度量,但也经常被使用不足。分位数可以告诉我们许多关于数据间距的信息,这是处理数据时需要理解的一件非常重要的事情。我认为这个分位数归一化器肯定会派上用场,尽管它的应用可能更适合正态分布或标准标度的数据。无论如何,在这篇文章中,我只想写一个,然后继续展示它。记住这一点,非常感谢您的阅读;它对我来说意味着一切!

用最少的代码在 Python 中创建 APA 样式的绘图

原文:https://towardsdatascience.com/creating-apa-style-plots-in-python-e8adddc3421?source=collection_archive---------57-----------------------

完全基于 Python 的心理学研究管道的最后一步

绿色变色龙在 Unsplash 上的照片

APA 是什么?

APA 是一个神奇的词,很可能是你阅读这篇文章的原因。

像许多心理学学生一样,我学会了如何收集、分析和解释数据。但这还不是全部。

如果你读过这些教程,你可能会有同感。在这些教程中,准心理学家学会掌握引用研究论文的艺术,加上牛津逗号,以及构成一篇好的心理学论文的其他一切。(关于通用预约定价安排的更多信息:【APA.org】T4。)

心理学(和其他实验科学)教育让学生们有能力以最好的方式(阅读:最清晰的)解释和呈现数据。这里有一个反例:

为灌输虚假信心而制造的欺骗性阴谋(作者图片,灵感来自梅塔和古兹曼)

通过省略轴值和巧妙地操纵轴起点,不知情的读者可能会被骗以为竞争对手失败了。虽然这看起来像是一个高度人为的例子,但真实的案例在媒体中比比皆是。

当你花了几年时间学习如何设计无偏见的实验,收集适当的数据,并进行无偏见的分析时,你最不希望的事情就是以一种分散——或者更糟的是欺骗——你的读者的方式呈现结果。

研究中的数据可视化不仅仅是拥有漂亮的图表,也不意味着改变观点。因此,APA 的指导方针已经到位,以促进无偏见的数据呈现,传递真实的信息。

为什么是 Python?

鉴于对样式和格式的强调,基本的数据可视化(想想 Excel 中自动生成的图表)不被认可就不足为奇了。清晰度和美感—风格— 必须与来之不易的数据相称。

这就是 Python 和 R 出现的原因。如果您可以使用 R 和 ggplot2 包,那么设计一个您想要的美学定制的图形应该不成问题。

但是如果你可以用 Python 做同样的事情呢?毕竟,越来越多的实验是用 Python 设计和运行的(例如,参见 psychopy 和 pygame ),而不是使用专有的实验软件。开源软件包提供了更多的统计分析。想象一下,有一个完整的管道,您可以在其中收集、分析和可视化数据,所有这些都在一个工具中完成。很神奇,不是吗?另外,它开辟了新的职业机会;)

与使用简单图形用户界面创建图形的软件相比,使用 Python 和 R 代码的一些优势包括:

  1. 准确性:用代码进行数据分析和可视化,不容易出现人工错误。(错误仍然会发生,但也更容易被发现和纠正。)例如,在一个图形上,你不可能意外地把你的对照组标为实验组。
  2. 便利:从长远来看,你节省了时间。代码可重复用于相同的分析,即使是在多年以后。
  3. 开放科学:分享实验程序和数据分析代码的能力将极大地帮助你的读者和任何对复制你的工作感兴趣的人。快速浏览脚本后,任何错误都会变得明显,正确的实现也是如此。

你能实现什么?

美丽的情节,可以传达和突出你的结果,在几行代码内完成。创建自定义的“APA style”样式表后,样式将在后台完成。

这里有一个例子:

import matplotlib
import matplotlib.pyplot as pltmatplotlib.style.use(matplotlib.get_data_path()+'/stylelib/apa.mplstyle') # selecting the style sheetx = np.linspace(1., 8., 30) # create dummy dataplt.figure()
plt.plot(x, x**2, label=r'This is line a ($y=x^2$)')
plt.plot(x, 30/x, label = r'This is line b ($y=\frac{20}{x}$)')
plt.xlabel('Time (s)')
plt.ylabel('Measurement (unit)')
plt.legend()

APA 样式线图示例(图片由作者提供)

与使用相同代码但不使用自定义样式表的绘图相比:

默认样式线图示例(作者提供的图片)

matplotlib 附带了相当多的样式表。你可以在这里看看它们,或者自己测试一下:

import matplotlib
print(matplotlib.style.available)matplotlib.style.use('seaborn') # or any other style

虽然这种现成的款式确实很漂亮,但除了“灰度”、“seaborn-colorblind”和“tableau-colorblind”之外,大多数都使用了不太容易接近的颜色。

但是我们可以做得更好。建议“结合色彩使用图案,使元素的区分不仅仅依靠色彩。”在让情节更容易出版的同时,加入你的个人风格也没有坏处。

下面是它可能的样子,稍微详细一点:

APA 样式条形图示例(图片由作者提供)

对于神经心理学中的梅西耶图:

用 ax.vlines 添加阴影,用 ax.annotate 添加注释(图片由作者提供)

带 ax.vlines 的垂直虚线和多条线以及它们的平均值(图片由作者提供)

所有的数据和标签都被故意混淆了。

如何创建样式表?

matplotlib 文档解释了这一切。以下是基本步骤:

  1. 创建一个空白的纯文本文件,并将其命名为 YOUR_CHOICE.mplstyle(在我的例子中是 apa.mplstyle)。记住你把这个文件放在哪里,例如,在你的 matplotlib 路径中。
  2. 在这个文件中写下你想要定制的所有方面。浏览文档或你的 matplotlibrc 文件以获得灵感。
  3. 打开 Python IDE,导入 matplotlib,选择样式表,然后像平常一样开始绘图。
import matplotlib
import matplotlib.pyplot as pltmatplotlib.style.use(matplotlib.get_data_path()+'/stylelib/apa.mplstyle') # selecting the style sheet

一些想法:

font.family:  sans-serif # APA requires sans-serif fontfigure.titleweight: bold # weight of the figure titleaxes.facecolor:  white   # figure background coloraxes.spines.top:    False # remove top axis (the "frame")
axes.spines.right:  False # remove right axis (the "frame")
axes.spines.bottom: True  # only display the x axis on the bottom
axes.spines.left:   True  # only display the y axis on the leftsavefig.format:     svg   # save as vector image by default

另一个有用的工具是cycler,它允许完全控制线条类型和颜色,所以你可以有黑色实线、黑色虚线等等。,直到循环结束:

axes.prop_cycle: cycler('color', ['k', 'k', '0.5', '0.5', 'b', 'b', 'r', 'r']) + cycler('linestyle', ['-', '--', ':', '-.','-', '--',':', '-.']) # 'k' for black, 'r' for red, '0.5' for midgray

我已经把我最后的 apa.mplstyle 文件放在这里了,它一点也不完美,也不完整(我在假期不得不做几十个纸图的时候匆忙做的),但它可能是一个好的开始(请让我知道你的改进想法!)

希望这有助于更容易地将 Python 整合到您的研究管道中,我希望您能像我一样喜欢处理数据。

使用 Plotly、Datapane 和 GitHub 操作创建自动化 Python 仪表板

原文:https://towardsdatascience.com/creating-automated-python-dashboards-using-plotly-datapane-and-github-actions-ff8aa8b4e3?source=collection_archive---------2-----------------------

来源

今天,大多数在线数据科学课程都教你机器学习和深度学习;您将学习如何优化超参数,而不是 SQL、数据分析、报告、云服务等基础知识。但在现实世界中,分析数据,学习如何“自动化枯燥的东西”,创建 ETL 管道和仪表板,并引导利益相关者或客户走上正确的道路,往往会带来更多的价值。更多的数据团队失败是因为数据科学从未影响业务决策,而不是因为他们的模型没有优化。

在现实世界中,数据科学家面临的问题不仅仅是如何调整 ML 模型和比较指标,就像他们在 Kaggle 比赛中一样。他们面临的问题是被困在当地的 Jupyter 笔记本上,无法与使用他们分析的人联系。如果我们构建的数据产品(如 ML 模型、自动化平台或报告)对利益相关者或客户的决策过程没有帮助,我们就会失去最初的“存在理由”

高层主管对数字和见解感兴趣;而不是你在神经网络中使用的激活函数。

好的数据产品的主要驱动因素是与业务单元协作并定期获得反馈。你越积极参与决策过程,你就越了解如何检验假设和解决“真正的”问题,而不是教科书上的问题。在一天结束时,你的发现和故事将转化为推动结果的行动。

不幸的是,你不能把你的笔记本发给一个利益相关者,然后期望他们自己理解并运行它。这意味着,在许多公司中,您会收到一封来自业务部门的电子邮件,其中包含一个请求,重新运行 Jupyter 笔记本,然后手动构建 PowerPoint 或 Excel 电子表格。这种手动流程意味着数据科学家是洞察的瓶颈,他们花费大量时间手动构建报告,而不是解决难题。

处理问题的第一步也是关键的一步是创建 KPI 和精心制作的自动化报告和仪表板,它们可以提供价值,并消除您参与每个问题或数据刷新的需要。在与利益相关者(产品、增长、营销经理等)集思广益并与工程师合作后,您可以开始这个过程。幸运的是,Python 生态系统提供了一些方便的工具来构建工作流。

在本文中,我们将使用 Python 通过 pandas datareader 实时拉动股票市场价格,并使用 PlotlyDatapane 创建一个交互式报告。然后我们将使用 GitHub actions 来触发我们的代码每天运行以更新我们的报告。

每天早上 6 点(UTC)创建自动化仪表板有 4 个步骤:

  1. 为我们的可视化创建 Plotly 函数

2.使用 Datapane 的库在 Python 中创建报告

3.为 GitHub 操作编写一个. yml 文件

4.在线分享报告或将其嵌入博客

Plotly 是一个开源库,可以轻松创建交互式可视化。

Datapane 是一个开源框架,帮助我们轻松地与团队成员和利益相关者分享见解,而不需要第三方 BI 工具或 web 服务。

Github Actions 是一个运行代码的自动化平台,它使得直接在您的 Github 存储库中创建定制的软件开发生命周期工作流变得非常容易。

  1. 为仪表板创建 Plotly 函数
  • 创建了一个网飞股票价格散点图
  • 添加了 10 天、20 天移动平均线
  • 更新的标题布局

2。为报告创建数据面板功能

  • 所有数字相加
  • 定义的列和行

你可以接触到 GitHub 回购中的所有数字。

有关布局和定制的更多详细信息,请阅读文档。

https://docs.datapane.com/reports/layout-and-customization

3。为 GitHub 动作编写一个. yml 文件

  • 新增要求(熊猫-阅读器)
  • 计划的 cron 作业(每天早上 6 点)
  • 添加了脚本和令牌

有关构建 GitHub 动作的更多详细信息,请阅读文档。

https://github.com/marketplace/actions/datapane-build

4。在线分享报告或将其嵌入博客

https://datapane.com/u/kaan/reports/stock-analysis/

https://github . com/data pane/gallery/blob/master/stock-reporting/stocks . ipynb

如果你有任何问题,你可以通过推特或 LinkedIn 联系我。

使用 Bicep 和 Azure DevOps YAML 管道创建 Azure 数据块

原文:https://towardsdatascience.com/creating-azure-databricks-with-bicep-and-azure-devops-yaml-pipelines-4bf85be30cc7?source=collection_archive---------20-----------------------

继续 DataOps 自动化系列,在这篇文章中,我将演示如何使用基础设施作为代码,通过 Bicep 和 Azure DevOps YAML 管道在 Azure 中部署它,来创建您的 Databricks 工作区。我们去看看吧!

由本杰明·乔朋在 Unsplash 拍摄的照片

在之前的文章中,您可以查看如何使用 Bicep 创建具有 git 集成的 Azure 数据工厂,以及为 Azure 数据工厂创建 CI/CD 管道的最简单的方法

在文章的最后,你可以检查一个完整的 YAML 管道阅读使用!

什么是二头肌模板?

如果您不熟悉 Bicep,这是一个用于 ARM 模板的 DSL,它具有更清晰的语法、对模块更好的支持以及其他出色的特性。它还有一个很好的 Visual Studio 代码扩展,在从头构建模板方面帮助很大。

Visual Studio 代码的很好的扩展!—图片来自微软文档

当您使用 bicep 模板运行部署时,它会转换文件并生成本机 ARM 模板,类似于 Typescript 和 Javascript 之间发生的情况。

如果你想了解更多,查看官方文档这里。

将基础设施创建为 Azure 数据块的代码

使用 Azure CLI 创建资源组

要部署我们的 Databricks 工作区,我们需要在您的 Azure 订阅中创建一个资源组。最简单的方法是通过 Azure CLI。为此,您需要使用命令az login登录,然后运行以下命令:

az group create -name RG-Databricks -location northeurope

将参数名称和位置替换为最适合您需求的名称和位置。

为 Azure 数据块创建 Bicep 模板

Azure Databricks 的 Bicep 模板非常简单,有 4 个主要部分:

参数:

  • 工作区名称:如果您不提供值,它将使用一个uniqueString函数,这将确保它总是相同的,因为这是基于资源组 id 的。
  • 位置:默认情况下,这是使用资源组位置
  • SKU:默认值是试用,所以请务必在您的现实生活场景中替换它;).

变量:模板也有变量managedResourceGroupName。该资源组将由 Azure Databricks 管理,以便稍后创建您的集群。

资源:这里我们只有一个资源,即 Databrics 工作区。这是消费 API 版本2018–04–01

输出:这个部分包含了您需要公开的变量。这意味着它们可以在部署过程的后期被其他过程访问。

使用 Azure DevOps YAML 管道部署 Bicep

构建二头肌模板

正如我之前所说,将二头肌模板移植到手臂模板中是可能的。因此,为了确保我们的模板是有效的,让我们这样做!

为了构建它,您还将使用 Azure CLI。命令也很简单:

az bicep build --file <your file> --outdir <your directory>

为了创建 Azure DevOps YAML 管道,我们将在 AzureCLI 任务中运行上面的命令:

将二头肌移植到手臂模板后,它将作为部署人工制品部署,读取以供使用:

作者准备的图像

作者准备的图像

构建您的二头肌是一个很好的实践,因为您可以验证其中没有错误,并收集所有需要部署的文件。

使用 YAML 管道部署 Bicep

有了构建步骤中生成的工件,现在我们就可以在我们的环境中部署它们了。为此,有必要在构建 YAML 中再添加一个阶段,其中包含运行 ARM 模板的指令:

它使用负责将 ARM 模板运行到 Azure 订阅中的任务AzureResourceManagerTemplateDeployment@3。你可以在这里获得关于这个任务的更多信息。

这个阶段代表发展阶段。要在其他环境中部署它,您只需复制它并根据您的环境替换值:)

现实生活中的例子

为了在更现实的情况下检查这些例子,我一直在 GitHub 存储库中工作,其中有一些管道配置和工作的例子。你可以在 DevOps Nights GitHub 这里查看:DevOps Nights/azuredevops-YAML-quick start-templates(github.com)

数据布里克斯 YAML 管道公司

正如下面所承诺的,你可以检查一个完整的 Azure DevOps YAML 管道配置和工作:

结论

Bicep 已经成为 Azure 的一个非常相关的工具,并且很有可能成为 Azure 中基础设施的默认工具。所以现在就开始熟悉吧,以后会很有关系的:)

我希望这篇文章能帮到你,下次再见!

创建基线机器学习模型

原文:https://towardsdatascience.com/creating-baseline-machine-learning-models-d40c99243311?source=collection_archive---------32-----------------------

使用 Dabl 进行数据预处理和机器学习建模

Firmbee.com在 Unsplash 上拍照

创建机器学习模型包括许多预处理,其中我们操纵特征和目标变量来为机器学习模型准备数据。这种预处理包括检查数据中是否有丢失的值,清除垃圾值,以及可视化数据以进行探索性的数据分析。

在对数据执行所有这些操作之后,我们开始新的努力,以创建一个具有更高准确性和良好性能的机器学习模型。为了做到这一点,我们首先创建不同的机器学习模型,然后选择性能最佳的模型作为基线模型。

如果我告诉你,你可以在几行代码中完成所有这些,并节省你的时间和精力来优化你的模型,会怎么样?是的,Dabl 可以做到这一切。它是一个开源 python 库,用于执行数据预处理、数据可视化和创建基线模型。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装 Dabl 开始。下面给出的命令可以做到这一点。

pip install dabl

导入所需的库

在这一步中,我们将导入加载数据、执行 EDA 以及为该数据集创建基线模型所需的库。

import dabl
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_digits

正在加载数据集

在这篇文章中,我们将使用著名的糖尿病数据集,可以很容易地从网上下载。

df = pd.read_csv("Diabetes.csv")

预处理数据

在这一步中,我们将使用 Dabl 的 clean 函数清理数据,并找出所有特征和目标变量的数据类型。

dia_clean = dabl.clean(df, verbose=0)

干净的数据(来源:作者)

types = dabl.detect_types(dia_clean)
types

数据类型(来源:作者)

执行 EDA

在这一步中,我们将创建可视化来查看数据模式,并收集一些关于数据的初步见解。

dabl.plot(dia_clean, 'Outcome')

EDA(来源:作者)

创建基线模型

这是最后一步,我们将在一行代码中找到数据的基线模型。Dabl 在后台运行不同的模型,找出表现最好的模型。

features = ['Pregnancies', 'Glucose','BloodPressure','SkinThickness','Insulin','BMI','DiabetesPedigreeFunction','Age']
Y = df['Outcome']
X =  df[features]
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2)
sc = dabl.SimpleClassifier().fit(X_train, Y_train)
print("Accuracy score", sc.score(X_test, Y_test))

基线模型(来源:作者)

在这里,您可以看到 Dabl 如何向我们展示最佳性能模型及其准确性得分。我们可以选择这个模型进行进一步的调整和优化。

在本文中,我们看到了 Dabl 如何用于数据预处理、执行 EDA 和创建基线模型。继续尝试使用不同的数据集,并让我知道您在回复部分的评论。

本文是与皮尤什·英加尔合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

用 Python 创建漂亮的地图

原文:https://towardsdatascience.com/creating-beautiful-maps-with-python-6e1aae54c55c?source=collection_archive---------5-----------------------

Python + OSMnx

柏林地图——作者图片

我一直喜欢城市地图,几周前,我决定建立自己的艺术版本。谷歌了一下之后,我发现了这个令人难以置信的教程,作者是弗兰克·塞瓦洛斯。这是一个迷人和方便的教程,但我更喜欢一个更详细/现实的蓝图地图。正因为如此,我决定建立自己的版本。因此,让我们看看如何用一点 python 代码和 OpenStreetMap 数据创建漂亮的地图。

安装 OSMnx

首先,我们需要有一个 Python 安装。我推荐使用 Conda 和虚拟环境(venv)来实现整洁的工作空间。此外,我们将使用 OSMnx Python 包,它将允许我们从 OpenStreetMap 下载空间数据。我们只需编写两个 Conda 命令就可以完成 venv 的创建和 OSMnx 的安装:

conda config --prepend channels conda-forge
conda create -n ox --strict-channel-priority osmnx

下载街道网络

成功安装 OSMnx 后,我们就可以开始编码了。我们需要做的第一件事是下载数据。下载数据可以通过不同的方式实现,最简单的方式之一是使用graph_from_place()

下载柏林街道网络

graph_from_place()有几个参数。place 是将在 OpenStreetMaps 中用于检索数据的查询,retain_all将给出所有街道,即使它们没有连接到其他元素,simplify稍微清理一下返回的图,network_type 指定要获取的街道网络的类型。

我正在寻找检索all可能的数据,但你也可以下载只有驱动道路,使用drive,或使用walk 步行路径。

另一种可能是使用graph_from_point() ,它允许我们指定一个 GPS 坐标。这个选项在多种情况下更方便,比如有普通名称的地方,并且给我们更多的精确性。使用dist 我们可以只保留那些在图中心几米内的节点。

正在下载马德里街道网络

此外,有必要考虑到,如果你是从更大的地方下载数据,如马德里或柏林,你将需要等待一点,以便检索所有的信息。

打开包装并给我们的数据着色

graph_from_place()graph_from_point()都将返回一个多图,我们可以将其解包并存储在列表中,如 Frank Ceballos 教程所示。

达到这一点,我们只需要迭代数据并给它着色。我们可以给它上色,并根据街道长度调整线宽

但是也有识别某些道路的可能性,只是它们的颜色不同。

在我的例子中,我只使用了下面的颜色。

color = "#a6a6a6 "

color = "#676767 "

color = "#454545 "

color = "#bdbdbd "

color = "#d5d5d5 "

color = "#ffff "

但是你可以随意改变颜色或条件来创建符合你口味的新地图。

绘制并保存地图

最后,我们只需要做一件事,就是绘制地图。首先,我们需要确定地图的中心。选择您想要作为中心的 GPS 坐标。然后我们将添加一些边界和背景颜色,bgcolornorthsoutheastwest西部将是我们地图的新边界。这个坐标将基于这些边界裁剪图像,只需在你想要的更大的地图中增加边界。考虑到如果你使用graph_from_point()方法,你将需要根据你的需要增加dist值。对于bgcolor,我选择了蓝色,深蓝色#061529,来模拟一个蓝图,但是你也可以根据自己的喜好来调整。

之后,我们只需要绘制和保存地图。我建议使用fig.tight_layout(pad=0)来调整剧情参数,这样支线剧情就能很好的配合。

结果

使用这段代码我们可以构建下面的例子,但是我建议你调整你的设置,比如每个城市的线宽或者边界限制。

马德里城市地图—海报尺寸

graph_from_place()graph_from_point()之间需要考虑的一个区别是graph_from_point()将根据您设置的dist从周围获取街道数据。这取决于你想要简单的地图还是更详细的地图,你可以在它们之间进行交换。使用graph_from_place()创建了马德里城市地图,使用graph_from_point()创建了柏林城市地图。

柏林城市地图

最重要的是,你可能想要一张海报大小的图片。一种简单的方法是在ox.plot_graph()中设置figsize属性。figsize可以调整宽度,高度以英寸为单位。我一般选择大一号的像figsize=(27,40)

奖励:加水

OpenStreetMap 也有来自河流和其他自然水源的数据,如湖泊或水渠。再次使用 OSmnx,我们可以下载这些数据。

下载自然水源

用和以前一样的方法,我们可以迭代这个数据并给它着色。在这种情况下,我更喜欢蓝色,如#72b1b1 或#5dc1b9。

最后,我们只需要保存数字。在这种情况下,我没有使用任何带有plot_graphbbox的边框。这是另一个你可以玩的东西。

成功下载 rivers 和 like 后,我们只需要将这两幅图像连接起来。只需要一点 Gimp 或者 Photoshop 就可以了,记住用相同的fig_size或者限制边框bbox来创建两幅图像,这样更容易插值。

柏林天然水源

收尾

我喜欢添加的一件事是带有城市名称、GPS 坐标和国家名称的文本。再来一次 Gimp 或 Photoshop 就行了。

此外,如果你添加水,你需要填充一些空间或油漆其他水源,如海水。河流的线条不是恒定的,但是使用油漆桶工具你可以填充这些缝隙。

代码和结论

创建这些地图的代码可以在我的 GitHub 上找到。请随意使用,并向我展示您的结果!!希望你喜欢这篇文章,再次感谢弗兰克·塞巴洛斯和媒体社区。另外,如果你们中的任何人想打印一些海报,我在 Etsy 上开了一个小店,里面有我的地图作品。

感谢阅读我和分享知识将引导我们更好的和不可思议的结果!!

在 Python 中使用 Matplotlib 创建箱线图

原文:https://towardsdatascience.com/creating-boxplots-of-well-log-data-using-matplotlib-in-python-34c3816e73f4?source=collection_archive---------1-----------------------

使用箱线图了解数据分布,识别岩石物理和测井数据中的异常值

使用 python 中的 matplotlib 生成具有不同 y 轴范围的多个箱线图。图片作者。

箱线图是一个很好的数据可视化工具,它们可以用来了解数据的分布,无论它是否偏斜,以及是否存在异常值。在本文中,我们将看看什么是盒图,以及如何使用 pandas 和 matplotlib 显示它们。

为了配合这篇文章,我制作了以下 YouTube 视频。

什么是箱线图?

箱线图是一种基于五个关键数字显示数据分布的图形和标准化方法:最小值、第一个四分位数(第 25 个百分位数)、中值(第二个四分位数)。/第 50 个百分位数)、第 3 个四分位数(第 75 个百分位数)和“最大值”。最小值和最大值分别定义为 Q1-1.5 * IQR 和 Q3 + 1.5 * IQR。任何超出这些限制的点都被称为异常值。

箱线图的图形描述,突出显示关键组成部分,包括中位数、四分位数、异常值和四分位数间距。作者创建的图像。

箱线图可用于:

  • 识别异常值或异常数据点
  • 来确定我们的数据是否有偏差
  • 了解数据的分布/范围

为了构建箱线图,我们首先从中值/第 50 百分位(Q2)开始。这代表了我们数据中的中间值。

然后在第 25 和第 75 个百分点之间形成一个方框(分别为 Q1 和 Q3)。这个方框表示的范围称为四分位间距(IQR)。

从这个盒子里延伸出线条,也就是众所周知的胡须。这些延伸到 Q1-1.5 * IQR 和 Q3 + 1.5 * IQR,或者延伸到小于该值的最后一个数据点。

任何超出晶须极限的点都称为异常值。

导入库和数据

我们将在 Jupyter 笔记本中执行的前几个步骤包括加载库和数据。在这种情况下,我们将使用 lasio 加载我们的日志 ASCII 标准(LAS)文件, pandas 存储我们的测井数据,以及 matplotlib 可视化我们的数据。

Lasio 是一个您可能不熟悉的库,但它用于加载 LAS 文件,石油和天然气行业通常使用这些文件来存储和传输测井数据。你可以看看我的第一个 YouTube 视频,它解释了如何使用这个库。

import pandas as pd
import matplotlib.pyplot as plt
import lasio

接下来,我们将加载并查看我们的数据。我们可以使用lasio.read()并传入一个文本字符串来做到这一点。为了将它转换成熊猫数据帧,我在它的末尾添加了.df()

我们正在使用的数据集来自于 2018 年发布的 Equinor Volve Field 数据集。本教程中使用的文件来自 15/9- 19SR 井,其中包含一组标准测井测量值。

df = lasio.read("Data/15-9-19_SR_COMP.LAS").df()

Pandas 数据框显示了测井数据的前五行和后五行。

当我们调用 dataframe 时,我们可以看到我们有一个表示前 5 行和后 5 行数据的表。每一列代表一个测井测量值。从左到右,我们用 AC 表示声波压缩慢度,用 CALI 表示井径,用 DEN 表示体积密度,用 GR 表示伽马射线,用 NEU 表示中子孔隙度和 RDEP,用 RMED 表示深层和中层电阻率。

为了使用一些 matplotlib 图,有必要删除由 NaN 表示的缺失值。我们可以通过使用.dropna()来移除这些。添加inplace=True允许我们从原始数据帧而不是它的副本中删除这些。

df.dropna(inplace=True)

当我们再次调用df时,我们可以看到行数从 6701 减少到 6579。

Pandas 数据框显示了移除 nan 后的前五行和后五行测井数据。

使用熊猫的简单方框图

现在我们的数据已经加载,我们可以生成我们的第一个箱线图。我们可以通过键入df['GR']从数据帧中选择 GR 列,然后键入.plot()来做到这一点。

在 plot 方法的参数中,我们传入kind=box来告诉函数我们想要一个 boxplot。

#Simple boxplot using pandas
df['GR'].plot(kind='box');

数据中 GR 列的简单箱线图。图片作者。

当我们运行这个单元时,我们得到一个非常基本的箱形图。我们有四分位数范围框,它包含中线。从两边延伸的是胡须,延伸到四分位间距的 1.5 倍。在顶部,我们有一系列圆圈,代表异常值。

带对数轴的箱线图

我们可以看看另一条曲线,在这种情况下,RDEP(深电阻率)。

#Viewing logarithmically scaled data
df['RDEP'].plot(kind='box');

数据中 RDEP 柱的简单箱线图。图片作者。

如果我们重复上面的代码,我们可以看到在图的底部有一个小方框,上面有大量的异常值。根据经验和现有知识,RDEP 通常以对数标度绘制,其范围可以从大约 0.01 欧姆毫米到大约几千欧姆毫米。

为了解决这个问题,我们可以通过添加plt.semilogy()将 Y 轴切换到对数刻度。你会看到我们现在使用 matplotlib 符号,这是因为 pandas 调用 matplotlib 来构建这个方框图。

df['RDEP'].plot(kind='box')
plt.semilogy();

使用半对数将 Y 轴设置为对数后,数据中 RDEP 列的简单箱线图()。图片作者。

使箱线图水平

如果我们更喜欢水平查看我们的盒状图,我们可以添加一个vert参数,它用来告诉这个图是垂直显示(真)还是水平显示(假)。默认情况下,它被设置为 True。

#Rotating the box plot so it is horizontal
df['GR'].plot(kind='box', vert=False);

GR 列的水平箱线图。作者图片

带 Matplotlib 的箱线图

上面的代码单元是使用 matplotlib 周围的 pandas 包装器完成的,如果我们想要使用 matplotlib 函数和语法,我们可以生成如下所示的相同图形。首先,我们调用plt.boxplot(),然后将 x 参数设置为df['GR']

#Using matplotlib to make a boxplot
plt.boxplot(x=df['GR'], vert=False);

使用 matplotlib 创建的水平箱线图。图片作者。

设计箱线图的样式

Matplotlib 图不是很时尚,用于生成它们的代码非常低级。这就是为什么有许多基于 matplotlib 开发的库,如 seaborn,并引入了更多的功能,使可视化更具吸引力。

首先,我们将通过改变异常圆的颜色来给我们的图添加一些颜色。为此,我们创建一个名为red_circle的新变量,然后创建一个字典。在这个字典中,我们将设置markerfacecolormarker。这些将分别设置为红色和圆形。

#Changing the outlier markers
red_circle = dict(markerfacecolor='red', marker='o')
plt.boxplot(x=df['AC'], vert=False, flierprops=red_circle);

Boxplot 突出显示 matplotlib 中的异常值并使用 fliersprops 参数。图片作者。

当我们运行这段代码时,我们现在用一些颜色来突出我们的异常值。

在当前箱线图上,我们的 IQR 框内有一条橙色线代表的中值。我们还可以通过创建另一个名为mean_shape的字典变量来添加数据的平均值。

我们为markerfacecolormarker设置了与之前相同的参数,它们都将被设置为绿色和菱形。要选钻石,我们可以用字母 d。

此外,我们将通过添加一个markeredgecolor变量来改变均值标记的边缘颜色。默认情况下,它被设置为黑色,但这里我们将它设置为绿色。

#Adding the mean
red_circle = dict(markerfacecolor='red', marker='o')
mean_shape = dict(markerfacecolor='green', marker='D', markeredgecolor='green')

plt.boxplot(x=df['AC'], vert=False, flierprops=red_circle, 
             showmeans=True, meanprops=mean_shape);

Matplotlib boxplot 使用 meanprops 和 showmeans 参数绘制平均值。图片作者。

添加槽口

我们可以用凹口代替线来表示中位数。这可以通过添加参数notch并将其设置为 True 来实现。

#Adding the median notch to the box
red_circle = dict(markerfacecolor='red', marker='o')
plt.boxplot(x=df['DEN'], vert=False, flierprops=red_circle, 
             showmeans=True, meanprops=mean_shape, notch=True);

Matplotlib 箱线图,带有表示中值的凹口。图片作者。

在图上显示多个箱线图

有时,我们可能希望在同一个图形上创建多个箱线图。最简单的方法就是调用df.plot(),传入kind=True

#Displaying all columns in the dataframe on a single figure
df.plot(kind='box');

使用 df.plot 绘制 dataframe 中所有列的箱线图(kind='box ')

这将生成一个包含我们所有列的图,但它并不十分吸引人。此外,我们所有的测量都在不同的测量范围内。GR 的典型范围为 0 至 200 API,而 DEN 的典型范围为约 1.5 克/立方厘米至约 3 克/立方厘米。

这使得读取和识别数据中的异常值变得非常困难。为了制作具有不同 y 轴的箱线图,为了制作一个既可读又可用的图形,我们需要使用支线图。如果你想在 matplotlib 中找到更多关于支线剧情的信息,请查看我之前的视频。

首先,我们首先将异常值定义为红色下划线圆圈。

red_circle = dict(markerfacecolor='red', marker='o', markeredgecolor='white')

然后我们将 fig,axs 定义为 plt.subplots。在参数中,我们传入我们想要的 1 行,然后是列数。列的数量将等于 df.columns 的长度。最后,我们将 figsize 设置为 20 乘 10。

fig, axs = plt.subplots(1, len(df.columns), figsize=(20,10))

然后我们需要创建一个小的 for 循环,它将在我们的每个绘图轴上循环。我们在这里使用枚举函数来跟踪 I,我们的索引值。

for i, ax in enumerate(axs.flat):

接下来,我们可以通过调用ax.boxplot()并传入 df.iloc 来添加我们的 boxplot,这允许我们通过索引变量来获取列,我们通过创建方括号来做到这一点,冒号后跟逗号。这告诉 iloc 函数获取所有行,然后我们传入列索引。接下来,我们指定离群属性并传入 red_circle。

ax.boxplot(df.iloc[:,i], flierprops=red_circle)

接下来的几行允许我们设置标题和 y 刻度标签的字体大小。最后,我们呼吁plt.tight_layout以一种很好的方式来安排剧情。

#Creating subplot of each column with its own scale
red_circle = dict(markerfacecolor='red', marker='o', markeredgecolor='white')

fig, axs = plt.subplots(1, len(df.columns), figsize=(20,10))

for i, ax in enumerate(axs.flat):
    ax.boxplot(df.iloc[:,i], flierprops=red_circle)
    ax.set_title(df.columns[i], fontsize=20, fontweight='bold')
    ax.tick_params(axis='y', labelsize=14)

plt.tight_layout()

使用子图分隔箱线图,以允许不同的 y 轴刻度/数据范围。图片作者。

当我们运行细胞时,我们有一个更好看的图,我们可以阅读。每个子情节都有自己的 y 轴刻度。我们可以看到卡利、GR 和 NEU 都有大量的异常值。最后两个副曲线 RMED 和 RDEP 应该用对数来表示。

为了捕捉这些,我们可以添加一个简单的 if 语句来检查列名是否等于 RDEP 和 RMED,然后调用ax.semilogy()

red_circle = dict(markerfacecolor='red', marker='o', markeredgecolor='white')

fig, axs = plt.subplots(1, len(df.columns), figsize=(20,10))

for i, ax in enumerate(axs.flat):
    ax.boxplot(df.iloc[:,i], flierprops=red_circle)
    df.iloc[:,i]
    ax.set_title(df.columns[i], fontsize=20, fontweight='bold')
    ax.tick_params(axis='y', labelsize=14)

    #Checking if column names are equal to columns we expect to be logarithmic
    if df.columns[i] == 'RDEP' or df.columns[i] == 'RMED':
        ax.semilogy()

plt.tight_layout()

使用子图分隔箱线图,以允许不同的 y 轴刻度/数据范围。图片作者。

摘要

在本教程中,我们已经了解了如何使用 matplotlib 和 pandas 创建测井数据的基本箱线图,以及如何使用具有不同 y 轴/数据范围的多个箱线图创建单个图形。箱线图是非常有用的数据可视化工具,允许我们了解数据的范围和分布,以及识别异常数据点,也称为异常值。

这是在项目的探索性数据阶段可以使用的许多方法之一。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!*或者,您可以* 注册我的简讯 免费获取更多内容直接发送到您的收件箱。

其次,通过注册会员,你可以获得完整的媒介体验,并支持我自己和成千上万的其他作家。它每个月只花你 5 美元,你可以完全接触到所有令人惊叹的媒体文章,也有机会用你的写作赚钱。如果你用 我的链接报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

使用 Python 在 Google Slides 中创建图表

原文:https://towardsdatascience.com/creating-charts-in-google-slides-with-python-896758e9bc49?source=collection_archive---------7-----------------------

利用 Google 的 API 和 gslides 包给你的观众留下深刻印象

数据科学家遇到的一个常见问题是如何在幻灯片中以编程方式创建简单、格式优雅且带有公司品牌的可视化效果。

利用谷歌 API 和包**gslides**你可以很容易地在谷歌幻灯片中创建图表和表格,这将会给你的观众留下深刻印象,这一切都是用 Python 实现的!

无论您是希望提高演示水平的数据科学家,还是希望在幻灯片和工作表中实现手工自动化的分析师,本教程都将带您了解如何将**gslides**集成到您的工作流程中。

我们正在尝试解决的示例场景

场景 1

数据科学家使用绘图包(matplotlib、plotly、ggplot2)在 Jupyter 笔记本中进行分析。为了分享他们的成果,他们将笔记本上的一张图片复制到幻灯片中

虽然他们的分析可能很出色,但熟悉表格和幻灯片的非技术利益相关者必须调整他们的思维模式,以解释用 python 创建的非标准格式的可视化。出现的问题有:

我可以查看图表中的基础数据吗?

我们想将这些材料分享给高级利益相关者,你能根据公司的品牌指导方针格式化图表吗?

场景二

出于监控目的,数据分析师必须每月更新一组数据。他们必须从数据仓库中获取数据,导出结果,将其复制到 Google 工作表中,并更新必要的图表。

这种工作流程是高度手动和重复的,这使得工作变得单调乏味,并降低了分析师的积极性。

解决方案

创建图表和表格的数据流。作者图片

为了在 Google slides 中创建图表,我们可以使用 python 将数据从 pandas 传递到 Google Slides & Sheets API。这些 API 是做什么的?在这些平台中,您可以手动执行的大多数操作都可以通过创建请求并将其传递给适当的 API 来复制。

Google 关于幻灯片 API 请求的文档截图。作者图片

这变得复杂的地方在于,你需要熟悉许多请求,并且创建这些请求,你通常需要编写数百行的 json。为了避免直接处理复杂的 Google API 请求,我们可以使用**gslides**,一个创建和执行请求的 Google API 包装器。通过为用户配置这些请求,**glides**使用户能够通过简单的 python 命令操作 Google Sheets &幻灯片,而不是冗长的 json 请求。

gslides 中的等效 json 请求。作者图片

gslides简介

**gslides**是面向对象的,其中每个类代表 Google Sheets 或 Slides 中的一个对象。

gslides API 中的类和方法。图片来自经许可发布的g 幻灯片

  • 电子表格代表一个谷歌表单
  • 框架表示谷歌工作表中的数据范围
  • 系列 代表图表中的一个系列或多个系列
  • 图表 表示将在 google sheets 中创建然后移动到 google slides 中的图表
  • 表格 表示将在 google slides 中创建的表格
  • 演示表示一个谷歌幻灯片演示。

SpreadsheetFramePresentation类的初始化方法get()create()允许用户获取现有对象或创建新对象。

欲了解更多关于该包的信息,请参考文档此处。

设置

使用**gslides**依赖于在 Google 云平台中创建一个项目和凭证。以下是你必须遵循的步骤。

  1. 在谷歌云平台中创建一个项目,启用幻灯片&表单 API。
  2. 创建服务帐户或 OAuth 2.0 凭证。这里的关键区别是,如果你使用 OAuth 2.0,你运行的任何命令都会像你的个人谷歌帐户是创建者&编辑器一样运行。如果您使用服务帐户,域为<project>.iam.gserviceaccount.com的帐户将成为创建者&编辑者。更多关于使用服务账户利弊的评论可以在这里找到。
  3. 建立您的凭证

对于 OAuth 2.0,您将运行:

**import** **os.path**
**from** **googleapiclient.discovery** **import** build
**from** **google_auth_oauthlib.flow** **import** InstalledAppFlow
**from** **google.auth.transport.requests** **import** Request
**from** **google.oauth2.credentials** **import** Credentials

*# These scopes are read & write permissions. Necessary to run gslides*
SCOPES = ['https://www.googleapis.com/auth/presentations',
         'https://www.googleapis.com/auth/spreadsheets']

creds = **None**
*# The file token.json stores the user's access and refresh tokens, and is*
*# created automatically when the authorization flow completes for the first*
*# time.*
**if** os.path.exists('token.json'):
    creds = Credentials.from_authorized_user_file('token.json', SCOPES)
*# If there are no (valid) credentials available, let the user log in.*
**if** **not** creds **or** **not** creds.valid:
    **if** creds **and** creds.expired **and** creds.refresh_token:
        creds.refresh(Request())
    **else**:
        flow = InstalledAppFlow.from_client_secrets_file(
            '<PATH_TO_CREDS>', SCOPES)
        creds = flow.run_local_server()
    *# Save the credentials for the next run*
    **with** open('token.json', 'w') **as** token:
        token.write(creds.to_json())

对于服务帐户:

**from** **google.oauth2** **import** service_account

SCOPES = ['https://www.googleapis.com/auth/presentations',
         'https://www.googleapis.com/auth/spreadsheets']

credentials = service_account.Credentials.from_service_account_file(
    '<PATH_TO_CREDS>')

creds = credentials.with_scopes(SCOPES)

4.下载**gslides**

pip install gslides

基本用法

在最基本的用法中,**gslides**将数据从**pandas**数据框架传递到 Google Sheets,然后使用 Google Sheets 中的数据在 Sheets &幻灯片中创建图表或表格。见下面这个流程,完整的笔记本在这里。

1。初始化与 Google APIs 的连接

**import** **gslides**
**from** **gslides** **import** (
    Frame,
    Presentation,
    Spreadsheet,
    Table,
    Series, Chart
)
gslides.initialize_credentials(creds) *#BringYourOwnCredentials*

2。创建演示文稿

prs = Presentation.create(
    name = 'demo pres'
)

3。创建电子表格

spr = Spreadsheet.create(
    title = 'demo spreadsheet',
    sheet_names = ['demo sheet']
)

4。将数据载入电子表格

plt_df = *#Pandas DataFrame with Iris data*
frame = Frame.create(
    df = plt_df,
    spreadsheet_id = spr.spreadsheet_id,   
    sheet_id = sp.sheet_names['demo sheet'],
    sheet_name = 'demo sheet',
    overwrite_data = **True**
)

5。创建散点图

sc = Series.scatter()
ch = Chart(
    data = frame.data,       #Passing the data from the frame
    x_axis_column = 'sepal length (cm)',
    series = [sc],           #Passing the series object
    title = 'Demo Chart',
    x_axis_label = 'Sepal Length',
    y_axis_label = 'Petal Width',
    legend_position = 'RIGHT_LEGEND',
)

6。创建一个表格

tbl = Table(
    data = plt_df.head()
)

7。用散点图&表制作一张幻灯片

prs.add_slide(
    objects = [ch, tbl],
    layout = (1,2),             #1 row by 2 columns
    title = "Investigation into Fischer's Iris dataset",
    notes = "Data from 1936"
)

结果是这张幻灯片:

基本用法的输出。图片来自 gslides 经许可发布

使用该软件包,用户可以:

  • 创建新演示文稿
  • 创建带有图表或表格的新幻灯片
  • 删除幻灯片
  • 创建新的电子表格
  • 在电子表格中添加或删除标签
  • 将数据从熊猫数据框添加到电子表格
  • 从电子表格获取数据到熊猫数据框架
  • 模板文本到类似于 J inj a 的演示文稿中
  • 用刷新的基础数据强制更新演示文稿中的所有链接图表

可配置性

在众多可配置参数中,**gslides**的亮点在于灵活性。这种可配置性的全部细节可以在这里找到,但是看看下面什么是可行的快照。

作者图片

总结

**gslides**支持分析师在 Google Slides 中轻松创建图表&表格。基于这篇教程,希望你对**gslides**有一个很好的理解,以及如何将它应用到你的工作流程中。如有任何疑问,请务必查看此处的文档。

利用 geo pandas——爱尔兰风能数据集创建 Choropleth 地图

原文:https://towardsdatascience.com/creating-choropleth-map-using-geopandas-irish-wind-energy-dataset-58dbeff913ed?source=collection_archive---------23-----------------------

用 Python 在 choropleth 地图上表示您感兴趣的数据。

在我之前的文章 [1]中,我讨论了爱尔兰风能在电网中的渗透。在那篇文章中,我报告了代表过去几年每个国家风力涡轮机数量变化的数字。下面,我将介绍创建您自己的 choropleth 地图的步骤,以便可视化您选择的任何数据!

为了便于说明,下面的代码用于生成我在上一篇文章中报告的数字。但是,这些步骤适用于任何数据!

按照下面详述的步骤,我们将生成如下所示的 choropleth 图。这张地图根据风力涡轮机的装机容量对不同的爱尔兰郡进行了颜色编码。每个县安装的风力涡轮机的数量用圆点表示,每个圆点代表一台风力涡轮机。

爱尔兰风力涡轮机的 Choropleth 地图(图片由作者提供)

你所需要的是创建这个地图是一些关于 Python(熊猫,Matplotlib)的手,我会帮助你与 GeoPandas。

我们将生成 choropleth 图分解为以下步骤:

  1. 数据整理:

因为我在都柏林工作,研究可再生能源;我将根据涡轮机数量和容量绘制风力涡轮机安装图,您可以按照您的数据创建自己的数据。

能源数据来自 EirGrid 网站【2】。数据是 PDF 格式的。我把它转换成 CSV 文件,对它做了一点预处理,然后上传到我的 GitHub 。精选的数据非常适合我们的演示目的。

我们还需要能接触到有问题的地图。我使用了爱尔兰共和国的地图,这是我从下面的网站下载的,我也上传到了我的 GitHub 中。

2。让我们开始编码:

我知道这可能是你第一次使用 GeoPands,所以首先你需要安装它。这可以通过运行以下代码行来完成:

pip install geopandas

如果你得到了一个错误,不要惊慌,有其他方法来安装它。看看这个。

要加载有问题的 CSV 文件,请执行以下代码行:

import pandas as pd
path = 'Give it the data path'  
df = pd.read_csv(path+'Tdata.csv')
df.head() # to see how data look likes

风力涡轮机数据集

如图所示,在加载的数据集中,我们有爱尔兰每个县的装机容量涡轮机数量。现在,我们需要加载正在讨论的地图,在本例中是爱尔兰地图。

import geopandas as gpd
ROI_map= gpd.read_file(path+'IRL_adm1.shp')  #reading the map 
ROI_map.NAME_1 #you can see names of counties here

现在,我们有了一个表示我们数据的 Pandas 数据帧( df )和一个表示爱尔兰地图的 GeoPandas 数据帧( ROI_map )。我们需要做的是根据县名合并这两个数据集:

ROI_map=ROI_map.set_index('NAME_1')
df=df.set_index('County')
df2= ROI_map.join(df)
# we need to replace NaN rows with 0 since there are some counties #without any wind turbines 
df2['Installed Capacity (MW)']=df2['Installed Capacity (MW)'].fillna(value=0)
df2['No of Turbines']=df2['No of Turbines'].fillna(value=0)
df2['name1'] = df2.index
df2.head() # it is the new data frame that we created merging map and wind data sets

2。准备好剧情了吗?

为了绘制相关数据,我们使用 Python 中的 MatPlotlib 库。我根据装机容量给每个县标上了颜色。我选择绿色是因为我在谈论绿色能源。我想在这里提到的一点是,由于我们是基于装机容量来给地图着色的,所以我们需要一个颜色条来显示装机容量的范围是如何随颜色变化的,因此您还需要为颜色条定义装机容量的最小值( vmin )和最大值( vmax )。等等!我们正在谈论爱尔兰岛,所以我喜欢我的地块的脸颜色是浅蓝色(face color = ' lightsteelblue '),如果你想它是白色,你可以删除它。

import matplotlib.pyplot as plt
vmin, vmax = 0, 500 #Range of variable you use as map color (here #range of Installed Capacity (MW)
fig, ax = plt.subplots(figsize=(6,8),facecolor='lightsteelblue')
fig=df2.plot(column='Installed Capacity (MW)', cmap='YlGn', linewidth=0.8, ax=ax, edgecolor='#140656',facecolor='lightslategray',vmin=vmin, vmax=vmax,
legend=True, norm=plt.Normalize(vmin=vmin, vmax=vmax))
ax.axis('off')

向颜色栏添加图例:

ax.annotate('Installed Capacity (MW)',xy=(0.9, .65),rotation=270, xycoords='figure fraction', horizontalalignment='left', verticalalignment='top', fontsize=12, color='black')

这是你目前的计划:

爱尔兰风力装机容量的 Choropleth 地图(图片由作者提供)

3。我们可以添加县名吗?

是啊!您可以通过指定经度和纬度来指定您想要的任何内容。您可能有兴趣将县的名称添加到您的绘图中,所以让我们获取每个县的经度和纬度,并要求 Python 在此基础上添加名称。

#Getting the lan and lat here from geometry data
df2['coords']=df2['geometry'].apply(lambda x: x.representative_point().coords[:])
df2['coords']=[coords[0] for coords in df2['coords']]
#Add names of county here
for idx, row in df2.iterrows():
    plt.annotate(s=row['name1'], xy=row['coords'],
                 horizontalalignment='center', color='black',fontsize=10, fontweight='light')

爱尔兰风力装机容量的 Choropleth 地图(图片由作者提供)

有一些名称重叠,但您可以通过调整布局或更改图形的大小来避免。

4。风力涡轮机的数量呢?

当然啦!它与第 3 部分非常相似,但有一点小小的不同,不是添加名称,而是添加风力涡轮机的数量!但是,要小心,我喜欢将圆圈分布在整个县,以清楚地显示风力涡轮机的累积,因为否则,所有的圆圈将在同一点重叠,我们不会告诉有多少!,所以我只是为每个县和每个涡轮机产生了一些随机数;因此;每个县都有相同数量的圆圈和风力涡轮机。

from random import gauss 
# Add turbine numbers here
for idx, row in df2.iterrows():
    if row['No of Turbines']!=0:
        s=row['No of Turbines']
        ss=int(s)
        for i in list(range(ss)):
            z=row['No of Turbines']/1000+gauss(0, 0.1)
            DFF=plt.scatter(x=z+row['coords'][0],y=gauss(0, 0.03)+row['coords'][1],c='#ec1313',alpha=0.5)

最后,我们有:

爱尔兰风力涡轮机的 Choropleth 地图;代表风力发电装机容量和涡轮机数量(图片由作者提供)

5。停下来。我们的数据总是需要传奇!

通过以下代码向地图添加图例:

#Add legend to red circles i.e. wind turbines
plt.legend([DFF, DFF], ["Wind turbines"],loc='upper left')

我们开始吧:

爱尔兰风力涡轮机的 Choropleth 地图;代表风力发电装机容量和涡轮机数量(图片由作者提供)

6。我可以保存我的地图吗?

您可以通过以下代码保存地图:

import os 
path2='your path here!'
filepath = os.path.join(path2,'mymap.jpg')
chart = fig.get_figure()
chart.savefig(filepath, dpi=300)

6。再见!

我希望你喜欢这篇文章,我希望它能帮助你的学习或工作。

你可以在我的 GitHub 上访问代码和数据。

值得注意的是,我受到了这两篇关于走向数据科学的文章[3,4]的启发。

确认

我要感谢 UCD 能源研究所和 ESIPP 集团对我的支持。另外,我推荐你看看我的同事们在这个研究所的有趣作品。

参考

[1]:绿色如爱尔兰:爱尔兰风能 Choropleth 地图,走向数据科学;2021 年 2 月 23 日https://towards data science . com/green-like-Ireland-choropleth-map-of-Irish-wind-energy-26603106 fe3e?source=social.tw

[2]: TSO 联网可再生能源—年装机容量,EirGrid,2021 年 2 月。http://www . eirgridgroup . com/site-files/library/EirGrid/TSO-Connected-Renewable-generation . pdf

[3]:用 Python 创建 Choropleth 地图的完整指南,走向数据科学;2020 年 10 月 4 日https://towards data science . com/a-complete-guide-to-creating-choropleth-maps-in-python-728 ee 2949 db4

【4】:我们来做个地图吧!利用 Geopandas、pandas 和 Matplotlib 制作 Choropleth 图;2018 年 6 月 25 日。https://towards data science . com/let-make-a-map-using-geo pandas-pandas-and-matplotlib-to-make-a-chloroleth-map-dddc 31 c 1983d

在 MongoDB 中创建云数据库

原文:https://towardsdatascience.com/creating-cloud-database-in-mongodb-e941739a9e61?source=collection_archive---------53-----------------------

如何使用 MongoDB Atlas 创建免费的云 NoSQL 数据库

在 Unsplash 上由 Daniel Páscoa 拍照

NoSQL 数据库近年来大受欢迎。NoSQL 数据库提供了更多的灵活性,而不是将所有内容存储在行和列值中。有相当多的面向文档的 NoSQL 数据库可用,如 AWS SimpleDB、MongoDB 等。MongoDB 提供了比其他 NoSQL 云数据库更多的灵活性和操作性。这将是一系列文章,包含如何为云数据库创建 MongoDB 集群,如何创建集合,以及通过 MongoDB compass (GUI)或 Python (pyMongo)执行创建、读取、更新和删除(CRUD)操作的信息。此外,以后的文章还将包含一些高级操作。如果您已经知道如何创建一个 MongoDB 集群并通过 MongoDB compass GUI 连接到它,那么您可以忽略这篇文章,转到下一篇文章。

首先,你需要在 MongoDB 中创建一个帐户,它是完全免费的,不需要信用卡信息就可以获得 MongoDB atlas。您可以通过这里报名。MongoDB Atlas 提供了云数据库。注册后,您可以选择想要的集群。有三个选项可用,我们将使用的是共享集群,因为它非常适合小型项目和学习目的,而且是免费的。顾名思义,它将是一个共享集群,而其他集群提供更高级和专用的服务。

选择共享集群

下一步是选择云提供商,有三个选项——AWS、Google Cloud 和微软 Azure。此外,基于云提供商,您可以选择您的集群的区域。我选择 AWS 和地区为新加坡。

选择云提供商和地区

现在,下一步将是选择群集层,有多个选项可用,但由于我们更多地将数据库用作学习项目,因此将继续使用 M0 沙盒,该沙盒提供共享 RAM 和 vCPU 以及 512 MB 存储。我们还可以在部署后随时纵向扩展集群层。

选择集群层

因为我们使用的是免费的共享集群,所以没有选择任何备份选项,我们可以根据需要更改集群名称。请记住,集群只能命名一次,之后就不能再更改了。

集群名称

完成上述步骤后,MongoDB 将继续供应和引导您的集群。部署群集只需几分钟。

集群创建

创建并部署集群后,您可以看到如下所示的状态:

创建的集群

现在,您可以选择“连接”选项来设置连接配置。您可以选择设备的 IP 地址或允许从任何地方访问。另外,您需要设置一个用户名和密码来访问您的 MongoDB 数据库。

连接设置

接下来,您需要选择一种连接方法,我通过 MongoDB compass 选择了,您也可以选择 MongoDB shell。MongoDB Compass 基本上是一个更容易操作的图形用户界面。但它的限制很少,看到集合并熟悉 MongoDB 很好,但它缺乏一些可以通过 shell 命令或 python 脚本完成的高级功能。

获取 MongoDB 指南针

如果您的机器上没有安装 MongoDB compass,您可以下载并安装该应用程序。在您安装了 MongoDB compass 并打开应用程序之后,您将看到一个字段,您可以在其中粘贴您将在上面的阶段中获得的连接字符串。

MongoDB 指南针 GUI

输入密码并完成身份验证后,您将会看到如下内容。

MongoDB 集群

如果您按照目前为止的步骤,一直到达最后一个图像,这意味着现在您可以通过 MongoDB compass 访问您的 MongoDB 集群。现在,您可以创建多个数据库,在每个数据库中,您可以创建多个集合。所有这些都将在下一篇文章中讨论。

希望本文能帮助您创建一个免费的 MongoDB 集群。

在 SQL 查询中创建条件语句

原文:https://towardsdatascience.com/creating-conditional-statements-in-sql-queries-a25339c4f44d?source=collection_archive---------9-----------------------

IF、CASE 和 IFNULL 语句快速指南

活动发起人在 Unsplash 上的照片

尽管 SQL 不是一种通用语言,但它包含了与其他语言结构相似的条件语句。经典的 IF 和 CASE 语句允许在查询级别更改数据,而不是在另一个环境(如工作表或数据框)中修改它们。

虽然这些语句都不难掌握,特别是在以前接触过编程语言的情况下,但是它们提供了修改查询结果的强大功能和灵活性。为了演示如何使用这些语句,将创建一个简单的表,详细说明销售 ID、周、部门和收入。

CREATE TABLE SALES_2021(
sales_id INTEGER PRIMARY KEY AUTOINCREMENT,
week INTEGER,
department VARCHAR(255),
revenue INTEGER
);

IF 语句

SQL 中最基本形式的 IF 语句与大多数工作表软件中的条件语句非常相似。

IF(*condition*, True, False) from *table*;

IF 语句简单地引入一些条件,然后根据条件是真还是假返回一个结果。当条件为真时,返回第二个参数,当条件为假时,返回第三个参数。注意,代替 IF 语句,一些实现使用了 IIF 语句,但是它的操作完全相同。

举一个更具体的例子,假设一个利益相关者请求对每周是否达到 5000 美元收入的部门目标进行细分。他们不一定关心该部门的收入。他们只关心是否达到了目标。

此外,他们不想要一个经过筛选的实现目标的周列表。他们想要所有 52 周的完整列表以及他们的收入目标状态。

SELECT department, week, 
IF(revenue > 5000, 'Met', 'Not Met') as 'Goal' 
FROM SALES_2021;

SELECT 语句按预期返回部门和星期,但还包括一个 IF 语句。第一个参数引入了收入是否大于$5,000 的条件。当实现收入目标时,返回第二个参数“已达到”,当未达到时返回“未达到”。为了使结果查询更具可读性,在 IF 语句中添加了一个别名。

查询的前五个结果

结果查询返回部门、周以及目标是否达到,如涉众所指定的。

案例陈述

虽然 IF 语句提供了一个基本的条件语句,但它不支持多个条件。在这种情况下,必须使用一个 CASE 语句。

CASE *field*
WHEN *expression_1* THEN *statement_1*
WHEN *expression_2* THEN *statement_2*
ELSE *statement_3*
END
FROM *table*;

案例从指定表中的字段开始。WHEN…THEN 语句随后创建一个特定的条件和返回语句。当表达式 _1 为真时,则返回语句 _1 。这同样适用于 expression_2 和 statement_2

如果没有一种情况得到满足,可选的 ELSE 语句(有时称为默认情况)将返回 statement_3 。请注意,CASE 语句必须以结尾结束。

假设一个涉众喜欢用部门代码而不是部门名称来查看数据。在这种情况下,他们希望看到法律作为腿,财产作为亲,管理作为人。

SELECT week, revenue, 
CASE department 
WHEN 'Legal' THEN 'LEG' 
WHEN 'Property' THEN 'PRO' 
WHEN 'Management' THEN 'MAN' 
END as 'department code' 
FROM SALES_2021;

考虑到这些查询会很快变得复杂,通常建议使用可选的空格来使其更具可读性。

SELECT week, revenue, 
    CASE department 
        WHEN 'Legal' THEN 'LEG' 
        WHEN 'Property' THEN 'PRO' 
        WHEN 'Management' THEN 'MAN' 
    END as 'department code' 
FROM SALES_2021;

注意,CASE 语句指定了 department 字段。在下面的 WHEN…THEN 子句中,该条件因此也适用于 department 字段中的条目。当部门等于“合法”时,则返回“LEG”。同样适用于“财产”和“亲”,“管理”和“人”。END 关闭 CASE 语句,并包含一个别名以使结果更具可读性。

查询的截断结果

因此,查询返回部门代码,而不是部门名称。

虽然这个例子为具有精确等式的数据提供了一个简单的例子,但是假设一个利益相关者想要将一个部门的收入分为高、中或低。

SELECT week, revenue, 
    CASE 
        WHEN revenue > 6000 THEN 'High' 
        WHEN revenue < 3000 THEN 'Low' 
        ELSE 'Medium' 
    END as 'Revenue Rating' 
FROM SALES_2021;

该查询遵循相同的基本模式,只是 CASE 语句没有明确声明它适用于收入字段。相反,在每个 WHEN…THEN…语句中,该表达式都包含对 revenue 字段的显式比较。

在这种情况下,当收入高于 6,000 美元时,查询返回“高”,低于 3,000 美元时,查询返回“低”。ELSE 将任何其他数量作为“中等”返回,因为它应该在$3,000 和$6,000 之间,包括这两个值。

查询的前五个结果

IFNULL 语句

当数据中出现空值时,数据专业人员通常会很担心。它们通常代表在数据清理时必须解决的不完整信息或错误。

考虑到对确认空值的高需求,SQL 提供了 IFNULL 语句来标记出现的空值。

IFNULL(*field*, *expression*) FROM *table*;

IFNULL 有两个参数。第一个参数指定表中的字段,如果条目为空,第二个参数给出返回值。

假设添加了一个新部门,Tax,但是其数据的初始条目省略了名称,使其为空。一个简单的 IFNULL 语句将在查询数据时填充这些信息。

SELECT week, IFNULL(department, 'Tax') as 'department', revenue 
FROM SALES_2021;

SELECT 语句包含 IFNULL 函数,该函数确定部门字段中的条目是否为空值。如果是,则返回“税”。此外,还添加了一个别名,以提高可读性。

查询的截断结果

最后一行最初省略了任何部门,但是查询添加了税务部门,使得数据清理过程更加简单。

结论

SQL 使得向查询添加条件语句变得很简单。有了它们,数据专业人员可以开始将逻辑注入到他们的查询中。它们构成了增加复杂性的基础,允许更复杂的技术来改变和查看数据库中的信息。

使用 Argo 创建容器化的工作流

原文:https://towardsdatascience.com/creating-containerized-workflows-with-argo-ec1011b04370?source=collection_archive---------9-----------------------

Kubernetes 上的 Argo 工作流入门

探索 Argo 工作流的核心概念

在的上一篇文章中,我探索了 Kubeflow 管道,并完成了创建和执行一个简单的机器学习管道的过程。在本文中,我将仔细研究 Argo,这是一个开源的工作流编排引擎,它被用作 Kubeflow 管道的默认编排平台。

建立 Kubernetes 集群

为了开始玩 Argo,我们首先需要一个正在运行的 Kubernetes 集群。我将使用 EKS,AWS 上的托管 Kubernetes 服务,并通过所需的步骤让 Argo 在 EKS 上运行。只要部署了 Argo 并且拥有在集群上运行工作流所需的权限,任何 Kubernetes 集群都可以工作。

开始使用 EKS 最简单的方法是使用 eksctl 命令行工具。安装 eksctl 的说明可以在这里找到:https://github.com/weaveworks/eksctl/blob/main/README.md

一旦安装了 eksctl,我们将通过运行以下命令来创建 Kubernetes 集群:

eksctl create cluster

注意:上面的命令创建了 AWS 资源,这将在您的账户上产生费用。默认情况下,eksctl create cluster命令创建一个包含 2 个 m5.large 类型 EC2 实例的 Kubernetes 集群,在撰写本文时,每个实例的成本约为每小时 0.10 美元。

此命令可能需要 15–20 分钟来完成群集资源调配。一旦完成,我们要做的第一件事就是创建一个命名空间来存放我们的 Argo 资源。我们将使用kubectl来做到这一点:

kubectl create namespace argo

接下来,我们将从 Argo GitHub 库下载 Argo 安装清单:

wget [https://raw.githubusercontent.com/argoproj/argo-workflows/stable/manifests/install.yaml](https://raw.githubusercontent.com/argoproj/argo-workflows/master/manifests/install.yaml) .

这将下载一个名为 install.yaml 的 YAML 清单文件,它描述了我们启动和运行 Argo 所需的所有 Kubernetes 资源。

为了访问 Argo 服务器用户界面,我们必须对这个文件做一些修改。

  1. argo-server 服务更新为负载平衡器类型。这将在 AWS 中提供一个网络负载平衡器,将请求路由到 argo-server 服务。生成的资源定义应该如下所示:

2.更新 argo-server 部署,添加一个名为 BASE_HREF 的环境变量,其值为“/”。结果应该如下所示(为简洁起见,资源定义被截断):

完成这些修改后,我们可以创建清单中定义的资源:

kubectl apply -n argo -f install.yaml

接下来,我们需要创建一个入口资源:

最后,为了让 Argo 能够访问其他 Kubernetes 资源,我们需要为 Argo 服务帐户分配一个角色。在实际的生产集群中,我们希望将这个服务帐户分配给一个具有特定有限权限的角色,但是现在,我们只授予这个帐户 admin 访问权限。我们可以使用以下命令来实现这一点:

kubectl -n argo create rolebinding default-admin --clusterrole=admin --serviceaccount=argo:default

这就是我们开始之前需要完成的所有设置。现在,我们将通过运行以下命令来获取 Argo 服务器 UI 的公共 URL:

kubectl get svc argo-server -n argo

该命令将在 EXTERNAL-IP 列中返回公共 URL。应该以. elb . Amazon AWS . com结尾

现在打开浏览器,导航到:https://{ YOUR _ EXTERNAL _ IP }:2746

注意:如果你在 MacOS 上使用 Chrome,并且在导航到 Argo 服务器 UI 时很难绕过浏览器发出的安全警告,Chrome 中有一个隐藏的解决方法:只需单击浏览器窗口中的任意位置以确保窗口处于焦点状态,然后键入this insural。有关此变通办法的更多详细信息,请参见这是不安全的——绕过谷歌浏览器的“您的连接不是私人的”警告

如果一切正常,您应该会看到一个 Argo 服务器登录页面,如下所示:

Argo 服务器用户界面登录页面

执行您的第一个工作流程

设置完成后,让我们执行 Argo 的第一个工作流。

导航至工作流(这是侧边栏中的顶部图标)> 提交新工作流>使用完整工作流选项编辑

这将打开工作流创建体验,其中包括一个填充了基本工作流 YAML 清单的文本编辑器,以及工作流参数和元数据的附加选项卡。

Argo 工作流创建

让我们用一个运行如下所示的 Whalesay 容器的简单工作流来替换这个默认工作流清单,然后单击 Create 来运行工作流:

一旦您开始工作流程,您将看到一个工作流程图,它将随着工作流程的进展而更新(在这种情况下,它只是一个单独的步骤)。在此页面中,您将能够查看工作流的详细信息、输入、输出和日志。在我们的准系统 Hello World 工作流程中,这里没有太多可看的,但是你可以导航到主日志来确认 Whalesay ASCII 艺术被记录。

简单的 Argo 工作流程图

了解工作流清单

现在我们知道了如何执行工作流,让我们仔细看看我们用来定义工作流的 YAML 清单。

[计]元数据

清单的前几行定义了工作流元数据,特别是 generateName 字段,它将与一个随机生成的字符串组合起来形成我们工作流的名称(我们也可以使用 name 字段来显式定义名称,但是这个名称必须是唯一的),以及 namespace 字段,它定义了工作流将在其中执行的 Kubernetes 名称空间。

工作流规范

清单的其余部分定义了工作流规范,这是定义实际工作流逻辑的地方。在上例中,工作流规范有两个顶级字段:

  • 入口点:指定首先执行的模板。
  • 模板:定义工作流程中使用的所有模板。正如我们将很快看到的,模板在 Argo 中是一个加载的术语,但在这里模板只是表示工作流执行的一个单元。在我们的 Whalesay 工作流中,我们只有一个名为 whalesay 的类型为的容器模板。由于这个模板定义了一个要执行的容器,我们指定了要使用的容器图像、要执行的命令和要传入的参数。

创建多步骤工作流

现在让我们介绍一个更复杂的工作流,它按顺序执行几个不同的步骤。这个工作流将接受 2 个参数、一个称呼和一个用户名,它将通过使用提供的参数执行 Whalesay 容器来创建一个问候消息来结束。

虽然我们可以很容易地用 Whalesay 容器来实现这一点,但是为了展示 Argo 提供的其他一些特性,我们将采取一种更迂回的方法。

这是我们新工作流程的 YAML 清单:

让我们来分解一下:

  • 您会注意到的第一个区别是在第 6 行添加了参数字段。这是我们定义将被传递到我们的工作流中的称呼用户名参数的地方。
  • 这个工作流中定义的第一个模板在第 14 行。这个模板名为问候语,接受名为问候语的参数,类型为 Script。脚本模板类似于容器模板,因为它们需要容器图像和命令;然而,脚本模板允许我们传入一个内联脚本来在容器上执行。该模板执行一个简单的 Python 脚本,该脚本检索 salutation 参数的值,然后将其打印出来。
  • 下一个模板叫做用户,也是脚本类型。这个模板就像 salutation 模板一样,只是这个模板使用了一个 shell 脚本而不是 Python 脚本(这里没有特别的理由不使用 Python;这只是为了说明我们并不局限于 Python 作为我们的脚本语言)。
  • 第三个模板与我们之前使用的 Whalesay 容器模板相同,只是现在它接受两个参数,问候语用户名,并使用这些参数创建问候语。
  • 第四个模板是一个步骤模板。步骤模板允许我们将一系列其他模板链接在一起,创建一个多步骤工作流,其中一个模板的输出可以用作另一个模板的输入。第一步使用问候语模板并传入工作流参数问候语,第二步使用用户模板并传入工作流参数用户名,最终模板使用 whalesay 模板并传入前两步的输出。

以下是此工作流程的工作流程图:

多步骤工作流程图

注意:如果你执行了这个工作流程(或者只是仔细看了一下这个图),你可能已经注意到获取标题获取问候步骤是并行执行的,然后在两个步骤都完成之后,再运行步骤。这是因为步骤模板实际上接受步骤列表的列表。内部列表中的步骤将并行运行,外部列表中的步骤将按顺序运行。例如,上面工作流的列表结构如下所示:

[[get-title, get-greeting], [whalesay]]

这就是为什么 get-titleget-greeting 并行运行,而 whalesay 在两者完成后运行。

重用工作流步骤

工作流编排平台最重要的特性之一是能够跨多个工作流共享常用步骤。这允许平台的用户通过使用其他用户已经实施的通用步骤库来快速开始创建工作流。例如,您可以为常见的数据转换或与外部服务的集成创建可重用的步骤。

Argo 中表示可重用步骤(或一组步骤)的结构称为工作流模板。这不要与我们之前在定义工作流 YAML 清单时讨论的模板相混淆。为清楚起见,区别如下:

  • 模板:表示工作流中的单个执行单元。有许多不同类型的模板,包括容器脚本步骤
  • 工作流模板:保存在集群中的工作流定义,可以作为独立工作流或任何其他工作流的一部分执行。

让我们创建一个工作流模板来看看它是如何工作的。我们的工作流模板将是一个随机数生成器,它接受最小值和最大值,并返回指定范围内的随机整数。

Argo 服务器 UI 中的工作流模板选项卡是我们可以查看和创建工作流模板的地方。

Argo 用户界面-工作流模板

创建工作流模板与创建工作流非常相似,只是当我们创建工作流模板时,它会被保存以供以后使用,而不是像工作流那样立即执行。

以下是我们将使用的工作流模板的 YAML 清单:

工作流模板清单

正如您所看到的,这个清单就像我们之前创建的工作流清单一样:它接受两个参数, minmax ,并且有一个 Python 脚本模板,该模板在指定的范围内生成一个随机数。

创建此工作流模板后,我们将能够从 UI 中的“工作流模板”选项卡查看它,并通过选择它并单击提交将其作为独立工作流提交

将工作流模板作为独立工作流提交

我们也可以在其他工作流中使用此工作流模板。让我们看看这是如何工作的。我们将返回工作流选项卡,选择提交新工作流,然后输入以下 YAML 清单:

这个工作流很像我们已经讨论过的多步骤工作流,只是这次步骤模板不仅仅是将在这个工作流中直接定义的模板链接在一起。步骤模板中的第一步(上面的第 19 行)使用templateRef字段而不是template字段来引用工作流模板中定义的模板。在这个特殊的例子中,我们引用了在random-number-generator工作流模板中定义的generator模板。

如果这仍然有点混乱,下面的图表说明了本例中工作流、工作流模板和模板之间的关系:

当我们执行这个工作流时,call-random-number-generator步骤将像它是一个直接在工作流中定义的模板一样运行,而实际上它的实现被封装在random-number-generator工作流模板中。

从工作流中引用工作流模板

这意味着我们可以创建许多其他工作流(或其他工作流模板)来使用该功能,而无需考虑其实现的细节,如果我们需要修改该功能(例如,当前随机范围不包括 max 值,这可能是也可能不是期望的行为;或者,我们可能希望将它重构到一个容器映像中,而不是一个内联脚本中,以便更容易地测试该功能),我们可以在工作流模板中这样做,因为我们知道所有的消费者都将开始使用这些修改,而无需在他们端做任何额外的工作。

结论

在本文中,我们看到了如何通过创建几个简单的工作流来开始使用 Argo 工作流。我们研究了如何在工作流中的多个模板之间传递参数,以及如何使用工作流模板封装共享逻辑。

虽然我们在这里探索的例子非常简单,但是这些相同的核心概念可以用来在 Kubernetes 上构建和执行强大的容器化工作流,如果您决定继续探索 Argo 必须提供的其他功能,它们将成为一个强大的基础。

你可以在【https://github.com/gnovack/argo-workflows-getting-started】的Argo-workflows-getting-started库中找到我们创建的所有 YAML 清单

参考资料:

  • https://argoproj.github.io/argo-workflows/quick-start/
  • https://www.eksworkshop.com/advanced/410_batch/

感谢阅读。如有任何问题或意见,请随时联系我们。

从头开始创建卷积神经网络

原文:https://towardsdatascience.com/creating-convolutional-neural-network-from-scratch-d3a8389dfb80?source=collection_archive---------16-----------------------

在 Graviti 数据平台上使用 CNN 建立图像分类模型

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

图像分类基本上帮助我们将图像分类到不同的标签中。这就像将不同的图像放入它们所属的桶中。例如,被训练来识别猫和狗的图像的模型将有助于分别分离不同的猫和狗的图像。有多种深度学习框架,如 Tensorflow、Keras、Theano 等,可用于创建图像分类模型。今天我们将使用 Keras 和 Tensorflow 从头开始创建一个图像分类模型。

用于创建图像的相关建模可以使用 CNN 来完成。卷积神经网络主要用于图像相关的建模。它是执行图像分类、图像检测、图像分割等的最简单的方法之一。它包含不同类型的卷积层,有助于使用不同大小的内核过滤掉图像中最重要的特征。一些最重要的层是:

  1. Conv2D

它用于创建卷积核,卷积核与输入层卷积以产生输出张量。

2。MaxPooling2D

这是一种缩减采样技术,根据池大小取最大值。

3.展平

它使输入变平并创建一维输出。

有多个超参数可以用来相应地提高模型性能。这些超参数可以包括神经元的数量、内核大小、池大小、激活函数等。

在本文中,我们将从头开始使用 CNN 创建一个网络。我将向您展示如何从在线数据源加载数据,预处理数据并为建模做好准备,最后设计模型架构。

让我们开始吧…

安装所需的库

我们将从安装所有需要的库开始。我们将安装 Keras、TensorFlow,还将安装用于加载数据集的 TensorBay (在 Graviti 数据平台上的 SDK)。下面给出的命令可以做到这一点。

!pip install tensorflow
!pip install tensorbay
!pip install keras

导入所需的库

在这一步中,我们将导入所有必需的库和函数来加载数据、预处理数据并创建模型。

# Library imports
from tensorbay import GAS
from PIL import Image
import matplotlib.pyplot as plt
from tensorbay.dataset import Data, Dataset
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.image import imread
import cv2
import random
from os import listdir
from sklearn.preprocessing import LabelBinarizer
from keras.preprocessing import image
from keras.preprocessing.image import img_to_array, array_to_img
from tensorflow.keras.optimizers import Adam
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Activation, Flatten, Dropout, Dense
from sklearn.model_selection import train_test_split

加载数据集

这是第一步,我们将从 TensorBay 加载数据。为了从 TensorBay 下载数据集,我们需要创建一个帐户,并派生出一个我们想要处理的数据集,它包含大量不同的图像数据集。为了在我们的 Jupyter 笔记本中加载数据集,我们需要有 TensorBay 的访问密钥,我们可以从我们的帐户中的开发者工具下载该密钥。

gas = GAS("<Your Key>")
dataset = Dataset("Flower17–1", gas)
segment = dataset[1]

对于这篇文章,我使用的是 Flower 17 数据集,你可以看到我已经用 TensorBay 加载了它。

预处理数据集

在这一步,我们将预处理数据,并为建模做好准备。我们将从创建图像和标签列表并向其中加载数据开始。

image_list, label_list = [], []
for data in segment:
with data.open() as fp:
image_list.append(img_to_array(Image.open(fp).resize((500, 500))))
label_list.append(data.label.classification.category)

接下来,让我们直观地看到这个数据集中的类的数量。

# Visualize the number of classes count
label_counts = pd.DataFrame(label_list).value_counts()
label_counts

数据标签(来源:作者)

接下来,我们将分割数据集,对其进行规范化,并对标签进行二值化。

# Splitting dataset
x_train, x_test, y_train, y_test = train_test_split(image_list, label_list, test_size=0.2, random_state = 10)
# Normalize and reshape data
x_train = np.array(x_train, dtype=np.float16) / 225.0
x_train = x_train.reshape( -1,500,500,3)
x_test = np.array(x_test, dtype=np.float16) / 225.0
x_test = x_test.reshape( -1,500,500,3)
# Label binarizing
lb = LabelBinarizer()
y_train = lb.fit_transform(y_train)
y_test = lb.fit_transform(y_test)
print(lb.classes_)

标签二进制化(来源:作者)

创建模型

这是最后一步,我们将创建模型架构,编译模型并训练它。在创建模型架构之前,让我们将训练数据分为训练和验证。

# Splitting the training data set into training and validation data sets
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size = 0.2)
# Building model architecture
model = Sequential()
model.add(Conv2D(8, (3, 3), padding="same",input_shape=(500,500,3), activation="relu"))
model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Conv2D(16, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(32, activation="relu"))
model.add(Dense(num_classes, activation="softmax"))
model.summary()

模型架构(来源:作者)

# Compiling model
model.compile(loss = 'categorical_crossentropy', optimizer = Adam(0.0005),metrics=['accuracy'])
# Training the model
epochs = 20
batch_size = 128
history = model.fit(x_train, y_train, batch_size = batch_size, epochs = epochs, validation_data = (x_val, y_val))

培训(来源:作者)

正如您在上面看到的,我们已经使用一些超参数创建并训练了模型,模型精度不是很好,但您可以随时调整超参数以提高性能。我们也可以使用下面给出的命令保存模型。

# Saving model
model.save("/content/flower_species.h5")
Let's visualize the model training and loss history.
#Plot the training history
plt.figure(figsize=(12, 5))
plt.plot(history.history['accuracy'], color='r')
plt.plot(history.history['val_accuracy'], color='b')
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend(['train', 'val'])
plt.show()

准确性(来源:作者)

#Plot the loss history
plt.figure(figsize=(12, 5))
plt.plot(history.history['loss'], color='r')
plt.plot(history.history['val_loss'], color='b')
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.legend(['train', 'val'])
plt.show()

损失(来源:作者)

最后,让我们也使用该模型创建一些预测。

# Storing predictions
y_pred = model.predict(x_test)
Let's verify one of the predictions.
# Plotting image to compare
img = array_to_img(x_test[4])
img

花卉图像(来源:作者)

# Finding max value from prediction list and comparing original value vs predicted
labels = lb.classes_
print(labels)
print("Originally : ",labels[np.argmax(y_test[4])])
print("Predicted : ",labels[np.argmax(y_pred[4])])

预测(来源:作者)

继续,使用不同的数据集尝试这种方法,并按照本文轻松创建 CNN 模型。如果您发现任何困难,请在回复部分告诉我。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的LinkedIn 个人资料 。可以查看我的*Github简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 阅读我写过的与数据科学相关的不同文章。**

在 TensorFlow 2 中使用 Lambda 层创建自定义激活函数

原文:https://towardsdatascience.com/creating-custom-activation-functions-with-lambda-layers-in-tensorflow-691398b8a52d?source=collection_archive---------17-----------------------

学习在 TensorFlow 2 中使用 lambda 层创建一个简单的自定义 ReLU 激活函数

之前我们已经看到了如何创建自定义损失函数— 使用 TensorFlow 2 创建自定义损失函数

自定义 ReLU 函数(来源:图片由作者创建)

简介

在本文中,我们看看如何创建自定义激活函数。虽然 TensorFlow 已经包含了一系列内置的激活函数,但仍有方法可以创建您自己的自定义激活函数或编辑现有的激活函数。

ReLU(整流线性单元)仍然是任何神经网络结构的隐藏层中最常用的激活函数。ReLU 也可以表示为函数 f(x ),其中,

f(x) = 0,当 x<0,

and, f(x) = x, when x ≥ 0.

Thus the function takes into consideration only the positive part, and is written as,

f(x)= max(0,x)

或者在代码表示中,

**if input > 0:
   return input
else:
   return 0**

但是这个 ReLU 函数是预定义的。如果我们想自定义这个函数或者创建自己的 ReLU 激活怎么办?在 TensorFlow 中有一个非常简单的方法来做到这一点——我们只需使用 Lambda 层

ReLU 和 GeLU 激活功能(资料来源:由 Ringdongdang —自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=95947821)

如何使用 lambda 图层?

**tf.keras.layers.Lambda(lambda x: tf.abs(x))**

Lambda 只是另一个可以在 TensorFlow 中直接调用的层。在 lambda 层中,首先指定参数。在上面的代码片段中,这个值是‘x’(λx)。在这种情况下,我们希望找到 x 的绝对值,所以我们使用 tf.abs(x)。所以如果 x 的值为-1,这个 lambda 层会将 x 的值更改为 1。

如何使用 lambda 图层创建自定义 ReLU?

**def custom_relu(x):
    return K.maximum(0.0,x)****model = tf.keras.models.Sequential([
     tf.keras.layers.Flatten(input_shape=(128,128)),
     tf.keras.layers.Dense(512),
     tf.keras.layers.Lambda(custom_relu),
     tf.keras.layers.Dense(5, activation = 'softmax')
])**

上面的代码片段展示了如何在 TensorFlow 模型中实现自定义 ReLU。我们创建一个函数 custom_relu,并返回最大值 0 或 x(与 relu 函数一样)。

在下面的顺序模型中,在密集层之后,我们创建一个 Lambda 层,并在自定义激活函数中传递它。但是这段代码仍然没有做任何与 ReLU 激活函数不同的事情。

当我们开始摆弄自定义函数的返回值时,乐趣就开始了。假设我们取 0.5 和 x 的最大值,而不是 0 和 x 的最大值。然后可以根据需要更改这些值。

def custom _ relu(x):
return k . maximum(0.5,x)

**def custom_relu(x):
    return K.maximum(0.5,x)****model = tf.keras.models.Sequential([
     tf.keras.layers.Flatten(input_shape=(128,128)),
     tf.keras.layers.Dense(512),
     tf.keras.layers.Lambda(custom_relu),
     tf.keras.layers.Dense(5, activation = 'softmax')
])**

在 mnist 数据集上使用 lambda 激活的示例

***#using absolute value (Lambda layer example 1)*****import tensorflow as tf
from tensorflow.keras import backend as K****mnist = tf.keras.datasets.mnist****(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0****model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128),
  tf.keras.layers.Lambda(lambda x: tf.abs(x)), 
  tf.keras.layers.Dense(10, activation='softmax')
])****model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])****model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**

用 mnist 数据集上的绝对值替换 ReLU 激活给出了 97.384%的测试准确度。

***#using custom ReLU activation (Lambda layer example 2)*****import tensorflow as tf
from tensorflow.keras import backend as K****mnist = tf.keras.datasets.mnist****(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0****def my_relu(x):
    return K.maximum(-0.1, x)****model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128),
    tf.keras.layers.Lambda(my_relu), 
    tf.keras.layers.Dense(10, activation='softmax')
])****model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])****model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**

在 mnist 数据集上,用定制的 ReLU 激活替换 ReLU 激活,取最大值-0.1 或 x,给出 97.778%的测试准确度。

结论

尽管 lambda 层使用起来非常简单,但它们有许多限制。在下一篇文章中,我将讲述如何在 TensorFlow 中创建完全自定义的层,这些层也是可训练的。

在 Python 中创建自定义列表

原文:https://towardsdatascience.com/creating-custom-lists-in-python-4f413b65282a?source=collection_archive---------13-----------------------

探索 OOP 基础,尝试 Python 中的自定义数据类型

克里斯里德在 Unsplash 上的照片

在本文中,我们将了解面向对象编程的基础,以及如何使用 Python 类来创建我们自己的定制列表。我们将在不使用任何包的情况下这样做(没有导入语句!).

假设我们想要创建一个新的数据容器类型,它将充当一个列表(例如,我们可以对它进行索引和切片),但同时可以包含来自多个来源的数据,我们可以像在字典中一样提取这些数据。

比方说,我们有一个列表字典:

d ={‘key1’ : [‘val11’, ‘val12’, ‘val13’],
    ‘key2’ : [‘val21’, ‘val22’, ‘val23’],
    ‘key3’ : [‘val31’, ‘val32’, ‘val33’]}

但是我们希望能够轻松地处理 d.values()中的所有列表,就像它是一个大列表一样:

l = [‘val11’, ‘val12’, ‘val13’,
     ‘val21’, ‘val22’, ‘val23’,
     ‘val31’, ‘val32’, ‘val33’]

但同时,我们不想失去字典的键值绑定。想象一个具有这些特征的物体:

作者截图

因此,它是一个充当列表的对象,但在后台为每个元素保留键。姑且称之为 dinx

首先,我们知道要初始化这个对象,我们需要一个列表字典。让我们也允许元组,并说它们将表示静态元素,如果我们改变 dinx 'list ',它们将不会改变。因此,我们需要断言输入(姑且称之为 comp,【components)是一个字典,并且包含列表或元组。后者可以用 isinstance 第二个自变量中的【list,tuple】(list,tuple) 来实现。我们还应该在字典键中只允许字符串,以避免在调用数字索引时产生混淆。

我们将把 comp 赋值给 self,并加上一个下划线前缀,表示它是供类内部使用的。

作者截图

我们还需要定义一个函数来获得一个映射变量,我们可以用它来获得字典的列表表示中元素的顺序,我们将调用 _comp_map (稍后会用到):

作者截图

所以,自我。_comp_map 看起来像这样:

[(‘key1’, ‘val11’),
 (‘key1’, ‘val12’),
 (‘key1’, ‘val13’),
 (‘key2’, ‘val21’),
 (‘key2’, ‘val22’),
 (‘key2’, ‘val23’),
 (‘key3’, ‘val31’),
 (‘key3’, ‘val32’),
 (‘key3’, ‘val33’)]

这已经是一个键-值元组的列表,但是我们想让它看起来更漂亮。

我们现在需要做的是编写一个 dinxdunder 方法,名为 repr ,它会在我们每次调用时显示 dinx 的表示。因为我们想让我们的 dinx 在调用时看起来像一个列表,我们将从 _sum_lists_getall 方法开始,我们可以用它们来展平 _comp 中的列表字典。

作者截图

然后我们可以使用 repr 中的 _getall 输出来指定当我们在控制台中调用 dinx 时它的样子:

作者截图

现在,我们可以初始化并调用我们的 dinx:

作者截图

索引和切片

太好了!让我们实现通过索引和切片调用值的能力。这个想法是我们想要结合字典和列表索引。所以,假设上面例子中的一个项 l[0]应该是一个 dinx(1) ,即有一个值 1 和一个键‘A’。一个切片 l[:5] 应该是一个 dinx(1,2,3,0,1) ,分别带有关键字‘A’‘B’

由于我们只允许在 _comp 中使用字符串字典键,我们可以假设如果它看到字符串索引输入,它应该返回底层 _comp 键的值。因此,我们可以在 dinx 中结合列表和字典类型的索引。

首先,当我们通过索引获取 dinx 的值时,我们希望返回一个 dinx 。因此,我们需要将 cls 变量定义为 type(self) ,然后我们可以使用它在 return 语句中启动一个新的 dinx :

如果传递的索引(ind)是一个字符串,则返回一个以 ind 为关键字的新 dinx(s作者捕获的屏幕截图)

为了从 intslice 类型生成 dinx ,我们需要定义一个方法,将我们的 _comp_map 元组列表转换成一个字典,我们可以使用它在 return 语句中启动一个新的 dinx :

作者截图

回到 getitem:

作者截图

让我们做几个测试:

在上面的例子中,我们是用 struct 方法单独定义的。它返回 dinx 的字典表示。在文章的最后将提供关于 dinx 类的完整代码。(作者截图)

将 dinxs 相加

在 Python 中,实现加法运算最常用的 dunder 方法有两种: add (+) 和 iadd (+=)。我们将从后者开始:

作者截图

这里我们取两个输入, selfother ,其中 other 是另一个 dinx ,我们迭代 other 中的每个元素。_comp 并将其添加到 self。_comp 如果密钥存在,或者在 self 中创建一个新密钥。_comp 否则。我们只对列表这样做,从而保持元组不变,这允许我们在我们的 dinx 中定义我们不想变异的元素。

定义了原地加法方法(x+=y)之后,我们现在可以用它来定义 x+y 类型的加法。这个想法很简单,我们将使用 dinx 的一个临时深度副本,在它上面做一个 other 的就地添加,并返回结果:

作者截图

让我们测试一下,看看它是如何工作的:

作者截图

分类索引

列表的另一个重要特性是排序的能力。我们也可以使用排序方法中的参数,根据自己的功能对列表进行排序。在本节中,我们将为 dinx 创建排序方法

首先要记住的是,我们已经有了一个键-值元组列表,我们用它来获得 dinx 元素( self)的顺序。_comp_map 。因此,我们对 dinx 应用的任何排序函数都可以简单地传递给 self。_comp_map 。唯一的问题是,我们需要按照元组的第二个元素进行排序。这可以使用 lambda x: x[1] 作为密钥来完成。然后,如果我们想将应用于 dinx ,我们可以通过λx:key(x[1])在内部将其应用于 x[1]最后,我们可以对应用排序或者让它返回一个新的 dinx :

作者截图

让我们测试一下新的排序方法:

在最后两个例子中,我们先排列偶数,然后排列奇数(作者截图)

结论

本文的目的是展示 Python 提供了相当简单易用的工具,我们可以利用这些工具来配置项目以满足我们的需求。上面的自定义数据容器的例子不一定适用于真实世界的场景,但仍然证明了我们可以构建自己的基本数据结构,以便更好地控制和管理正在处理的数据。

我还实现了一些更小的东西,比如 contains 向 dinx 中的 x 返回一个布尔值, len 获取 dinx 的长度, count 返回传递给它的变量的计数,以及 update、valueskeys 字典方法。以下是完整的代码:

为 sklearn 管道创建自定义转换器

原文:https://towardsdatascience.com/creating-custom-transformers-for-sklearn-pipelines-d3d51852ecc1?source=collection_archive---------2-----------------------

了解如何创建适合并转换数据的自定义转换器

照片由伊克拉姆-奥-道拉·沙文在 Unsplash 上拍摄

在我之前的文章中,我谈到了如何使用 sklearn 中的Pipeline类来简化您的机器学习工作流程。特别是,我谈到了如何使用各种转换器类(比如SimpleImputerStandardScalerOneHotEncoder)来转换管道中的数据。

有些时候 sklearn 没有提供你需要的变压器。所以在这种情况下,你必须写你自己的 transformer 类,sklearn 的Pipeline类可以使用。

定义我们的定制转换器

让我们从您能想到的最简单的转换器开始——一个过滤熊猫数据帧中的列的定制转换器。这是为 transformer 类结构奠定基础的好机会:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_is_fitted# The ColumnsSelector class inherits from the sklearn.base classes 
# (BaseEstimator, TransformerMixin). This makes it compatible with 
# scikit-learn’s Pipelinesclass ColumnsSelector(BaseEstimator, TransformerMixin):
    # initializer 
    def __init__(self, columns):
        # save the features list internally in the class
        self.columns = columns

    def fit(self, X, y = None):
        return self def transform(self, X, y = None):
        # return the dataframe with the specified features
        return X[self.columns]

上面定义了一个名为ColumnsSelector的 Python 类,它继承了sklearn.base类— BaseEstimatorTransformerMixin。它具有以下功能:

  • 初始化器— __init__。在这里,您将传递到这个定制转换器中的列的名称保存为一个内部变量— self.columns。该内部变量的名称必须与参数名称相匹配(即columns)。
  • 一个拟合函数— fit()。此函数用于计算自定义变压器的参数。在这个例子中,我们不需要做任何事情,因为我们的转换只是过滤列。在其他转换器(如StandardScalar)中,fit()函数将计算数据集中各列的平均值和标准偏差值,以便transform()函数稍后执行转换。同样,我将在后面的部分用另一个例子来说明这一点。
  • 一个变换函数— transform()。这个函数用于将实际的转换应用到您的自定义转换器打算执行的数据帧。在我们的示例中,您希望根据用户传入的列列表来过滤 dataframe。

注意,fit()transform()函数都接受两个参数— Xy(可选;值None的默认参数)。

使用我们的定制变压器

定义了自定义转换器后,让我们使用我在上一篇文章中使用的相同数据集来尝试一下:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_splitdf = pd.read_csv('train.csv')
df = df[['Survived','Pclass','Sex','Age','Fare','Embarked']]X = df.iloc[:,1:]
y = df.iloc[:,0]
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                  test_size = 0.3, 
                                                  stratify = y, 
                                                  random_state = 0)
X_train

数据来源 :本文数据来源来自https://www.kaggle.com/c/titanic/data.

下面是我们将在本文中使用的数据框架:

作者图片

要使用ColumnsSelector转换器,让我们创建一个Pipeline对象,并将我们的ColumnsSelector转换器添加到其中:

from sklearn.pipeline import Pipelinenumeric_transformer = Pipeline(steps=[
    **('columns selector', ColumnsSelector(['Age','Fare'])),**
])

在上面的语句中,我想从 dataframe 中提取出AgeFare列,稍后我将使用fit()函数传递给它。

现在,我可以通过调用Pipeline对象上的fit()函数并向其传递X_train dataframe 来调用自定义转换器中的fit()函数:

numeric_transformer.**fit**(X_train)

您将看到以下输出:

Pipeline(steps=[('columns selector', ColumnsSelector(columns=['Age', 'Fare']))])

回想一下,我们的fit()函数在这里没有做任何有用的事情。因此在这里调用fit()并不会真正在类内部做任何事情。

transform()功能怎么样?现在让我们使用X_train数据帧从Pipeline对象调用transform()函数:

numeric_transformer.**transform**(X_train)

您将看到以下输出:

作者图片

您可以使用fit_transform()功能合并对fit()transform()的调用:

numeric_transformer.fit_transform(X_train, y_train)

fit_transform()函数调用fit(),然后在您的自定义转换器中调用transform()

很多变形金刚里,需要先调用fit(),才能调用transform()。但是在我们的例子中,由于我们的fit()不做任何事情,所以您是否调用fit()并不重要。

基于您目前所看到的,值得记住以下fit_transform()transform()函数的用例:

  • 您在训练数据集上使用fit_transform()来拟合和转换数据
  • 您使用transform()来应用您在测试集合上的训练数据集上使用的转换

继续我们的讨论,让我们将SimpleImputer转换器添加到Pipeline对象中:

from sklearn.pipeline import Pipeline
**from sklearn.impute import SimpleImputer**numeric_transformer = Pipeline(steps=[
    ('columns selector', ColumnsSelector(['Age','Fare'])),
  **  ('imputer', SimpleImputer(strategy='median')),**
])

如果您现在尝试在Pipeline对象上调用transform():

numeric_transformer.transform(X_train)

您将得到一个错误:

NotFittedError: This SimpleImputer instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.

如前所述,对于某些变压器,您需要调用fit()fit_transform()函数来确保数据首先被拟合。在本例中,SimpleImputer对象需要计算指定列的中值(在fit()函数中),然后才能替换transform()函数中列的所有NaNs

要解决这个问题,用X_train数据帧调用fit_transform()函数:

numeric_transformer.**fit_transform**(X_train)

您将看到如下所示的结果:

作者图片

您可以通过以下方式可视化工作流:

作者图片

现在让我们继续添加StandardScaler转换器到Pipeline对象:

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
**from sklearn.preprocessing import StandardScaler**numeric_transformer = Pipeline(steps=[
    ('columns selector', ColumnsSelector(['Age','Fare'])),
    ('imputer', SimpleImputer(strategy='median')),
 **('scaler', StandardScaler())**
])numeric_transformer.fit_transform(X_train)

现在,您应该可以看到标准化的AgeFare列中的值:

作者图片

使用标准化的训练集合中的值,您现在可以使用transform()函数将转换应用到测试集合:

numeric_transformer.**transform**(X_test)

您应该会看到以下结果:

array([[-0.65142052, -0.47989005],
       [-1.97483693,  0.09842973],
       [ 3.20205667, -0.47958116],
       [-0.41787645,  0.91519704],
       [-0.06756034, -0.48921406],
       [-0.80711657, -0.06803741],
       [-0.04809833, -0.47958116],

创建我们自己的定制标准转换器

既然您已经看到了如何创建定制转换器的简单示例,那么让我们来看看另一个示例。这一次,让我们试着自己实现StandardScaler变压器。

首先,让我们声明一个类调用MyStandardScaler:

class MyStandardScaler(BaseEstimator, TransformerMixin): 
    def __init__(self):
        return None

    def fit(self, X, y = None):
        print(type(X))
        # the type of X might be a DataFrame or a NumPy array
        # depending on the previous transformer object that 
        # you use in the pipeline
        self.means = np.mean(X, axis=0)    # calculate the mean
        self.stds = np.std(X, axis=0)      # calculate the 
                                           # standard deviation
        return self def transform(self, X, y = None):
        return (X - self.means) / self.stds

像前面的例子一样,MyStandardScaler类实现了fit()transform()函数:

  • fit()函数中,您计算 2D 矩阵中每一列的平均值和标准偏差(作为 NumPy 数组或 Pandas 数据帧)
  • transform()函数中,您使用以下公式计算标准化值:

作者图片

其中 X 为列中的当前值, μ 为数列的平均值,【σ为数列的标准差,Z 为新的标准化值。

fit()函数中,我特意打印了X的类型,向您展示您的管道中使用的前一个转换器如何影响您在当前转换器中接收的数据类型。

为了使用MyStandardScaler转换器,让我们修改一下之前的管道:

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScalernumeric_transformer = Pipeline(steps=[
    ('columns selector', ColumnsSelector(['Age','Fare'])),
 **('my scaler', MyStandardScaler())** 
])numeric_transformer.fit_transform(X_train)

对于我们的MyStandardScaler变压器,您需要直接调用fit_transform()或者同时调用fit()transform()。如果您简单地调用transform()函数,它将不起作用,因为该类没有每列的平均值和标准偏差来计算每列的标准化值。

当管道运行时,您将看到以下输出:

<class 'pandas.core.frame.DataFrame'>

这意味着从ColumnsSelector传入的数据是熊猫数据帧。fit_transform()功能的输出为以下数据帧:

作者图片

现在,让我们在管道中的MyStandardScaler变压器之前添加一个SimpleImputer变压器:

numeric_transformer = Pipeline(steps=[
    ('columns selector', ColumnsSelector(['Age','Fare'])),
 **('imputer', SimpleImputer(strategy='median')),**
    ('my scaler', MyStandardScaler())  
])numeric_transformer.fit_transform(X_train)

这一次,当您运行代码时,您将看到以下内容:

<class 'numpy.ndarray'>

这表明SimpleImputer将转换后的数据作为 NumPy 数组返回。

Pipeline对象的fit_transform()函数的输出将是一个数组:

array([[-0.02863633, -0.47911875],
       [-0.65142052, -0.46270324],
       [-0.04809833, -0.32513665],
       ...,
       [ 0.20490775,  0.42203815],
       [-0.04809833, -0.22194182],
       [-0.5735725 , -0.45646073]])

输出中的值与使用StandardScaler时的值相同。

确保变压器已经安装

还记得我之前说过,对于MyStandardScaler转换器,您需要在转换发生之前调用fit()函数吗?如果用户没有拟合就调用transform()函数会怎么样?在这种情况下,重要的是向用户返回正确的错误消息,告诉他们首先拟合数据。您可以通过check_is_fitted()功能这样做,就像这样:

**from sklearn.utils.validation import check_is_fitted**class MyStandardScaler(BaseEstimator, TransformerMixin): 
    def __init__(self):
        return None

    def fit(self, X, y = None):
        print(type(X))
        # the type of X might be a DataFrame or a NumPy array
        # it depends on the previous transformer object that 
        # you use in the pipeline
        self.means = np.mean(X, axis=0)
        self.stds = np.std(X, axis=0)
        return self def transform( self, X, y = None ):
        **check_is_fitted(self, ['means','stds'])**
        return (X - self.means) / self.stds

check_is_fitted()函数中,您只需要传入一个字符串(或字符串列表),指定需要出现在类中的对象属性(如果用户跳过fit()函数,将不会创建meansstds属性,因此该函数将引发NotFittedError异常)。

为了测试这一点,让我们使用transform()函数调用Pipeline对象:

numeric_transformer = Pipeline(steps=[
    ('columns selector', ColumnsSelector(['Age','Fare'])),
    ('imputer', SimpleImputer(strategy='median')),
    ('my scaler', MyStandardScaler())  
])numeric_transformer.**transform**(X_train)

正如所料,您将看到错误消息:

NotFittedError: This SimpleImputer instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.

摘要

我希望这篇文章能揭示出变形金刚在幕后是如何工作的。特别是,我希望你现在理解fit()transform()fit_transform()功能之间的区别以及它们是如何工作的。更具体地说,我还希望您现在已经掌握了创建自己的自定义转换器的知识,它可以与Pipeline对象一起工作。

https://weimenglee.medium.com/membership

使用 Scikit-Learn 创建自定义变压器

原文:https://towardsdatascience.com/creating-custom-transformers-using-scikit-learn-5f9db7d7fdb5?source=collection_archive---------4-----------------------

本文讨论了使用 Scikit-Learn 创建定制转换器的两种方法,以及它们在 Pipeline 和 GridSearchCV 中的实现。

阿瑟尼·托古列夫在 Unsplash 上的照片

转换器是在为机器学习预处理数据时实现数据转换的类。Scikit-Learn 中的转换器示例有 SimpleImputer、MinMaxScaler、OrdinalEncoder、PowerTransformer 等等。有时,我们可能需要执行流行的 Python 包中没有预定义的数据转换。在这种情况下,定制变压器来拯救。在本文中,我们将讨论使用 Scikit-Learn 在 Python 中定义定制转换器的两种方法。我们将使用 Scikit-Learn 中的“虹膜数据集”,并使用 IQR 方法定义一个用于异常值消除的自定义转换器。

方法 1

该方法通过继承 Scikit-Learn 的 BaseEstimator 和 TransformerMixin 类来定义自定义转换器。Scikit-Learn 的“BaseEstimator”类通过添加“set_params”和“get_params”方法来启用超参数调优。而“TransformerMixin”类添加了“fit_transform”方法,但没有显式定义它。在下面的代码片段中,我们将导入所需的包和数据集。

作者图片

在上面的代码片段中,我们定义了一个名为“OutlierRemover”的类,这是我们的自定义转换器,用于删除异常值,即使用 NaN 替换异常值。该类有一个名为“factor”的属性,它是一个超参数,用于控制异常值移除过程。“因子”越高,极端值将被移除。默认情况下,“因子”初始化为 1.5。该类有三个方法,即“离群值移除”、“拟合”和“转换”。继承 BaseEstimator 和 TransformerMixin 类增加了另外三个方法,即,' fit_transform ',' get_params '和' set_params '。我们还创建了一个名为“OutlierRemover”类的“outlier_remover”实例。

init '是创建该类的实例/对象时调用的第一个方法。这用于初始化类属性。我们将用 1.5(默认值)初始化 IQR 方法的因子。“异常值移除”方法用 NaN 替换系列中的异常值。“fit”方法总是返回 self。“transform”方法接受一个数组/数据帧作为输入,并将 outlier_removal 方法应用于数据帧/数组的所有列并返回它。

作者图片

我们将使用“OutlierRemover”通过创建一个名为“test”的包含三列和四条记录的数据框来应用异常值移除转换。

作者图片

我们可以看到“col1”有一个异常值(999),而“col3”也有一个异常值(-10)。我们将首先使“OutlierRemover”适合“test”数据框(使用已经创建的实例“outlier_remover”),并对其应用变换。

outlier_remover.fit(test)

作者图片

outlier_remover.transform(test)

作者图片

我们可以看到,“列 1”(999)中的异常值被替换为 NaN,“列 3”(10)中的异常值被替换为 NaN。我们可以使用如下所示的一个“fit_transform”方法来应用转换。这与上面的结果相同。

outlier_remover.fit_transform(test)

作者图片

我们将通过将“因子”设置为 100 来创建“OutlierRemover”类的一个名为“outlier_remover_100”的实例。如前所述,“因子”越高,极端值将被剔除。

作者图片

我们可以看到,“列 1”中的“999”和“列 2”中的“-10”这次没有被视为异常值,因为“因子”属性很高。现在,我们将离群点去除器变换应用于虹膜数据集。在此之前,我们将使用箱线图显示 Iris 数据集的四列中的异常值。

作者图片

在上面的方框图中,我们可以看到列“SepalWidthCm”有几个异常值,准确地说是四个。其他三列没有异常值。我们将创建一个 ColumnTransformer,将“OutlierRemover”应用于 Iris 数据集的所有变量,并使用箱线图可视化离群点移除后的变量。

作者图片

在上面的方框图中,我们可以看到“SepalWidthCm”列中的异常值已被移除,即替换为 NaN。我们将找出从每一列中删除了多少个异常值以及哪些异常值。

作者图片

作者图片

我们可以看到,大于 4 且小于或等于 2 的“SepalWidthCm”的值被移除,因为它们是异常值。在前面显示异常值的箱线图中也可以看到同样的情况。现在,我们将创建一个移除异常值的管道,估算移除的异常值并拟合逻辑回归模型。我们将使用 GridSearchCV 调优超参数。

作者图片

方法 2

创建自定义转换器的第二种方法是使用 Scikit-Learn 的“FunctionTransformer”类。这是一种更简单的方法,不需要定义类,但是,我们需要定义一个函数来执行所需的转换。类似于方法 1,我们将创建一个定制的转换器来删除离群值。下面的函数将数组/数据框以及“因子”作为输入,并用 NaN 替换每列中的异常值。

在上面的代码片段中,我们还创建了一个名为“FunctionTransformer”类的“outlier_remover”的实例,方法是传递我们为异常值删除定义的自定义函数(“outlier_removal”)以及参数“factor”。在此方法中,我们需要使用“FunctionTransformer”的“kw_args”参数将附加参数(而不是输入数组/数据帧)作为字典传递给“Functiontransformer”中的函数。我们还创建了方法 1 中使用的“测试”数据框。

作者图片

我们可以看到“col1”有一个异常值(999),而“col3”也有一个异常值(-10)。我们将使用已经创建的实例“outlier_remover”对数据进行拟合和应用“OutlierRemover”转换。

outlier_remover.fit_transform(test)

我们可以看到,“列 1”(999)中的异常值被替换为 NaN,“列 3”(10)中的异常值被替换为 NaN。使用“FunctionTransformer”创建一个自定义转换器为我们提供了一些额外的方法,如下所示。

[i for i in dir(outlier_remover) if i.startswith('_') == False]

作者图片

现在,我们将创建一个移除异常值的管道,估算移除的异常值并拟合逻辑回归模型。我们将使用 GridSearchCV 调优超参数。

作者图片

方法 2 的主要区别在于,我们需要调整“kw_args”超参数,这与其他变压器(包括方法 1 中讨论的变压器)不同。在上面的代码片段中,我们使用值列表[{'factor':0}、{'factor':1}、{'factor':2}、{'factor':3}、{'factor':4}]调整了' kw_args '超参数。这可能使得难以调整定制变压器的多个超参数。

这是使用 Scikit-Learn 定义定制转换器的两种方法。定义自定义转换器并将它们包含在管道中简化了模型开发,还防止了使用 k-fold 交叉验证时的数据泄漏问题。

创建定制的 ML Web 应用程序

原文:https://towardsdatascience.com/creating-customized-ml-webapps-984874b6d858?source=collection_archive---------36-----------------------

使用 Gradio 创建基于 UI 的应用程序

来源:作者

如果你曾经创建过一个 web 应用程序,那么你应该知道构建一个需要付出的努力。创建 web 应用程序需要花费大量时间,因为我们需要寻找 UI 组件,创建机器学习模型,创建管道以在应用程序中呈现它,等等。这需要一点经验和知识来使它工作。

Gradio 是一个开源 python 库,用于创建漂亮的 web 应用程序。我们可以围绕 ML 模型创建一个 UI 包装器,并将其呈现给期望的受众。它易于使用,只用几行代码就能创建应用程序。

在本文中,我们将探索 Gradio 的基础知识,并通过应用不同的过滤器创建一个图像编辑应用程序。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装 Gradio 开始。下面给出的命令可以做到这一点。

!pip install gradio

导入所需的库

在这一步中,我们将导入所需的 Gradio & Numpy 库。

import gradio as gr
import numpy as np

创建 Web 应用程序

在这里,我们将创建 web 应用程序,其中我们将使用 NumPy 数组创建不同的过滤器进行图像编辑,并使用 Gradio 渲染该应用程序,以创建一个漂亮的界面,我们将上传任何图像并在其上应用过滤器。

def sepia(img):  

  sepia_filter1 = np.array([[.99, .99, .9],
                           [.29, .19, .9],
                           [.98, .345, .234]])
  sepia_img1 = img.dot(sepia_filter1.T)
  sepia_img1 /= sepia_img1.max()      

  return sepia_img1iface = gr.Interface(sepia, gr.inputs.Image(shape=(200, 200)), "image")
iface.launch()

来源:作者

你可以看到我们使用 Gradio 用一行代码创建了一个多么漂亮的界面。在接下来的文章中,我将向您展示如何为您的机器学习、深度学习和 NLP 应用程序创建 UI 界面。

继续尝试不同的图像和过滤器。如果您发现任何困难,请在回复部分告诉我。

本文是与 Piyush Ingale 合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时联系我在 hmix13@gmail.com 或我的 LinkedIn 简介 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

使用 Jupyter Notebook 创建数据科学 Python 包

原文:https://towardsdatascience.com/creating-data-science-python-package-using-jupyter-notebook-6fa6e6b74a87?source=collection_archive---------12-----------------------

了解面向对象编程如何帮助您使用 Jupyter notebook 构建第一个 Python 包。

图片作者|元素作者 katemangostar

介绍

你想知道像 Scikit-learn、pandas 和 NumPy 这样的 Python 包是如何构建的吗?它们都基于面向对象编程(OOP)来创建复杂且易于使用的包。对于一个数据科学家来说,学习 OOP 是必要的,这样他们就可以在生产就绪产品的开发中使用它。

我们将使用 cloud Jupyter 笔记本来简化环境的设置,并完全专注于创建一个包。该项目包括面向对象的基础知识,如继承,对象,类和神奇的功能。这个项目受 AWS 机器学习基础课程的影响很大,一旦我知道如何构建它,我花了 10 分钟来重新创建这个包。

分布

父类

让我们深入编码并讨论我们的类“分布,它将被高斯和二项式类使用。我们将使用 Jupyter 笔记本的神奇功能%%witefile 来创建 python 文件。

%%writefile distributions/general.py

上面的代码将在发行版文件夹中创建一个 python 文件,为了简单起见,您需要创建一个包含测试文件的测试文件夹,一个包含所有软件包文件的发行版文件夹,以及一个包含.txt数据文件夹。

分布类有两个参数,表示标准差,它还包含用于访问数据文件的read_data_file()函数。

__init__函数初始化变量。

测试分布类

这个班的一切都很顺利。我们添加了均值、标准差,并加载了random.txt文件来测试我们的Distribution类。

高斯分布

高斯分布在统计学中很重要,在社会科学中常用来表示分布未知的真实随机变量。 —维基百科

图 1 | 维基百科

平均

一列数字的平均值是所有数字的总和除以样本数。意思是——维基百科

标准偏差

这是对数据变化的一种度量。BMJ

概率密度函数

参数mu 是均值,而参数 sigma 是标准差。x是一个列表中的值。

高斯类

我们将从父类Distribution继承值和函数,并使用 python 这个神奇的函数。

  1. 初始化父类分配
  2. 创建plot_histogram_pdf函数→ 数据的归一化直方图,并可视化 概率密度函数。
  3. 创建魔法函数__add__将两个高斯分布对象相加。
  4. 创建魔法函数__repr__输出高斯实例的特征。

做实验

测试__repr__魔法功能。

用 25 个平均值和 2 个标准偏差初始化gaussian1 对象,然后从数据文件夹中读取random.txt文件。

计算数据上 25 means 和 2 Stdev 的概率函数。然后,计算random.txt的均值和标准差。新的均值是 125.1 和 Stdev 到 210.77 ,这使得我们的概率密度函数值从 0.19947 变为 0.00169

绘制概率密度函数的直方图和线图。

单元测试

unittest 是一个测试框架,最初受 JUnit 的启发,与其他语言中的主要单元测试框架有相似的风格。它支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中,以及测试独立于报告框架,参见文档。

创建高斯类测试文件

测试优先是一个很好的工具。它在团队中创造了更好的理解和生产力。结果是高质量的代码——无论是在早期成功发现错误还是正确实现功能方面。— 吉尔·齐伯菲德

我们将使用 unittest 库来测试我们所有的函数,以便将来如果我们做了任何更改,我们可以在几秒钟内检测到错误。

创建包含所有函数的TestGaussianClass来测试Gaussian 类中的函数。我们使用了assertEqual方法来破解函数的有效性。

我自己测试了这些值,然后将它们逐个添加,以测试每种可能性。

试探性试验

让我们使用!python 运行测试文件夹中的测试文件。

如你所见,所有测试都通过了。一开始我得到了多个,调试这些问题帮助我更好地理解了Gaussian 类是如何在每一级工作的。

二项分布

带参数np 的二项式分布是一系列n独立实验中成功次数的离散概率分布,每个实验都提出是或否的问题,并且每个实验都有自己的布尔值结果:成功(概率为 p)或失败(概率为 q = 1p)。二项式分布—维基百科

二项分布图|维基百科

平均

差异

标准偏差

概率密度函数

二项式类

我们将使用上面提到的数学函数来创建均值、标准差和概率密度函数。我们已经在上一个类中完成了具有挑战性的工作,现在我们将使用类似的模式来编写Binomial 类。

  1. 初始化概率和大小变量→ p,n
  2. 初始化父类分布→ 计算 **mean** **Stdev** 并将其添加到父类中。
  3. 创建replace_stats_with_data 函数 ,从导入的数据中计算概率、大小。新的平均值和标准偏差将被更新。
  4. 使用 matplotlib 库创建*plot_bar*函数→ 显示条形图。
  5. 创建*pdf* 函数→ 使用均值和标准差计算数据的概率密度函数。
  6. 创建*plot_bar_pdf*函数→ 绘制二项分布的 pdf。
  7. 创建魔法函数*__add__*用两个 **Binomial** 分配对象相加。
  8. 创建魔法函数*__repr__*输出 **Binomial** 实例的特征

做实验

测试__repr__魔法功能

测试Binomial 对象和read_data_file功能。

测试 p 0.4 和 n 20 的初始值的 pdf。我们将使用replace_stats_with_data来计算数据的 pn ,然后重新计算 PDF。

测试条形图

测试概率密度函数柱状图。

二项式类别测试函数

我们将使用 unittest 库来测试我们所有的函数,以便将来如果我们做了任何更改,我们可以在几秒钟内检测到错误。

创建TestBinomialClass,它具有测试Binomial 类的所有函数。

试探性试验

运行 test_binomial.py 显示在测试过程中没有发现错误。

正在创建 init。py 函数

我们需要在 distributions 文件夹中创建__init__.py文件来初始化 python 文件中的类。这将帮助我们直接调用特定的类。

我们已经启动了二项式和高斯类。

创建 setup.py 函数

这个setuptools是构建 python 包所必需的。设置功能需要软件包信息、版本、描述、作者姓名和电子邮件。

目录

下图显示了包含所有必需文件的包目录。

安装分发包

(venv) [[email protected]](https://www.analyticsvidhya.com/cdn-cgi/l/email-protection):~/work # pip install -U .

使用pip install .pip install -U .来安装我们可以在任何项目中使用的 python 包。正如我们所看到的,我们的分发包已经成功安装。

**Processing /work**
Building wheels for collected packages: distributions
  Building wheel for distributions (setup.py) ... done
  Created wheel for distributions: filename=distributions-0.2-py3-none-any.whl size=4800 sha256=39bc76cbf407b2870caea42b684b05efc15641c0583f195f36a315b3bc4476da
  Stored in directory: /tmp/pip-ephem-wheel-cache-ef8q6wh9/wheels/95/55/fb/4ee852231f420991169c6c5d3eb5b02c36aea6b6f444965b4b
**Successfully built distributions**
Installing collected packages: distributions
  Attempting uninstall: distributions
    Found existing installation: distributions 0.2
    Uninstalling distributions-0.2:
      Successfully uninstalled distributions-0.2
Successfully installed distributions-0.2

测试我们的包

我们将在 Linius 终端中运行 Python 内核,然后测试这两个类。

做得好,你已经创建了你的第一个 Python 包。

>>> from distributions import Gaussian
>>> from distributions import Binomial
>>> 
>>> print(Gaussian(20,6))
**mean 20, standard deviation 6**
>>> print(Binomial(0.4,50))
**mean 20.0, standard deviation 3.4641016151377544, p 0.4, n 50**
>>>

https://github.com/kingabzpro/Creating-Python-Package-using-Jupyter-Notebook

如果还面临问题,可以去看看我的GitHubrepo或者Deepnote项目。********

你可以关注我的领英和 T21,我每周都会在那里发表文章。

本文中显示的媒体不归 Analytics Vidhya 所有,由作者自行决定使用。

原载于 2021 年 7 月 30 日 https://www.analyticsvidhya.com*https://www.analyticsvidhya.com/blog/2021/07/creating-data-science-python-package-using-jupyter-notebook***

用 3 到 5 行代码创建深度神经网络

原文:https://towardsdatascience.com/creating-deep-neural-networks-with-3-to-5-lines-of-code-baa83fa616ed?source=collection_archive---------8-----------------------

思想和理论

我们可以通过改变已经提出的模型的很少几行代码来创建新的深度神经网络。

图片作者。

当在深度学习中处理监督学习时,我们可以说有一些经典的方法可以遵循。第一种解决方案是所谓的“英雄”策略,其中从零开始创建一个全新的深度神经网络(DNN ),并对其进行训练/评估。实际上,这种解决方案可能不是很有趣,因为现在有无数的 dnn 可用,如许多深度卷积神经网络(CNN),可以重复使用。第二条路是简单地考虑一个可部署的 DNN,为某个环境训练,并在另一个环境中观察它的操作。尽管深度学习取得了诸多进步,但如果环境过于多样化,模型可能会表现不佳。

今天最著名的方法之一被称为迁移学习,它用于通过转移相关领域的信息来改进一个领域(上下文)的模型。依赖迁移学习的动机是当我们面临训练数据集中没有那么多样本的情况时。造成这种情况的一些原因是,收集和标记这些数据并不便宜,或者这些数据很少。

照片由扬科·菲利 在 Unsplash 上拍摄。

但是,迁移学习也有缺点。通常,模型是在大型数据集上训练的,因此这种预训练的模型可以在另一个上下文中重用。因此,我们不是从零开始训练,而是基于预训练模型中嵌入的后天“智能”。然而,即使我们有大量的图像要训练,训练数据集也必须足够通用,以处理不同的上下文。有许多有趣的基准映像集,如 ImageNet 和 COCO,旨在解决这个问题。但是,最终,我们可能会在一个具有挑战性的领域(例如自动驾驶、遥感)工作,其中基于这些经典数据集的迁移学习可能是不够的。

即使我们多次尝试增加训练样本,例如数据增加、生成对抗网络(GANs),我们也可以通过重用和/或进行一些修改和/或组合其他已提出模型的不同特征来创建新模型。这种策略的一个最重要的例子是著名的对象检测 DNNs,称为 YOLO 。这些模型,尤其是版本 4,是基于许多其他解决方案开发的。这种网络是一种不同概念的折衷混合,以获得一种新的模型,它们在检测图像和视频中的对象方面非常成功。请注意, YOLOX 是 YOLO 网络的最新版本。

在 Unsplash 上由安梅丽·莫里雄 拍摄的照片。

这篇文章的方向是通过在以前提出的方法中完成一些变化来创建新的模型。它展示了通过改变先前提出的模型的很少几行代码来创建“新的”dnn 是多么容易。请注意,由于我们所做的更改基本上与原始模型的层数有关,因此我们将下面介绍的网络称为“新”网络,这是对它的一点推动。但是,重点是鼓励实践者考虑这一点,并最终在实际环境中使用 DNNs 时重用/修改以前的想法以产生新的方法。

VGG12BN

在 2014 年 ImageNet 大规模视觉识别挑战赛(ils vrc)中,VGG 是一个经典的 DNN,今天仍有一些用途,尽管一些作者认为它是一个过时的网络。在最初的文章中,作者提出了具有 11、13、16 和 19 层的 vgg。在这里,我们展示了如何创建一个“新的”VGG 组成的 12 层和批量规格化(BN)只是通过增加/改变 5 行代码:VGG12BN。

我们依赖 PyTorch 团队的实现,并修改它来创建我们的模型。VGG 修改后的代码是这里是,使用它的笔记本是这里是。此外,我们考虑了 fastai 的 imagenette 320 px 数据集的一个稍微修改的版本。不同之处在于,原始验证数据集被分成两部分:包含原始验证集的 1/3 图像的验证数据集,以及组成测试数据集的 2/3 图像。因此,在训练中有 9,469 幅图像(70.7%),在验证中有 1,309 幅图像(9.78%),在测试集中有 2,616 幅图像(19.53%)。这是一个有 10 个类别的多类别分类问题。我们将数据集称为 imagenettetvt320 。

我们现在展示我们在 PyTorch 团队的 VGG 实现中所做的修改:

  • 首先,我们注释掉了from .._internally_replaced_utils import load_state_dict_from_url以避免依赖其他 PyTorch 模块。此外,为了完全确定我们不会使用预训练模型(默认情况下 pretrained = False),我们注释掉了model_urls。这只是为了强调这一点,并不是真的有必要这样做;
  • 第一个修改是增加了我们车型的名称:"vgg12_bn”

图片作者。

  • 由于我们有 10 个类,所以我们把num_classes从 1000 改成了 10;

图片作者。

  • 因此,我们创建一个新的配置,"V",具有以下卷积层(每层的信道数量按顺序显示):64、64、128、128、256、256、512、512、512。请注意,下面的"M" 表示最大池。因为 VGG 默认有 3 个全连接(FC)层,所以我们总共有 12 个层;

图片作者。

  • 最后,我们创建一个函数vgg12_bn,其中只有一行代码调用另一个函数。请注意,我们看到参数"vgg12_bn"(网络名称)、"V"(配置)和True的值,其中后者激活批量标准化。

图片作者。

就是这样。通过添加/修改 5 行代码,我们创建了我们的模型。在笔记本中,我们需要导入vggmodified文件来使用 VGG12BN。

图片作者。

下图(表)显示了基于 10 个时期训练后的测试数据集的准确度(Acc)结果。我们比较了原始的 VGG16BN、VGG19BN 和提议的 VGG12BN 模型。列 # Train Param (M)# Param Mem (MB)Time (s) 表示每个模型的百万个可训练参数的数量,仅由模型参数决定的兆字节大小,以及使用 Google Colab 执行它们的时间。我们的“新”VGG12BN 获得了更高的精度。

VGG:结果。图片作者。

DenseNet-83 和 ResNet-14

在 DenseNet 模型中,每一层都以前馈方式与其他层相连,旨在最大化层间的信息流。2015 年 ILSVRC 的另一个获奖者, ResNet 是最受欢迎的 CNN 之一,其中已经提出了它的几个变体(ResNeXt、Wide ResNet、…),它也作为其他 dnn 的一部分得到了重用。这是一种残差学习方法,其中堆叠层拟合残差映射,而不是直接拟合期望的底层映射。我们遵循了与刚才介绍的 VGG12BN 类似的过程,但现在我们只需更改 3 行代码,就可以创建 DenseNet-83 (83 层)和 ResNet-14 (14 层)。

访问此处dense net 修改后的代码及其对应的笔记本是此处。ResNet 修改后的代码在这里是,笔记本与 VGG12BN 相同,但现在我们通过运行 ResNet-14 来显示的输出。由于创建这两个网络的修改是相似的,下面我们将只显示创建 DenseNet-83 的修改。因此,这就是我们所做的:

  • 如前所述,我们注释掉了from .._internally_replaced_utils import load_state_dict_from_url以避免依赖其他 PyTorch 模块。但是注意,我们现在没有评论出models_url
  • 我们添加了我们模型的名称:"densenet83"

图片作者。

  • 我们创建一个函数densenet83,它只有一行代码调用另一个函数。注意,我们看到参数"densenet83"(网络的名字),和(3,6,18,12)的值分别是密集块 1,2,3,4 的重复次数。

图片作者。

下图显示了 ImageNet 的 DenseNet 架构。我们将 DenseNet-161 作为参照,并将嵌段的重复次数减半以得到 DenseNet-83。

图片(表格)来自 DenseNet 的文章。

总共添加/修改了 3 行代码。对于 DenseNet,下图(表)显示了基于 10 个时期训练后的测试数据集的准确度(Acc)结果。我们比较了最初的 DenseNet-121、DenseNet-161 和提议的 DenseNet-83 型号。我们基本上看到了 DenseNet-161 和我们的“新”DenseNet-83 在性能方面的差距,DenseNet-161 略胜一筹。

DenseNet:结果。图片作者。

关于 ResNet,比较 ResNet-18、ResNet-34 和“新”ResNet-14,ResNet-18 最好,ResNet-14 次之,如下图(表)所示。

ResNet:结果。图片作者。

结论

在本帖中,我们展示了通过修改先前提议的网络的几行代码来创建新的 dnn 是多么容易。我们声称重用以前的想法并通过适当的修改衍生出新的模型是一个很好的途径。

创建、编辑和合并 ONNX 管道。

原文:https://towardsdatascience.com/creating-editing-and-merging-onnx-pipelines-897e55e98bb0?source=collection_archive---------7-----------------------

可视化一个简单的图像处理管道。

ONNX 是一种非常有用的存储数据科学/人工智能工件的格式,用于版本控制和部署。我们很高兴分享[sclblonnx](https://pypi.org/project/sclblonnx/),这是一个 python 包,可以轻松编辑和扩充 ONNX 图形。

在过去的一年里,在 Scailable ,我们大量使用 ONNX 作为存储数据科学/人工智能工件的工具:ONNX 图有效地指定了对输入数据执行的所有必要操作,以生成所需的输出。因此,ONNX 不仅可以用于存储复杂的人工智能/人工智能模型(像 TensorFlow 和 PyTorch 这样的流行的人工智能框架将允许您开箱即用),而且还可以在某些特定的上下文中部署经过训练的模型所必需的所有预处理和后处理。因此,我们使用 ONNX 作为 DS / AI 模型和管道的版本控制工具。此外,一旦 ONNX 中的管道可用,就可以很容易地高效部署。

因为在 Scailable,我们经常使用 ONNX,并且因为我们对 ONNX 模型/管道的使用几乎总是(远远)超出简单地将一个合适的模型存储在一个环境中,以便以后在完全相同的环境中使用它,我们经常发现自己处于这样的情况,我们想要检查、改变、测试或合并现有的 ONNX 图。例如,我们经常将图像大小调整添加到现有的视觉模型中,这样所得到的 ONNX 管道就可以用于不同分辨率的相机。然而,在我们看来,现有的onnx.helper API 使用起来有点困难。因此,在内部,我们正在开发(并不断尝试改进)一个用于操作 ONNX 图形的高级 API。今天,我们正在开源我们当前的版本;请下载、探索、追加或提交问题/功能请求。

在本文的剩余部分,我将提供一个sclblonnx python 包的概述,该包旨在使手动操作 ONNX 图变得容易。

基本用法

简单地说,sclblonnx包提供了许多高级实用函数来处理 ONNX 图。我们尝试使用一致的语法,如下所示:

# Import the package
import sclblonnx as so# Assuming we have a graph object g:
g = so.FUNCTION(g, ...)

因此,我们提供了许多函数来操作一个图(并且经常改变该图),这导致了该图的更新版本。常见的功能有:

  • add_node(g, node):向现有的图中添加一个节点(是的,显然你也可以delete_node(g, node))。
  • add_input(g, input):向现有图形添加新输入。您也可以删除或更改输入。
  • add_output(g, output):向现有图形添加新输出。
  • add_constant(g, constant):给图形添加一个常数。
  • clean(g):清理图形;这一点非常重要,因为导出的图形经常会臃肿或者不完全一致。
  • check(g):检查图形是否有效,是否可以运行,是否可以使用 Scailable 部署(后者可以关闭)
  • display(g):使用 Netron 目视检查图形。
  • merge(g1, g2, outputs, inputs):将两个(子)图形合并成一个图形。例如对训练好的模型添加预处理。

请注意, ONNX 图形而不是当您将模型从您最喜欢的培训工具导出到 ONNX 时,存储的唯一内容是一个 ONNX 模型(.onnx文件的内容),它包含图形、用于生成图形的软件/版本的描述。因此,一旦你使用sclblonnx打开一个模型,该包将提取图形,并且,如果你使用该包存储打开的图形.onnx——同样,即使没有编辑该模型——存储的模型将不同于原始模型,因为现在它将由sclblonnx包生成。

一个简单的例子:从头开始创建一个图

介绍软件包的最简单方法是通过示例;我们已经向其中一些人提供了包装本身。第一个例子创建了一个超级简单的 ONNX 图,将两个数相加。

首先,让我们创建一个空图:

g = so.empty_graph()

现在我们有了空图g,我们可以开始向它添加节点、输入和输出:

# Add a node to the graph.
n1 = so.node('Add', inputs=['x1', 'x2'], outputs=['sum'])
g = so.add_node(g, n1) # Add inputs:
g = so.add_input(g, 'x1', "FLOAT", [1])
g = so.add_input(g, 'x2', "FLOAT", [1]) # And, add an output.
g = so.add_output(g, 'sum', "FLOAT", [1])

就这样,我们刚刚创建了第一个正常工作的 ONNX 图。但是,我们可能想清理、检查和尝试它:

# First, let's clean the graph (not really necessary here) 
g = so.clean(g) # Next, lets see if it passes all checks:
so.check(g)# Display the graph
display(g) # Evaluate the graph:
example = {
    "x1": np.array([1.2]).astype(np.float32), 
    "x2": np.array([2.5]).astype(np.float32)
   }result = so.run(g,
    inputs=example,                
    outputs=["sum"])print(result)

最后一行打印3.7,合理。

最后,我们可以存储模型:

so.graph_to_file(g, "filename.onnx")

另一个例子:合并两个现有的图形

也许比创建 ONNX 图来从零开始添加两个数字更有用的是合并两个现有的——可能很复杂——ONNX 图;两个或多个图形的合并就是创建管道的方式。

使用sclblonnx合并相对容易(尽管不可否认可能有我们还没有考虑的边缘情况;我们打开这个包的动机之一是让它在我们自己的用例之外接受测试:如果您发现任何问题,请提交一个问题,并随时提交更改)。这里有一个例子:

# Open the graphs. 
sg1 = so.graph_from_file("resize-image-450x600-300x400.onnx")
sg2 = so.graph_from_file("check-container.onnx")# Merge the two graphs
g = so.merge(sg1, sg2, outputs=["small_image"], inputs=["in"])

上面的代码打开了两个现有的图形。第一个有small_image作为输出,而第二个有in作为输入。这两个图形 a) 共同调整大小和图像, b) 检查图像中的容器是否为空。你可以在这里找到工作示例。

包裹

sclblonnx软件包使编辑、修改、检查和合并 ONNX 图形变得容易。该包仍在开发中;如果您发现任何问题,请分享它们,并提交任何改进。同样,我们认为 ONNX 是存储和管理需要跨设备/平台使用的数据处理管道的好工具。我们希望sclblonnx包有助于提高 ONNX 的实用性。

尽情享受吧!

放弃

值得注意的是我自己的参与:我是 Jheronimus 数据科学院 的数据科学教授,也是scaliable的联合创始人之一。因此,毫无疑问,我对 Scailable 有既得利益;我有兴趣让它成长,这样我们就可以最终将人工智能投入生产并兑现它的承诺。这里表达的观点是我自己的。

使用 Python Streamlit 创建财务规划计算器

原文:https://towardsdatascience.com/creating-financial-planning-calculator-using-python-streamlit-6837460c5863?source=collection_archive---------17-----------------------

照片由 Unsplash 上的 recha oktaviani 拍摄

财务规划在我们的生活中是必不可少的。除了跟踪我们每月的收入和支出,我们能为未来存多少钱以应对多年来的通货膨胀是另一个重要方面。传统的计算器允许我们进行所有需要的计算,并显示数字。但是,如果我们能够在一个图表中直观地显示我们的预测费用和多年来的节省,那就更好了。好消息是 Streamlit 让我们能够构建自己的财务规划计算器,满足所有需求。

在本文中,我们将一步一步地介绍如何使用 Streamlit,一个基于 Python 的开源数据科学应用框架,来创建一个财务规划计算器。Streamlit 是一款简单易学、高度可定制的工具,使我们能够根据自己的需求构建数据应用。

可以使用以下链接访问财务规划计算器的部署版本:

https://share . streamlit . io/teobeeguan/financialplanningcalculator/main/budgetapp . py

如果您希望使用我的代码来跟踪这篇文章,您可以在我的 GitHub Repo 获得完整的源代码。

必备 Python 库

在开始开发过程之前,我们需要确保以下库在我们的机器中可用:

  1. 细流—https://www.streamlit.io/
  2. 阴谋地—https://plotly.com/python/
  3. numpy—https://numpy.org/

计算器应用的开发

1.导入库

首先,我们尝试在程序中导入所有需要的库。

2.设置页面标题

接下来,我们为计算器应用程序创建页面标题(如财务规划计算器)。

第 1–2 行:set_page_config 方法中设置浏览器标签标题。

第 3 行:在我们的应用程序主体中创建一个一级标题。

此时,我们可以尝试运行 Streamlit 应用程序来可视化输出。为此,我们在终端/命令提示符下键入以下命令。

streamlit run YourPythonFileName.py

(注意: 在运行应用程序之前,请确保您已经导航到保存脚本文件的目录。)

我们将看到如下输出:

作者准备的图像

3.创建收入部分

在这里,我们希望获得用户对收入的输入。为此,我们需要一个工资输入字段和另一个税率输入字段。

第 1–2 行:创建一个标题(如月收入)和一个副标题(如工资)。

第 3 行:创建两列,并列放置我们的工资和税率输入字段。 colAnnualSalcolTax 是我们定义的列名。

第 5–6 行:在第一列( colAnnualSal ,使用 Streamlit number_input 方法创建年薪的数值输入字段。我们可以设置最小值为 0.0,格式为一个小数点数字,“ %f ”。

第 7–8 行:在第二列( colTax ),使用 Streamlit number_input 方法创建另一个税率数值输入字段。

第 10–12 行:计算每月实得工资的公式。核心思想是按照进项税率从对我们收入征收的税中扣除工资。接下来,扣除税款后的工资除以 12,这将得出每月的实得工资。

作者准备的图像

4.创建费用部分

现在,我们将转到费用部分。我们将为月租金、每日食物预算、水电费等创建几个输入字段。(您可以根据自己的需要灵活地更改或添加任何相关字段)。

第 1–2 行:创建一个标题,并定义两列来放置我们的输入字段。

第 4 行:-13: 在第一列中,创建三个数字输入字段,分别用于每月租金、每日食物预算和不可预见费用及其相应的子标题。

第 15–23 行:在第二列中,创建另外三个数字输入字段,分别用于每月交通费、每月水电费和每月娱乐预算及其相应的子标题。

第 25–26 行:计算每月 _ 费用和每月储蓄的公式。基本上,我们合计所有的月支出项目,然后从每月的实得工资中减去它们,以获得我们每月的储蓄。

作者准备的图像

5.显示计算的节省

这里,我们希望显示根据我们在脚本中定义的公式计算出的节省。

第 1–4 行:创建一个标题(如储蓄),然后将计算出的实得工资、每月开支和储蓄显示为三个不同的副标题。

作者准备的图像

6.预测节约

此时,我们已经完成了根据当前收入和支出计算储蓄的部分。虽然我们可以选择多年保持我们的生活方式,但这并不意味着我们的开支和储蓄金额在未来几年将保持不变。由于通货膨胀的因素和我们工资/收入的增加,储蓄金额会随着时间的推移而变化。假设我们的生活方式在未来几年保持不变,预测通货膨胀和我们的增量收入如何相互交织以影响我们的财务计划是一件有趣的事情。

我们可以将这一部分分成两部分:

(a)为通货膨胀率和工资增长率创建输入字段,

(b)创建一个图表,显示预测工资、费用和储蓄的趋势

6.1。为通货膨胀率和工资增长率创建输入字段

这里我们将创建几个用户输入字段,以获得他们每年的估计通货膨胀率和工资增长率。为了简化我们的计算,我们假设通货膨胀和工资/收入增长将遵循相同的预计增长率。

第一行:在我们的计算应用程序中创建一条水平线。

第 3–4 行:创建一个标题并定义两列来放置我们的输入字段。

第 5–14 行:在第一列中,使用 number_input 方法创建预测年和通货膨胀率的数字输入字段及其相应的子标题。

每月通货膨胀的计算遵循以下公式:

作者准备的图像

一旦计算出每月的通货膨胀率,我们就开始计算每月的预测累积通货膨胀率。Numpy 为我们提供了两个非常有用的内置方法, np.cumprodnp.repeat ,让我们免于重复计算几个月的累计通胀。 np.cumprodnp.repeat 将给我们一系列按月的通货膨胀率,我们把它赋给一个变量cumulative _ inflation _ forecast。通过将每月费用乘以预测的累积通货膨胀率,我们可以得到一系列从这个月到另一个月的预测费用。

第 15–20 行:在第二列中,使用 number_input 方法为预期年薪增长创建数字输入字段。

每月工资增长的计算如下:

作者准备的图像

几个月内预测的累积工资增长的计算类似于上文详述的通货膨胀。

第 22–23 行:通过从预测工资中减去预测费用来计算每月的预测节省。接下来,使用 NumPy cumsum 方法来计算过去几个月累计的预测储蓄。请注意,我们假设没有额外的储蓄支出。

6.2 创建一个图表,显示预测工资、费用&节省的趋势

上一节已经给出了几个数字序列中所有计算出的预测工资、费用和储蓄。每一个数字序列的图表会给我们一个更清晰的画面,让我们检查我们目前的储蓄是否足以应对未来的通货膨胀。

我们将使用 Python Plotly 库在单个图表中创建三个线图,以根据用户输入的预测年数显示预测的工资、费用和储蓄的趋势。

第 1 行:按预测年数设置 x 轴数值。

第 3–10 行:创建一个**图形对象。使用 Plotly go 为预测工资创建一个线图。分散物体。将预测薪金设置为 y 轴值。使用add _ trace方法将该图添加到图形对象。

第 12–26 行:以类似的方式,使用 go 创建预测费用和预测节省的折线图。分散对象并将它们添加到同一个图表中。

第 27–29 行:使用 update_layout 方法设置整个图表的标题,以及 x 轴和 y 轴的标题。

第 31 行:使用 Streamlit plotly_chart 方法渲染图表。

作者准备的图像

目前,图表显示为空,因为我们还没有在前面创建的输入字段中输入任何输入值。

7.示范

现在,计算器应用程序已经准备好了,我们可以通过输入所有必需的工资和费用条目值来测试它。

作者准备的图像

通过输入上述所有收入和支出的输入值,我们的应用程序将计算并显示当前每月的税后工资、支出和储蓄,如下所示。

现在,让我们开始输入预测年数、预计通货膨胀率和工资增长率。

作者准备的图像

输入上述值后,我们将看到图表中显示的线图。

作者准备的图像

图表显示了未来 5 年的健康储蓄计划。假设年通货膨胀率为 5%,预测工资/收入将远远高于预测费用。预计累计储蓄将逐年稳步增长。

现在,让我们尝试调整年薪增长和通货膨胀率的输入值。

作者准备的图像

这次我们试图假设通货膨胀率是工资增长的两倍。对于我们的储蓄计划,我们将得到一个非常不同的图景。

作者准备的图像

在大约 4 到 5 年的时间里,我们的支出将超过我们的收入,从那时起,我们开始花我们的积蓄。如果我们将预测年份的数量延长至 10 年,则从第 8 年开始,预测节约将变为负值。

作者准备的图像

如果我们多年来有额外的支出或承诺(如抵押贷款、孩子等),我们可以想象更糟糕的情况。这就是为什么在作出任何额外的财务承诺之前,一个适当和仔细的财务规划是至关重要的。

结论

这里介绍的财务规划计算器给我们一个未来收入、支出和累积储蓄的粗略预测。我们可以选择根据我们的需求定制计算器,通过输入更多的输入字段来捕捉用户的收入来源和支出领域。这将导致更精确的投影。从上面的样本结果中,我们还可以了解到,额外的投资计划或额外的收入来源可能对保持健康的财务状况非常有帮助。

另一方面,本文还旨在展示 Streamlit 在开发金融数据应用程序中的一个可能用例。Streamlit 在我们的技术市场中的存在为我们提供了一个简单的平台,可以快速构建和部署任何类型的数据应用程序。

我希望你喜欢阅读这篇文章。

Github

这篇文章的所有源代码都在我的 Github Repo 中。

参考

https://numpy . org/doc/stable/reference/generated/numpy . cum prod . html

https://numpy . org/doc/stable/reference/generated/numpy . cumsum . html

https://numpy . org/doc/stable/reference/generated/numpy . repeat . html

从基因组数据创建生殖艺术 NFT

原文:https://towardsdatascience.com/creating-generative-art-nfts-from-genomic-data-16a48ae4df99?source=collection_archive---------3-----------------------

作者图片

在这篇文章中,我概述了我和 IPFS 在区块链以太坊创建动态 NFT 的旅程,并讨论了科学数据可能的用例。我不讨论静态图像的算法生成(你应该阅读 Albert Sanchez Lafuente 的 neat 一步一步的),而是演示当从浏览器查看 NFT 时,我如何使用 Cytoscape.js、Anime.js 和基因组特征数据在运行时动态生成可视化/艺术。我也不会提供区块链的概述,但我强烈推荐阅读黄一飞最近的帖子:为什么每个数据科学家都应该关注加密。

疫情期间,我被困在家里,我是在我们位于布鲁克林的小公寓阳台上尝试园艺的 1000 万 T4 人之一。日本黄瓜很受我们邻居的欢迎,西红柿很受松鼠的欢迎,但我最喜欢看辣椒生长。这就是我的第一个 NFT 的目标:描绘一个随着时间而成熟的辣椒。

有多少描绘是视觉化的,多少是艺术?这是旁观者的看法。当你花时间仔细检查数据点,崇拜最佳实践,优化从内存使用到午餐订单的一切时,采取一些艺术许可,仅仅因为你喜欢就做出一些东西,这是很好的,这正是我在这里所做的。该描述真实地产生于基因组数据特征,但显然这不应被视为任何种类的严肃的生物学分析。

如果你正在寻找最终的实况结果,你可以在这里查看它,在这里查看 GitHub 上的源代码。

准备基因组数据

这里没有什么新的东西,但为了完整起见,我将快速浏览一遍。我的第一站是访问 NCBI 装配页面,搜索辣椒。我很惊讶地发现了 8 个结果,我想我也许可以创造 8 种不同的辣椒,但在进一步挖掘后,我发现并非所有的数据集都有注释,同一物种有一些重叠。在对那些既有注释又有独特物种的进行过滤后,我得到了 3 个可行的数据集:

  • 辣椒来自 Jo YD 等人【1】与红辣椒
  • 辣椒 baccatum 来自金 S 等人【2】用黄椒
  • 黄灯笼辣椒来自金 S 等人【2】与甜椒

我发现 Dubey 等人[3]的这篇论文 T14 列出了 11 个怀疑与辣椒果实成熟有关的基因组区域,并从补充材料中复制了引物核苷酸序列和长度。

来自 NCBI 的 gff 文件是简单的 tsv 文本文件,列出了一个特征(如基因、mRNA、外显子等)以及开始和结束坐标以及任何其他元数据——参见下面的示例。我们的目标是将这些文件分成子集,只包含那些属于 Dubey 研究中成熟过程所涉及的区域的特征。

NC_029977.1  Gnomon  gene  590985  592488  .  -  .  ID=gene-LOC10...
NC_029977.1  Gnomon  mRNA  619017  620755  .  +  .  ID=rna-XM_016...
NC_029977.1  Gnomon  exon  619829  620755  .  +  .  ID=exon-XM_01...

为了只从那些感兴趣的区域提取 gff 特征,我们需要相应的坐标,这是通过 NCBI 基本局部比对搜索工具( BLAST )实现的。使用这个工具,我们获得了 Dubey 研究中发现的每一个核苷酸序列(例如 GGCATCGT…),并在每种植物的整个基因组序列中查找它——类似于在一本非常大的书中查找特定的短语。

BLAST 确实有一个 web 界面,但我想编写这个步骤的脚本,以便它可以在三个数据集上一致地重复,所以接下来我下载了他们的命令行应用程序。我首先试图通过传递-remote标志来使用 NCBI 服务器进行处理。结果以令人怀疑的速度返回,我没有得到任何点击,但是我发现你还需要通过短序列的-task blastn-short,这似乎在任何地方都没有记录。

blastn -db “GPIPE/4072/100/GCF_000710875.1_top_level” -query dubey.fsa -out results.out -task “blastn-short” -remote

这现在产生了相反的效果——远程进程运行了很长时间,而我得到了Error: [blastn] Failed to fetch sequences in batch mode。此时,我决定对子弹进行字节化处理,并创建自己的 BLAST 数据库来本地运行这个过程。我从同一个 NCBI 页面下载了所有 fna 文件,并编写了一个类似如下的命令:

for g in "${genome_ids[@]}"; do
  for ((i=1;i<=12;i++)); do
    makeblastdb -in datasets/ncbi_dataset/data/${g}/chr${i}.fna
      -dbtype nucl -parse_seqids -out blast/dbs/${g}/chr${i}.blast
  done
done

这被证明是值得的:我重复了 blastn 命令,但没有使用-remote标志,不久后就有了一个坐标列表,报告了成熟过程中涉及的每个基因序列的完美匹配。最后一步是使用一堆 bash 命令(参见源代码)来修剪和格式化数据,因此我为 3 个物种中的每一个留下了一个简单的 3 列 tsv,如下所示——第一列是 Dubey 研究中用于识别该区域的基因位置 ID(总共 11 个不同的 loc ),第二和第三列是 gff 文件中该区域的基因组坐标和特征(有误差)。

LOC107843860 213978278 gene
LOC107843860 213989346 mRNA
LOC107843860 213991885 exon
...

用 Cytoscape.js 生成可视化

几年前,我摆弄过 Cytoscape 桌面应用程序,我一直觉得它生成的网络图形很有美感。显然,我在这里准备的数据绝不是网络,所以这不是一个典型的用例,但我接受了那个创造性的许可并选择了它,因为我喜欢它的外观。

不足为奇的是,Cytoscape.js 需要 JSON 格式的数据,而是什么呢有点令人惊讶的是,它不能像桌面版本那样读取表格(2D 数组)并推断节点和边。相反,我们需要明确地将每个节点和边定义为一个数据对象,如下例所示。

const dataAnnuum = [{
  "data": {
    "id": "6679599"
  }
},{
  "data": {
    "id": "gene"
  }
},{
  "data": {
    "id": "6679599-gene",
    "source": "6679599",
    "target": "gene"
  }
},
...

jq 来拯救:

for g in "${genome_ids[@]}"; do
  for loc in "${loc_ids[@]}"; do
    cat graph/$g-$loc.txt | jq --raw-input --slurp 'split("\n") | map(split(" ")) | .[0:-1] | map( { "data": { "id": .[1] } }, { "data": { "id": .[2] } }, { "data": { "id": (.[1] + "-" + .[2]), "source": .[1], "target": .[2] } } )' >> json/$g.js
    cat graph/$g-$loc.txt | jq --raw-input --slurp 'split("\n") | map(split(" ")) | .[0:-1] | map( { "data": { "id": .[0] } }, { "data": { "id": .[1] } }, { "data": { "id": (.[0] + "-" + .[1]), "source": .[0], "target": .[1] } } )' >> json/$g.js
  done
done

一旦你格式化了你的数据,对我来说唯一的另一个问题是,我需要将构造函数包装在一个DOMContentLoaded监听器中(见下文),但是除此之外,他们的入门例子很好地工作了。

document.addEventListener("DOMContentLoaded", function () {
  cyto1 = cytoscape({
    container: document.getElementById("target"),
    elements: dataAnnuum,
    style: [...],
    layout: {
      name: "circle",
    },
  });
});

Cytoscape.js 为动画提供了一个令人印象深刻的 API,可用于动态设置节点和边的样式(见下文),但也值得注意的是,它有一个完整的视口操作特性集,如缩放和平移,这对于需要单步执行和叙述图表的正确通信可视化来说非常方便。作为一个简单的动画示例,在下面的代码中,我找到了与一种基因特征(基因、外显子等)相关的所有边缘,并改变了颜色,将线条的宽度加倍。

cyto1
  .nodes("#" + geneFeature)[0]
  .connectedEdges()
  .animate({
    style: {
      lineColor: RIPE_COLOR[seqNum],
      width: SKELETAL_WIDTH[seqNum] * 2
    },
  });

用 Anime.js 制作动画

我想让图片更生动一些,但是 Cytoscape.js 的平移和缩放并不是我真正想要的效果。我过去曾和 p5.js 一起玩,这似乎在生成艺术界很流行,但我想借此机会给 anime.js 一个机会,好家伙,我很高兴我这么做了。只需几行代码,我就能拿起包含细胞图的div,并流畅地前后旋转它,轻松地开始和停止。

anime({
  targets: #graph1,
  rotate: [45, -45],
  duration: 10000,
  easing: "easeInOutSine",
  direction: "alternate",
  loop: true,
});

我还使用了倾斜效果,在页面第一次加载时将图形放大。当你需要开始对效果进行计时和排序时,事情会变得稍微复杂一些,anime.js 为此提供了一个时间线特性。当我将所有的动画移动到时间线上时,我发现还有一个简单的complete:选项,可以在每个动画完成时触发一个功能,这被证明是一个对这个简单的动画进行排序的更优雅的解决方案。

在 IPFS 部署

不可替代是一个经济术语,用来描述独一无二且不能与其他同类事物互换的事物。不可替代令牌背后的概念是,它们不仅是唯一的,而且其唯一性可以很容易地通过区块链上的公共记录来验证。当一个数字资产,比如一个静态的“photo.jpg”文件,作为一个 NFT 被添加到以太坊区块链时,一个常见的误解是文件“photo.jpg”的实际字节码被写入一个区块。仅交易和链上数据,以太坊区块链今天就超过了 1TB 的大关,所以你可以想象,如果每个 NFT 的 jpeg、gif 和电影文件都被添加进去,它会迅速膨胀到 Pb 级的数据。鉴于区块链的主要动机是去中心化,如果链增长到这种规模,对于大多数节点来说,维护起来会非常大,留下一个更集中的大盒子网络。

NFT 没有将 NFT 数据文件存储在链上,而是有一个不可变的tokenURI记录指向一个文件。如果这个tokenURI使用位置寻址,例如传统的 web 服务器,例如http://myserver.com/photo.jpg,那么拥有不可撤销的tokenURI记录是没有意义的,如果地址目的地的文件可以被切换出去,这就是一些不高兴的 NFT 所有者所发生的事情。

作者图片

这就是 IPFS 的用武之地。星际文件系统是一个点对点的分布式存储网络,与 BitTorrent 不同,它由遍布全球的计算机组成,存储和共享数据。IPFS 还使用一种名为 FileCoin 的加密货币作为激励层,这样用户就可以因为在电脑上存储数据而获得奖励。这里的关键区别是,IPFS 不像传统的网站那样使用位置寻址,而是使用内容寻址,这涉及到生成文件或目录的散列(“CID”)并使用它进行检索。

Location addressing: [http://myserver.com/photo.jpg](http://myserver.com/photo.jpg)
Content addressing:  ipfs://QmP7u9UzoUtfpiNkj3Sa...

要从 web 浏览器访问 IPFS 内容,您需要使用网关,如 Cloudflare 提供的 ipfs.io ,例如:

https://ipfs . io/ipfs/qmp 7 u 9 uzoutpinkj 3 sal 5 tly m2 ngrufvsinhf 21 uff 3 l 1

对 NFT 数据使用 IPFS 的好处在于,它不仅是分散的和始终在线的,而且如果文件中的一个字节发生变化,CID 也会发生变化。这意味着 NFT 记录的不可变tokenURI总是保证返回完全相同的数据。

在开始将数据上传到 IPFS 之前,还有一个额外的考虑事项:用于显示 NFT 的元数据。与其将 NFT 的tokenURI设置为直接指向 IPFS 上的文件,不如将它指向 IPFS 上的一个元数据 JSON 文件,该文件包含 NFT 的信息,并依次指向源文件以及任何其他文件,如预览图像。因为这个元数据文件也存储在 IPFS 上,所以可以保证它也没有被修改。没有官方的以太坊规范,但是 OpenSea 描述的格式已经成为标准。

作者图片

要将文件上传到 IPFS,你可以下载桌面应用,并使用它上传完整的源目录,包括 index.html、基因组数据、javascript、支持库和预览图像。请注意,index.html 中的文件路径不需要使用内容寻址(IPFS 网关可以在目录级别解析位置寻址),但由于这个原因,它们需要是相对的。

作者图片

现在有了 IPFS 上的数据,然后复制目录和图像预览文件的 CID,并完成 metadata.json 文件中的条目。最后,上传元数据文件并复制将用于 NFT 的 CID。请注意,传递给index.htmltokenId=1001参数只是用作一个序列号,以便单个源代码目录可以根据元数据中引用的 URL 生成 3 个不同的变体(种类)。

{
  "token_id": 1001,
  "name": "Capcicum annuum",
  "description": "This red pepper depiction is generated...",
  "image": "ipfs://QmYpZF5D95THTiF4gVuUuze46eA4SHjwWEZBvFXSn7GE2k/annuum-preview.png",
  "background_color": "fcf5e5",
  "external_url": "[https://nicetotouch.eth.link/peppers](https://nicetotouch.eth.link/peppers)",
  "animation_url": "ipfs://QmYpZF5D95THTiF4gVuUuze46eA4SHjwWEZBvFXSn7GE2k/index.html?tokenId=1001",
  "attributes": [
    { "trait_type": "Species", "value": "Capsicum annuum" },
    ...
  ]
}

IPFS 桌面应用程序实际上是向全世界提供你的文件,所以它们只有在你的电脑运行时才可用。为了确保文件始终在线并复制到其他对等点(而不仅仅是临时缓存),我们需要“固定”它们。有一些不同的锁定服务,但我选择了 Pinata ,它给你 1GB 的免费空间,而且非常简单易用。只需注册,点击上传/添加并粘贴您想要 pin 的 cid。

作者图片

以太坊区块链上的造币

最后一步是通过在区块链上创建一个公共的、可验证的记录来主张你的数据的所有权。有很多像 OpenSea 这样的 NFT 聚合器提供造币服务,但不幸的是,它们只支持创建简单的单文件 NFT,如图像和电影。BeyondNFT 是我发现的唯一一个允许你通过上传 zip 文件来创建动态 NFT 的网站,但在撰写本文时,还不支持创建你自己的智能合约,相反,你必须使用他们的通用总括合约。

为了概念化契约的角色,NFT 的“令牌”部分可以被认为是一个对象类的实例,该对象类是 ERC721 智能契约的实现。智能合约存在于区块链上,并具有一个 mint 函数,该函数使用一组不可变的变量(例如一个tokenIdtokenURI)创建一个唯一的令牌。由于这个原因,从同一个契约创建的所有令牌都被视为一个“集合”并被分组在一起,因此当创建一组 NFT(如本例所示)时,您确实希望使用自己的契约,而不是加入一些您无法控制的现有大型通用集合。

创建你自己的智能合同,然后铸造一个 NFT 需要几个步骤,幸运的是,阿米尔·索雷玛尼在这本精彩的指南中完美地概述了这些步骤。我以前没有使用 Solidity 或部署智能合同的经验,但在这篇文章之后,我在大约半小时内完成了 3 个 NFT。

科学数据的用例

当我在生物信息学领域工作时,我似乎花了大量的时间来检查、再三检查我认为我正在存储、移动或处理的文件是否确实是正确的文件。带有相应文件名、服务器位置和目录路径的样本名称的电子表格,以及“新的”、“最新的”或“已修复的”这些词困扰着我。

如果你混淆了 Word 文档、电子表格或 JavaScript 源文件的命名,你可以很快确定你打开的文件是错误的,但科学数据通常不是这样。样本数据可能是如此密集和同质,以至于除了结果之外,没有简单可靠的方法来区分文件内容,这就是分析,这意味着文件名混淆可能是灾难性的。

这就是内容寻址数据非常有意义的地方。是的,当你有校验和的时候,它们是很棒的,但是要想有用,它们真的需要从数据的来源产生,并携带到数据去的任何地方。然而,通过校验和寻址给了我们一石二鸟的机会:我们可以保证我们下载的是正确的、原始的、未修改的文件,我们还可以在我们这边对它进行校验和,以确保我们已经完全传输了它。

IPFS 的分散性质也非常适合科学数据。学术界很少拥有与企业同等的资源来提供高度可用、高度冗余的数据,具有讽刺意味的是,大多数学术数据都是公开的,是为了公众利益。如果 NCBI 网站今天离线,虽然他们可能会将数据镜像到其他服务器上并备份到磁带上,但如果我无法访问他们的网站,我就无法访问我需要的数据。有了内容地址,我可以直接从 IPFS 下载数据,独立于任何 URL,也不管 NCBI 节点或网关是否关闭。除此之外,点对点组件的操作就像一个内容交付服务,所以当我在处理一个巨大的基因组参考文件时,如果我隔壁的同事想下载相同的数据,他们会自动从我这里直接获得,而不是跨越全球。

IPFS 不太适合科学数据的地方是起源和血统方面,这是区块链和非功能性测试的方向。在最基本的层面上,在高度可访问、完全冗余、安全、分散的服务上拥有不可变的记录来描述一个数据集或多个数据集,为数据科学带来了巨大的价值。当负责拥有数据的实体改变时,可以处理 NFT,并且永久记录历史,并且如果需要更新记录,可以发布具有更新的元数据的新令牌,该元数据包括对旧令牌和旧数据的引用。

在一个更高的层次上,是对一个记录引用和知识产权的新系统的可能应用。我不是一个学者,但在今天的信息时代,期刊出版和引用系统似乎过时和笨重。几年前,理查德·福达·伯利发表了一篇论文,提议建立一个受比特币启发的分散式共享引用分类账。他指出,集中式分类账(如 Scopus 和 Web of Science)是一项大业务,通常“……关于什么被索引和不被索引的重要决定在许多方面都基于经济考虑”,这对于传播科学知识来说是一个问题。想象一下,如果一篇研究论文,连同所有附带的补充材料、数据集和软件被存放在区块链和 IPFS,归作者所有,任何人都可以阅读和复制。索引呢?像 The Graph 这样的项目已经发明了 Dapps(去中心化应用程序)来索引区块链数据,许多人认为我们像今天使用谷歌一样搜索和浏览 Web3(去中心化 Web)只是时间问题。

最后,区块链是记录知识产权的明显匹配,正如去年世界知识产权组织指出的。虽然他们的讨论集中在设计和商标上,但我也设想了一个与这个例子相关的专利申请。再一次,从我对化学实用专利的有限理解来看,专利的很大一部分是描述这项工作,以及它是如何制作的,以及如何重复或复制(“实现”)。想象一下,如果数据在一个去中心化的区块链上被很好地打包并打上时间戳,这个包用于发布和引用,没有利益冲突或国际政治干预,那么专利当局可以简单地指向这个记录让世界看到。

我希望这为如何将动态可视化作为 NFTs 添加到以太坊区块链提供了一些见解,也让你思考 Web3 在数据科学中可能的未来用例。你可以在这里查看最终结果,在这里查看 GitHub 上的源码。

剪贴画

以上所有剪贴画均来自 un draw(https://undraw.co)并在 unDraw 开源许可下使用。

参考文献

[1] Jo,Y. D .,Park,j .,Kim,j .,Song,w .,Hur,C. G .,Lee,Y. H .,& Kang,B. C .,辣椒质体基因组的完整测序和比较分析揭示了辣椒质体基因组上串联重复和大插入/缺失的高频率(2011),植物细胞报告30 (2),217–229。https://doi.org/10.1007/s00299-010-0929-2

[2] Kim S,Park J,Yeom SI 等,辣椒新的参考基因组序列揭示了植物抗病基因的大量进化(2017), Genome Biol 。2017;18(1):210.发布于 2017 年 11 月 1 日。https://doi.org/10.1186/s13059–017–1341–9

[3] Meenakshi Dubey,Vandana Jaiswal,Abdul Rawoof,Ajay Kumar,Mukesh Nitin,Sushil Satish Chhapekar,Nitin Kumar,易勒雅斯·艾哈迈德,Khushbu Islam,Vijaya Brahma,Nirala Ramchiary,辣椒果实发育/成熟相关基因的鉴定和功能标记的开发(2019 年),基因组学,第 111 卷,第 6 期,2019 年,https://doi.org/10.1016/j.ygeno.2019.01.002.

[4]伯利·理查德·福特,稳定而分散?共享引用账本的承诺与挑战(2018),信息服务&使用,第 38 卷,第 3 期,第 141–148 页,2018,https://doi.org/10.3233/ISU-180017

使用 Plotly 创建地理图

原文:https://towardsdatascience.com/creating-geographical-plots-using-plotly-e77401f676c1?source=collection_archive---------22-----------------------

使用 plotly 可视化地理数据

来源:作者

Plotly 是一个创建高级交互图形的开源库,可用于轻松绘制各种类型的图形和图表。

在 plotly 之前,创建地理图从未如此容易。Plotly 在后端使用 JS 来呈现图形。这使得它们具有视觉吸引力和高度交互性。

在本文中,我们将使用 plotly 来创建地理图,并使用其他功能。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装 plotly 开始。下面给出的命令将安装它。

pip install plotly

导入所需的库

在这一步中,我们将导入一些创建图表所需的库,加载数据所需的库等等。

import pandas as pd
from urllib.request import urlopen
import json
import plotly.express as pximport plotly.graph_objects as go

创建地理图表

这是最后一步,我们将使用不同的在线数据集创建不同的地理地图。我们将从创建一个简单的图表开始。

with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
    counties = json.load(response)df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv",
                   dtype={"fips": str})fig = px.choropleth_mapbox(df, geojson=counties, locations='fips', color='unemp',
                           color_continuous_scale="Viridis",
                           range_color=(0, 12),
                           mapbox_style="carto-positron",
                           zoom=3, center = {"lat": 37.0902, "lon": -95.7129},
                           opacity=0.5,
                           labels={'unemp':'unemployment rate'}
                          )
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

地理图(来源:作者)

同样,让我们看看其他类型的图表,我们可以使用 Plotly 创建。

df = px.data.election()
geojson = px.data.election_geojson()fig = px.choropleth_mapbox(df, geojson=geojson, color="winner",
                           locations="district", featureidkey="properties.district",
                           center={"lat": 45.5517, "lon": -73.7073},
                           mapbox_style="carto-positron", zoom=9)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

地理图(来源:作者)

us_cities = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/us-cities-top-1k.csv")
us_cities = us_cities.query("State in ['New York', 'Ohio']")import plotly.express as pxfig = px.line_mapbox(us_cities, lat="lat", lon="lon", color="State", zoom=3, height=300)fig.update_layout(mapbox_style="stamen-terrain", mapbox_zoom=4, mapbox_center_lat = 41,
    margin={"r":0,"t":0,"l":0,"b":0})fig.show()

线条地图框(来源:作者)

fig = go.Figure(go.Scattermapbox(
    mode = "markers+lines",
    lon = [10, 20, 30],
    lat = [10, 20,30],
    marker = {'size': 10}))

fig.add_trace(go.Scattermapbox(
    mode = "markers+lines",
    lon = [-50, -60,40],
    lat = [30, 10, -20],
    marker = {'size': 10}))

fig.update_layout(
    margin ={'l':0,'t':0,'b':0,'r':0},
    mapbox = {
        'center': {'lon': 10, 'lat': 10},
        'style': "stamen-terrain",
        'center': {'lon': -20, 'lat': -20},
        'zoom': 1})

fig.show()

散点图框(来源:作者)

这就是你如何使用 plotly 创建不同的地理图。继续在不同的数据集上尝试,并让我知道您在回复部分的评论。

本文与 皮尤什英加尔 合作。

在你走之前

感谢 的阅读!如果您想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

使用 Voila 创建交互式 Jupyter 笔记本并部署在 Heroku 上

原文:https://towardsdatascience.com/creating-interactive-jupyter-notebooks-and-deployment-on-heroku-using-voila-aa1c115981ca?source=collection_archive---------7-----------------------

使用 Python、Pandas 和 Plotly 分析 Covid 推文

作者图片(使用谷歌绘图创建),结果的折叠视图

最近,我被指派分析一个包含大约 44k 条目的 Covid tweets 数据集,这篇博客描述了我为创建一些漂亮的可视化效果以及最终部署到云平台 Heroku 所采取的所有步骤。部署了整个 Jupyter 笔记本,消除了任何前端编码的需要。

数据集

数据包含日期时间列,这是索引的最佳选择,因为我可以根据日期数据对数据及其子集进行分组。下面是 df.info()返回的内容,考虑到 df 是熊猫读取 CSV 文件的数据框对象:

数据集的所有功能

有 19 列(索引被设置为“created_at ”,它最初是数据集的一部分),除了 hashtags 和 user_description 列之外,大多数列都有非空值,这是有意义的,因为不是每个人都用 hashtags 发推文,也不是所有的推文都有个人资料描述。

经过一段时间的摸索,我发现 language 列只包含' en ',因此我放弃了它。类似地,“id”、“tweet_url”、“user_screen_name.1”也被删除。“用户屏幕名称”和“用户屏幕名称. 1”是相同的列。

数据预处理

略述之后,是时候将数据转换成更好的形式了:

时区转换:我住在印度,我的时区是 GMT+5:30。数据集具有 UTC 时区,这使得执行日期时间分析变得困难。例如,如果不进行转换,推特的高峰时间是早上 6 点,但实际上是 11 点。我是这样做的:

UTC 到 IST 的转换

清理推文:推文通常包含标签、提及、链接和照片。从 Twitter API 获取数据时,照片被替换为一个链接。所有这些额外的材料都需要被移除,以获得良好的词云和高效的情感检测。我创建了以下函数来消除这种干扰,停止单词和标记化:

Tweets 清理功能

获取地点的坐标:有一个名为“地点”的栏目,告诉我们这条推文是从哪里发出的。这给了我一个在地图上绘制它们的绝佳机会,但唯一的问题是我需要可以传递给任何 Mapbox 库的这些地方的准确纬度和经度。经过一番搜索,我找到了一个网站,通过请求他们的端点来提供坐标。这是一个简单的函数:

函数来获取任意地址的坐标

制作交互式可视化

在最后一个笔记本里,我做了很多可视化,在这里描述每一个都要花很长时间。我会解释其中一些不同之处。所有的图表、数字都是用 Plotly 制作的。

图表:生成表示定性数据计数的静态条形图要容易得多。Plotly 为图表提供了广泛的定制。为了提高交互性,我使用 ipywidgets 来获取用户输入并控制图表的流程。例如,为了以条形图的形式显示 tweets 排名靠前的地方,使用了以下代码:

px 是 plotly express 的别名。

displayPlaces 函数采用参数“top ”,该参数控制绘制条形图时要考虑多少个前 X 位。interact 函数是 ipywidget,它自动创建用户界面控件。更多功能参见文档。下面的 gif 是为了更好的理解:

显示条形图交互性的 GIF

地图绘制:我个人喜欢这种可视化,因为它挑战我探索更多关于 Plotly 的东西。最初,我用 leav 绘制了这个图,结果令人满意,但是用 Plotly,你可以在底图上添加更多的图层,让它看起来更惊人。获取坐标是预处理时解决的一个大任务。以下是获取地理地图的步骤:

px.scatter_mapbox 获取位置坐标、可选的色标、缩放和高度参数。update _ layout map box _ style“carto-dark matter”使地图变暗。查看生成的地图:

表示地图绘图的 GIF

更多类型的绘图可参考 Plotly 文档。

单词云:这些是用一串单词描述文本信息/段落中整体趋势的图像。这些图片乍一看很酷,但大多数都是带有文字的矩形图像。为了使它更吸引人,我们可以把这些话放在图片上!没错,你可以用一个图像作为蒙版,这些文字将被强加于其上,它的实现更容易。将图像作为 numpy 数组加载,并将其作为遮罩参数传递给 word cloud 函数。词云函数来自库词云。

示例单词云

我加大了赌注,让它以用户为基础。用户可以选择屏蔽(可用选项:Modiji、Trump 和 India Map)和语料库(tweets 数据或用户描述),从中挑选单词。

部署 Jypter 笔记本

如果你读过我的“分析 WhatsApp 群聊&构建 Web 应用”的文章,那么你一定知道我必须为这个项目创建整个前端,如果知道就好了。

Voila 是一个 Python 包,它可以将我们的 Jupyter 笔记本变成一个独立的 web 应用程序。这意味着笔记本将作为网站呈现给用户,并且笔记本的单元格将被优先执行。它还提供了选择主题的功能,我选择了深色。下面是本地测试 voila 的过程:

pip install voila
pip install voila-material (optional)

安装后,只需在任何终端中运行该命令(假设您导航到了保存笔记本的文件夹,否则请输入笔记本名称的完整路径):

voila nameofnotebook.ipynb 

然后嘣!你有一个网站运行在你的本地主机上,也就是你的笔记本上!您可以在笔记本中添加 HTML 代码作为 markdown,使其更具创造性。要更改网站的主题,只需在运行 voila 命令时传递 theme=dark:

voila --theme=dark nameofnotebook.ipynb 

要将它部署在云上,以便其他人可以查看您的项目,有许多选择:

Heroku :只需在 Heroku 中创建一个新的应用程序,连接您笔记本所在的 GitHub repo。在 Procfile 中,可以使用此命令来避免任何错误:

web: voila --port=$PORT --no-browser --template=material --enable_nbextensions=True nameofnotebook.ipynb

活页夹:更简单的方法是使用名为活页夹的服务,它会为你的回购创建一个 docker 映像,每次你想运行你的笔记本时,你只需在活页夹上启动它。

截图来自 mybinder.org

这里要提到的一件重要事情是,在笔记本文件的路径中,从下拉列表中选择 URL,然后将 voila 端点粘贴为:

voila/render/path-to-notebook.ipynb

"请注意,如果您的笔记本使用任何外部库,您的 Git 存储库中需要有一个 requirements.txt 文件,该文件可以通过 pip 安装。如果没有,将会出现诸如 404:笔记本找不到"的错误

决赛成绩

由于 voila 支持,笔记本电脑的部署变得非常容易。我已经在这两个平台上部署了我的最终分析笔记本,我想在这里提到的一点是,由于我的笔记本是资源密集型的,它通常会溢出 Heroku 内存限制(512MB ),当它达到 200%时,笔记本无法正常呈现。我没有遇到很多活页夹的问题,但是加载图片需要更多的时间。在任何平台中,我的最终笔记本看起来都是这样的:

作者 GIF

整个预处理、仪表板笔记本文件和部署的笔记本链接都可以在我的 Github 存储库中找到:

https://github.com/kaustubhgupta/Covid-Tweets-Analysis-Dashboard

结论

有许多功能都是为分割工作负载而构建的。这种部署有助于更轻松、更交互地与外部世界共享结果。

这就是关于这篇文章的全部内容,我希望你能从这篇文章中学到一些新的东西。再见!

我的 Linkedin:

https://www.linkedin.com/in/kaustubh-gupta

其他热门文章:

用 Python 创建交互式雷达图

原文:https://towardsdatascience.com/creating-interactive-radar-charts-with-python-2856d06535f6?source=collection_archive---------18-----------------------

用 Plotly 实时绘制交互式雷达图

作者视觉

介绍

也许数据可视化的无名英雄之一是仁慈而优雅的雷达图。举几个例子,我们已经习惯了一大堆其他的可视化,choropleths,甜甜圈和热图,但是雷达图在我们眼花缭乱的仪表盘上基本上不见了。当然,这种图表只有特定的用例,即可视化风玫瑰图、地理数据和一些其他类型的多元数据。但是当您使用它时,它在可视化数值和有序数据集中的异常值或共性方面非常有效。

在本教程中,我们将生成一个带有交互式动态雷达图的仪表板,它将实时呈现。为此,我们将使用 Plotly 和 Streamlit 作为我们强大的 Python 堆栈。如果您还没有这样做,请启动 Anaconda 或您选择的任何其他 Python IDE,并安装以下软件包:

pip install plotlypip install streamlit

然后继续将以下包导入到脚本中:

Plotly

Plotly 是目前市面上最通用、最具交互性的数据可视化工具之一。它配备了 Python 和 R 的绑定,与仪表板的集成是无缝的。Plotly 能够生成交互式雷达图,对开发人员来说几乎没有任何开销。您需要做的就是输入一个与每个变量的值相对应的数字数组,剩下的就交给 Plotly 了,如下所示:

细流

对于我们的仪表板,我们将使用 Streamlit 。长话短说,Streamlit 是一个纯粹的 Python web 框架,它将仪表板实时呈现为 web 应用程序。一旦您的仪表板准备好了,您可以将它端口转发到您的本地 TCP 端口之一,并在您的浏览器上打开它。或者,如果你有兴趣,可以使用 Heroku、AWS 或 Streamlit 自己的一键式部署服务将仪表盘部署到云中。

对于 Streamlit 仪表板,我们将创建一个滑块,使我们能够向 radar_chart 函数中输入任何值。

脚本完成后,您可以通过打开 Anaconda 提示符并键入以下命令来呈现 dashboard/app。

最初,将目录更改为脚本的位置:

cd C:/Users/.../script_directory

然后通过键入以下命令运行您的应用程序:

streamlit run script_name.py

然后,Streamlit 将自动生成您的应用程序,并将其转发到您的本地主机,您可以在您选择的任何浏览器中打开它。

结果

现在你有了一个交互式雷达图,你可以通过修改滑块的位置来改变可视化显示的值。

作者图片

您还可以使用 Plotly 提供的所有交互式铃声和口哨声。

作者图片

如果您想了解更多关于数据可视化和 Python 的知识,请随时查看以下(附属链接)课程:

使用 Streamlit 开发 Web 应用程序:

https://www.amazon.com/Web-Application-Development-Streamlit-Applications/dp/1484281101?&linkCode=ll1&tag=mkhorasani09-20&linkId=a0cb2bc17df598006fd9029c58792a6b&language=en_US&ref_=as_li_ss_tl

使用 Python 实现数据可视化:

https://www.coursera.org/learn/python-for-data-visualization?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW2aEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

面向所有人的 Python 专业化:

https://www.coursera.org/specializations/python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW16Ewvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c

GitHub 资源库:

https://github.com/mkhorasani/interactive_radar_chart

新到中?您可以在此订阅和解锁无限文章。

使用 Python Altair 创建交互式散点图

原文:https://towardsdatascience.com/creating-interactive-scatter-plots-with-python-altair-e4b47e0aa8eb?source=collection_archive---------6-----------------------

增强数据可视化的信息能力

照片由 IIONA VIRGIN 在 Unsplash 拍摄

数据可视化是数据科学不可或缺的一部分。我们创建数据可视化来获得手头数据的结构化概览。它们也是交付成果的有效工具。

因为这是一个如此重要的主题,所以有各种各样的软件工具和软件包来创建数据可视化。

其中之一是 Altair ,它是 Python 的一个声明性统计可视化库。

在本文中,我们将学习如何用 Altair 创建交互式散点图。交互式绘图能够提供比标准绘图更多的信息。它们还允许增加可视化的灵活性。

如果你想在我发表新文章时收到电子邮件,别忘了订阅。

当然,首要的要求是数据集。我们将在 2021 年 7 月 7 日使用来自西班牙巴塞罗那的 Airbnb 房源数据集。它是与知识共享许可共享的,所以你可以自由地使用和探索它们。

让我们从导入库和创建熊猫数据框开始。

import pandas as pd
import altair as altcol_list = ["accommodates", "instant_bookable", "room_type", "reviews_per_month", "price"]df = pd.read_csv(
    "listings_2.csv",
    usecols = col_list,
    nrows = 1000
)df.dropna(inplace=True)print(df.shape)
(965, 5)df.head()

(图片由作者提供)

原始数据集中有 17k 行和 74 列。我们通过使用read_csv函数的usecolsnrows参数创建了一个仅包含 5 列 1000 行的数据框。

值得注意的是,在默认设置下,Altair 最多可以使用 5000 个观测值(即行)。可以使用以下命令禁用此限制。感谢 Natalia Goloskokova 的提醒!

alt.data_transformers.disable_max_rows()

我们还使用了dropna函数来删除缺少值的行。

在我们开始创建散点图之前,还有一个数据处理操作。价格列以对象数据类型存储,但需要转换为数字格式。

我们需要删除用作千位分隔符的“$”符号和“,”符号。然后,我们可以将其转换为数值数据类型。

df.loc[:, "price"] = \
df.loc[:, "price"].str[1:].str.replace(",","").astype("float")df = df[df["price"] < 1000]df.head()

(图片由作者提供)

散点图

散点图通常用于可视化两个连续变量之间的关系。它们概述了变量之间的相关性。

我们可以创建一个散点图来检查 accommodates 和 price 列之间的关系。容纳栏是一个地方容量的指标,所以我们预计它与价格正相关。

alt.Chart(df).mark_circle(size=50).encode(
    alt.X("accommodates"),
    alt.Y("price"),
    alt.Color("room_type", 
              legend=alt.Legend(
                  title="Room Type",  
                  orient='left',
                  titleFontSize=15,
                  labelFontSize=13)
             )
).properties(
    height=350, width=500
).configure_axis(
    titleFontSize=20,
    labelFontSize=15
)

第一步是将数据框传递给顶级图表对象,然后我们指定可视化的类型。mark_circle功能创建一个散点图。

encode函数中,我们写下要绘制在 x 和 y 轴上的列名。color参数用于区分图例上显示的不同类别。类似于 Seaborn 中的hue参数。

最后,propertiesconfigure_axis功能调整图形和标签大小等视觉属性。

该代码片段创建了以下散点图:

(图片由作者提供)

这是一个标准的散点图。我们现在将看到如何以几种不同的方式使它具有交互性。

互动功能

互动功能是使情节互动的最简单的方法。它允许在图上放大和缩小。

让我们通过添加 size 属性来增强上一个示例中的绘图。我们将分别在 x 轴和 y 轴上使用每月容纳量和每月评论数列。

颜色将指示房间类型,每个点的大小将与价格成比例。

通过在最后添加interactive功能,我们将能够放大和缩小。

alt.Chart(df.sample(100)).mark_circle(size=50).encode(
    alt.X("accommodates"),
    alt.Y("reviews_per_month"),
    alt.Color("room_type", 
              legend=alt.Legend(
                  title="Room Type",  
                  orient='left',
                  titleFontSize=15,
                  labelFontSize=13)
             ),
    alt.Size("price",
            legend=alt.Legend(
                  title="Price",  
                  orient='left',
                  titleFontSize=15,
                  labelFontSize=13))
).properties(
    height=350, width=500
).configure_axis(
    titleFontSize=20,
    labelFontSize=15
).interactive()

我从我们的数据框中抽取了一个包含 100 个观察值(即行)的样本,以使该图看起来更有吸引力。这是我们的第一个互动情节。

(作者 GIF)

交互式图例

互动性也可以用来制作更具知识性和功能性的剧情。例如,我们可以通过使图例具有交互性来将其用作过滤器。

我们可以通过创建一个选择对象并将其绑定到图例来实现。

selection = alt.selection_multi(fields=['room_type'], bind='legend')alt.Chart(df).mark_circle(size=50).encode(
    alt.X("accommodates"),
    alt.Y("price"),
    alt.Color("room_type", 
              legend=alt.Legend(
                  title="Room Type",  
                  orient='left',
                  titleFontSize=15,
                  labelFontSize=13)
             ),
    opacity=alt.condition(selection, alt.value(1), alt.value(0))
).properties(
    height=350, width=500
).configure_axis(
    titleFontSize=20,
    labelFontSize=15
).add_selection(
    selection
)

与之前的散点图相比,有 3 处变化。

  • room_type列上的选择对象。它必然与传说有关。
  • 根据所选房间类型更改点的不透明度的“不透明度”参数。
  • 用于将选择对象添加到我们的绘图中的add_selection功能。

结果如下:

(作者 GIF)

具有多个图的交互式图例

牛郎星允许连接一个传说到多个支线剧情。因此,我们可以同时看到我们的选择对不同关系的影响。

selection = alt.selection_multi(fields=['room_type'], bind='legend')chart = alt.Chart(df).mark_circle(size=50).encode(
    y='price',
    color='room_type',
    opacity=alt.condition(selection, alt.value(1), alt.value(0))
).properties(
    height=200, width=300
).add_selection(
    selection
)chart.encode(x='reviews_per_month:Q') | chart.encode(x='accommodates:Q')

我们首先创建一个图表对象,但没有指定 x 轴的列。创建和绑定选择部分是相同的。在最后两行中,我们添加了两个不同的 x 轴,并用“or”(|)运算符将它们组合起来。

我已经删除了用于格式化图例和轴标题的部分,使代码看起来更容易理解。

(作者 GIF)

结论

我们已经介绍了如何使用交互性来增强数据的可视化。就交互性组件而言,Altair 的功能更多。一旦您理解了交互性的概念,如选择、绑定和条件,您就可以创建令人惊叹的数据可视化。

别忘了 订阅 如果你想在我发表新文章时收到电子邮件。

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果您使用以下链接,我将收取您的一部分会员费,无需您支付额外费用。

https://sonery.medium.com/membership

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

使用 JoyPy 创建快乐图

原文:https://towardsdatascience.com/creating-joy-plots-using-joypy-67327a15eb50?source=collection_archive---------21-----------------------

使用 JoyPy 创建一系列堆积直方图作为 Joy 图

来源:https://scrapbox.io/pycoaj/JoyPy

可视化是发现洞见的核心部分,可用于讲故事。在创建可视化时,我们需要考虑使用哪个情节,考虑哪些功能,将会出现什么故事,或者找到根本原因分析。你有没有被这些问题困住过?

有不同的 python 库可用于数据可视化。在本文中,将讨论一种罕见的情节类型,称为欢乐情节。它们是一系列直方图、密度图或时间序列数据,其中我们通过固定 X 轴上的数据点并在 Y 轴上创建堆栈来创建堆栈可视化。

在本文中,我们将探索 JoyPy,这是一个用于创建 Joy Plots 的开源 python 库。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装 Joy Plots 库开始。下面给出的命令可以做到这一点。

!pip install joypy

导入所需的库

在这一步中,我们将导入加载数据集和可视化数据集所需的库。

import joypy
import seaborn as sns

正在加载数据集

对于本文,我们将使用著名的“Tips”数据集,它已经在 seaborn 库中定义。

df = sns.load_dataset('tips')
df

数据集(来源:作者)

创建快乐情节

现在,我们将从使用不同列的数据创建不同类型的快乐图开始。

fig, axes = joypy.joyplot(df)

来源:作者

该图显示了数据集中所有数字列的分布。

fig, axes = joypy.joyplot(df, by="smoker")

来源:作者

此图显示了数值列相对于吸烟者列的分布。

fig, axes = joypy.joyplot(df, by="size", ylim='day')

来源:作者

fig, axes = joypy.joyplot(df, by="day", overlap=10)

来源:作者

继续尝试不同的数据集,并使用 JoyPy 创建不同的可视化效果。如果您发现任何困难,请在回复部分告诉我。

本文是与皮尤什·英加尔合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

使用 BigQuery 和 Dataflow 轻松创建 ML 数据集

原文:https://towardsdatascience.com/creating-ml-datasets-with-ease-using-bigquery-and-dataflow-121eef01f53a?source=collection_archive---------13-----------------------

放弃内存处理,支持并行执行和水平扩展

TL;DR:如果你正在处理大量数据,谷歌云平台(GCP)上的 BigQuery 和 Dataflow 可以提高你的效率,让你在为机器学习生成数据集时更加轻松。

最近,初创公司 reviewr.ai 找到我,让我完成一项数据工程任务,包括为机器学习(ML)准备数据和训练 ML 模型。大公司显然可以让他们的数据科学家花上几天或几周的时间来完成这样的任务,因为他们必须与本地基础设施或云提供商合作,选择云提供商主要是因为该公司多年来一直在许可其 office 套件,与大公司不同,初创公司希望快速完成任务——速度很重要。与许多公司不同,初创公司在选择特定任务的基础设施时通常非常灵活。因此,我们同意应该在 GCP 上完成这项工作,在我看来,它仍然是大数据和 ML 的最佳云平台。因此,我没有花几天时间,而是在一个上午做了所有的数据准备,并在训练 ML 模型的时候休息了一个下午。

本文不是关于任务的机器学习部分或 ML 模型的准确性。它是关于在机器学习开始之前必须发生的数据工程和预处理。大多数数据科学家可能会同意,这通常是花费大部分时间和精力的地方。

令人惊叹的任务

我被要求使用来自拥抱脸的亚马逊 _ 美国 _ 评论数据集来训练一个简单的 NLP 分类模型。它包含来自亚马逊网站的近 1.51 亿条顾客评论,总计约 76 GB 的数据。基于用户写的产品评论,该模型应该将评论分成特定的类别。类成员资格(标签)可以从数据集中包含的数据中导出。因为这个问题很标准,而且我们想要快速的结果,我在 GCP 上使用了 AutoML 。

为了能够使用 AutoML 中的数据,我必须以某种方式从 1 . 51 亿个样本中选择最多 100 万个合适的样本,并将它们转换为所需的格式,即每个样本一个文本文件,其中包含评论文本以及一个索引 CSV 文件,其中包含所有样本的 URIs 和类别。听起来令人畏惧或耗时?都不是。

BigQuery:全进

让我们从获取数据副本开始。这些文件存储在 AWS S3 存储桶中,可以通过 HTTP 请求公开访问。在我们进一步处理它们之前,谷歌云存储 (GCS)是放置它们的合适地方。具体来说,我将把数据吸收到 BigQuery 中,其原因稍后将变得显而易见。有几种方法可以将数据传输到 GCS——例如,使用 bash 脚本wget s 或curl s 文件,然后gsutil cp s 循环地将它们传输到 GCS,或者使用小的 Python 脚本。

我在云外壳中运行这个程序,而不是在我的本地机器上,因为通过谷歌网络传输数据花费的时间要少得多。一旦所有文件都在 GCS 桶中,我只需使用bq将它们一次性加载到 BigQuery 中,仍然来自云 Shell:

bq load --source_format CSV --autodetect --field_delimiter tab 
--skip_leading_rows 1 --quote ' ' [DATASET_NAME].amazon_us_reviews gs://[BUCKET_NAME]/datasets/amazon-us-reviews/raw/*.tsv.gz

通过查看标志可以看出,我让 BigQuery 从数据中推断出模式,并将字段分隔符设置为制表符而不是逗号,将引号字符设置为 none 而不是双引号(“制表符分隔,没有引号和转义符”,如数据集描述所述)。BigQuery 本身可以处理 gzipped 文件,所以我们不必先解压缩文件。

几分钟后,数据存储在 BigQuery 中,并准备好接受检查:

附带说明:如果您有一个 AWS 帐户(因此可以创建一个访问密钥 ID 和一个秘密访问密钥,您可以使用存储传输服务下载文件,甚至可以使用 BigQuery 数据传输服务将数据直接导入 BigQuery。

接下来,让我们运行几个查询来感受一下数据。例如,我们可以询问每个产品组和星级有多少评论,以及星级在产品组中的百分比是多少:

或者:哪些产品类别平均获得的评论最长?

顺便说一下,最短的是礼品卡,这可能不会让人感到意外。

如您所见,在 1 . 51 亿行上运行这些查询只需要几秒钟。因此,你可以尽情发挥你的创造力,在你提出问题的时候尽快分析数据。(但是,请记住,你是按照处理的数据量向收费的,除非你选择统一价格模式。)如果你想绘制结果,只需点击一下鼠标,就可以在数据工作室中看到它们。

从数据集中选择训练数据

然而,我们不只是想分析数据。我们还希望为 AutoML 生成训练数据集,这意味着从总共 1.51 亿个样本中选择 100 万个样本并计算特征。我不想透露 reviewr.ai 到底想让我做什么,所以让我们假设我们想从评论机构推断评级(1-5 颗星)。理想情况下,在这种情况下,每个类有 200,000 个例子。

首先,我们将排除所有没有审核主体的审核(即WHERE review_body IS NOT NULL)。此外,我们必须排除具有相同 review_body 的行,因为基本事实中的分类可能会变得模糊,而且 AutoML 不允许重复。事实证明,有很多这样的例子:

厉害!

为了进一步缩小结果范围,我们将关注大多数用户认为有帮助的评论。此外,我们将要求一个评论收到至少 x 票。在哪里设置阈值,x?让我们制作一个统计图,感受一下每个评分的投票数是如何分布的:

如果我们将阈值设置在 10 到 20 之间,我们似乎仍然有足够的样本用于每一类,所以我选择 15。这意味着我们只包括至少获得 15 票的评论,其中大多数被认为是有帮助的。当然,我们可以更进一步,要求每个产品类别都应该有平等的代表性。出于本文的目的,我们将它留在这里。因此,下面是最终定义数据集的查询:

运行一个快速的SELECT class, COUNT(*) FROM ... GROUP BY class确认我们每个类确实有 200,000 个样本。

一旦我们对我们的查询感到满意,我们就可以运行它并将结果具体化为一个表,或者将查询本身保存为一个视图。加载表将比查询视图更快(这基本上与运行查询本身是一样的)。尽管如此,我还是选择创建一个视图,因为我们只需要查询一次或几次,所以速度并不重要。该视图的优点是记录了数据集是如何创建的,并且如果您想要为另一个模型迭代创建新的数据集,您可以很容易地修改它并以不同的名称保存它。

那么,现在我们通过 SQL 查询得到了训练数据集的定义——我们如何将它转换成我们需要的格式(每个示例一个包含评论正文的文本文件,加上一个包含所有示例的 URIs 和类的 CSV 文件)?将查询结果导出为 CSV 文件,并编写 Python 脚本来逐行处理该文件?这将花费一两个永恒的时间(处理,而不是写剧本)。相反,让我们转向另一个专门用于这种工作负载的伟大工具:GCP 上的 Apache Beam 和 Dataflow 。

无与伦比的并行执行速度

引用文档,“Apache Beam 是一个开源的统一模型,用于定义批处理和流数据并行处理管道”。Dataflow 是 GCP Apache Beam 的一个完全托管的跑步者。通常的工作流程是这样的:编写您的管道(用 Java 或 Python),用一些元素在本地测试它以验证它的工作,然后将其部署到数据流以在云中大规模处理整个数据集。

Apache Beam 有一组 I/O 连接器(“源”和“接收器”),其中一个用于 BigQuery,一个用于 GCS。这意味着我们可以直接从 BigQuery 查询结果中读取,并将输出写入 GCS bucket。从概念上讲,我们将要构建的管道如下所示:

管道从一个源(BigQuery 查询结果,包含 review_id、review_body 和类)读取数据,并生成两个输出:第一个分支使用 review_body 创建 100 万个文本文件,第二个分支创建 100 万个包含 URI ( gs://...)和类的字符串,然后将它们连接起来并将结果写入一个 CSV 文件。管道以每行为基础进行操作。也就是说,每个元素都是查询结果中的一行。

以下是完整的管道代码:

使用 Apache Beam 的好处在于,因为查询结果的每一行都可以独立处理,所以我们实现了大规模并行处理。正如您在下面看到的,Dataflow 确实将工作线程的数量扩展到了 527 个,每秒处理大约 2,200 行:

工作所需的基础设施得到全面管理。在开始实际的管道执行之前,Dataflow 需要花几分钟来配置基础设施(计算引擎)。作业成功完成(或失败)后,它会降速并删除虚拟机。

由于并行执行,相当于 72 个 CPU 小时的工作仅用了大约 18 分钟就完成了。一个重要的注意事项:数据流扩展工作负载的程度可能会受到配额的限制。特别是,在新创建的 GCP 项目中,Compute Engine API in-use IP addresses配额(默认为每个区域 8 个)会限制为作业提供的计算实例数量(因为每个工作实例都需要一个 IP 地址)。因此,如果您发现现有配额过低,请务必提前请求增加配额。

现在我们有了:100 万个文本文件和一个 CSV,准备导入 AutoML。

工作证明

外卖食品

现在,准备这个数据集的麻烦已经消失在云中,让我们得出一些结论:

  • 水平而不是垂直缩放。我认识的许多数据科学家都专注于垂直扩展。不符合记忆?让我们得到一个有更多内存的更大的实例。然而,在坚持内存处理的同时,仅仅投入更多的内存来解决问题,会失去并行工作负载的优势,从而在更短的时间内完成更多的工作。对于 BigQuery 中的数据分析,我不必花一秒钟考虑它需要多少内存——我只需打开 BigQuery UI 并开始查询。我的数据流工作的工人都是 n1-standard-1 虚拟机,带有 1 个 vCPU 和 3.75 GB 的内存。唯一可能面临内存瓶颈的实例是在将一百万行写入文本文件之前收集并连接它们的工作人员。在这种情况下,产生的字符串使用了 123 MB,所以根本没有达到限制。如果我们这样做,我们只会创建分片文件,而不是一个单一的文件。
  • 使用 GCP 的专业数据工程工具。为什么每次想使用 Jupyter 笔记本时都要麻烦地启动它并将数据加载到 pandas 中呢?相反,您可以将数据转储到 BigQuery 中,并在那里保存数据,使您可以随时查询数据。当 Jupyter 实例完成旋转,并且已经将所有数据加载到 pandas 数据帧中时,您可能已经完成了 BigQuery 中的数据分析。当然,你仍然可以使用 Jupyter 毕竟它对于数据科学任务有其优点。但是使用它来查询 BigQuery 和编写 Apache Beam 管道,而不是处理内存中的数据。顺便说一句:也有很多现成的数据流模板,所以你甚至可以不用写自己的管道。
  • 精益和可重用流程。使用 BigQuery 和 Apache Beam 的工作流是精简和灵活的。需要另一个具有不同功能的训练集吗?只需编写所需的查询,启动管道,20 分钟后,您就已经将新数据集导入到 AutoML 中了。如果我们想用相同的数据集在 TensorFlow 中训练自己的模型呢?稍微修改一下 Apache Beam 管道,输出 TFRecord 文件,就可以了。
  • 高效利用基础设施。使用这些工具不仅可以节省时间,还可以降低基础设施的使用成本。由于 BigQuery 和 Dataflow 都是无服务器的,因此不存在未充分利用或过度利用的基础设施,也没有固定成本(当然,除了存储成本之外,存储成本在大多数情况下可以忽略不计)。考虑到工作负载的短暂性和所需的有限财政承诺,您可能会考虑使用 GCP 来完成这种数据工程任务,即使它不是您的默认主力。

使用 Streamlit 创建多页面应用程序(高效!)

原文:https://towardsdatascience.com/creating-multipage-applications-using-streamlit-efficiently-b58a58134030?source=collection_archive---------2-----------------------

由miko aj在 Unsplash 拍摄的照片

实践教程

使用面向对象编程,而不是条件编程。

你有多少次有一个伟大的 ML 项目想法,你认为你可以在你的简历上炫耀?你快速收集数据,分析数据,并在此基础上建立模型;所有这些都在一个 Jupyter 笔记本中,然后你面临你最糟糕的噩梦——有人要求你部署模型并用一个用户友好的界面显示推理。如果你独自工作,这有时真的会令人生畏,为什么不呢?你是一个数据科学家,而不是一个网络开发人员!这就是细流 的用武之地。这是一个非常棒的工具,它可以让你快速构建交互式 web 应用程序,并用图形展示你的模型,这可能会让许多开发人员感到羞愧。

Streamlit 最棒的一点是,你甚至不需要了解 web 开发的基础知识就可以开始工作,甚至不需要创建你的第一个 web 应用程序。因此,如果你对数据科学感兴趣,但因为不喜欢 web 开发而不愿意部署你的模型,那么这就是你只用 Python 构建漂亮的数据应用程序的机会!

有许多资源可以教你如何开始使用 Streamlit。我个人最喜欢的是这个。然而,一旦你开始,你很快就会意识到仅仅构建一两个页面是不够的,一个好的应用程序会有更多的页面,这就是构建多页面应用程序的需要。所以,我决定把它写下来。在本文中,我将带您构建您的第一个多页面 Streamlit 应用程序并部署它。先决条件是了解 Python 和 Streamlit 的基础知识。

编辑:Streamlit 社区成员非常友好地让我在 Streamlit 共享平台上展示我的应用程序,所以我在那里部署了它。现在任何人都可以实时测试。你可以在这里找到应用。

代码概述

在这一节中,我将带您浏览我做的一个项目,在这个项目中,我实现了 Streamlit 的多页面功能 。现在,这个不是使用一个if-else方法完成的,在这个方法中,我一直检查用户选择了streamlit.selectbox()的哪个条目,并相应地显示页面。这个方法看起来有点像这样。

import streamlit as st# Create a page dropdown 
page = st.selectbox("Choose your page", ["Page 1", "Page 2", "Page 3"]) if page == "Page 1":
    # Display details of page 1elif page == "Page 2":
    # Display details of page 2elif page == "Page 3":
    # Display details of page 3

虽然上面的方法没有错,但我发现它非常烦人,因为我必须管理这么多的if-else和其中的代码。作为程序员,我们应该能够编写更整洁的应用程序,并在任何需要的地方使用面向对象编程。这就是我在这里要做的!

我制作的应用程序被称为“DataSpeare”(我知道这是一个糟糕的文字游戏),它是一个基于人工智能的工具,为非技术用户自动化数据分析和机器学习的过程。它可以获取数据集,识别数据中的模式,解释结果,然后基于问题的上下文生成业务用户可以理解的输出故事。该应用程序的功能如下

  • 根据给定的数据将数据转化为交互式数据故事
  • 产生深刻的见解,推断模式并帮助业务决策。
  • 提供个性化配置文件;这些可以表示为描述给定用户感兴趣的内容的元数据。
  • 使用交互式直观界面生成业务用户可以理解的报告。

你可以在这里阅读更多关于应用的内容。如果你想获得项目的源代码,那么你可以去 GitHub 仓库。在这篇文章中,我不会介绍整个应用程序,因为它有一个很大的代码库,但我会介绍它的基本结构。

首先,您需要将 Streamlit 安装到您的设备上。就个人而言,我会推荐使用虚拟环境,但这一步是可选的。

**pip install streamlit**

对于我的应用程序,如果你正在构建整个系统,你可以下载一堆其他需求。现在,最重要的部分是构建应用程序的结构。我使用了一个基于类的结构,它可以让你在应用程序中添加页面作为MultiPage类的实例。这已经在我的项目报告中名为multipage.py的文件中创建。

这是一个简单的类,有两个方法

  • add():用来给你的应用添加更多的页面。每个新页面都附加到实例变量pages上。
  • run():这个方法在应用程序的侧边栏中创建一个下拉菜单,这样你就可以从所有你需要的选项中进行选择。

它只需要你输入streamlit,你就可以开始了!

这是一个处理应用程序结构的类,但是你实际上需要 file 来添加页面和管理代码。这已经在app.py文件中完成。

这是我们的 Streamlit 应用程序中的主文件,它将运行以加载所有页面。在第 8 行,我创建了一个MultiPage类的实例app,它是我在第 4 行导入的。app实例让我向应用程序添加页面,并运行应用程序。页面已经从第 14 行开始添加,用户可以以类似的方式添加他们的页面。最后,在第 21 行,我使用run函数运行了应用程序。

注意:- 使用这种结构的人只需改变第 5 行的导入,从第 14 行添加的页面和其余的代码将保持不变。

下面是一个片段,展示了您的应用程序导航的外观,具体取决于您在应用程序中添加了哪些页面。

多页应用程序的简化输出(app.py 文件)

最后,您可以用下面给出的方式为您的应用程序创建一个页面。我只展示了一页,其余的可以在这里看到。我创建了一个名为pages的新目录,并将所有页面文件放入其中,您也可以这样做。

我下面展示的页面叫做data_upload.py。在这个页面中,我上传了数据集并制作了它的本地副本。这对于在页面之间传输数据很有用。使用会话变量有另一种方法可以做到这一点,但是我不推荐初学者使用(也许我会写另一篇关于它的文章)。上传的数据集以 csv 格式存储在data文件夹中,并由其他页面读取。因为这是一个自动化的数据分析应用程序,所以它还会为更新的数据集中的每一列生成一个列数据。这是在第 44 行使用[utils.py](https://github.com/prakharrathi25/data-storyteller/blob/main/pages/utils.py) 文件中定义的genMetaData()函数完成的。您可以用类似的方式创建其他页面并构建您的应用程序。

注意:-在 app()函数中编写代码很重要,因为它在多页面应用程序的结构中被调用。

一旦所有的页面都制作好、导入并添加到你的应用程序中,就该在你的命令提示符下使用下面的命令来运行你的应用程序了。

streamlit run app.py

一旦您运行应用程序,您的 cmd 应该看起来像这样,一旦您重定向到本地 URL,您将看到您的应用程序。

最终多页简化应用程序

您也可以使用这个方法,并在您定义的页面内建立的新执行个体,在 multipage 应用程式内建立 multipage 应用程式。

使用 Streamlit 和它的其他组件,如会话变量,您可以做很多令人惊奇的事情。我可能会写另一篇关于会话状态和变量的文章,但我希望这篇文章简短且内容丰富。我希望你喜欢它,这是有益的。祝你好运!

参考

  1. https://www.youtube.com/watch?v=nSw96qUbK9o&t = 78s
  2. https://streamlit.io/
  3. https://sap-code . hackere earth . com/challenges/hackathon/sap-code/custom-tab/Data-4-storying/# Data % 204% 20 storying

用 ML 创作音乐

原文:https://towardsdatascience.com/creating-music-with-ml-b1960bce3b45?source=collection_archive---------21-----------------------

变形金刚又来了。

技术设备日复一日地播放音乐。你的手机可以做到,我的电脑可以做到,智能设备根据命令播放歌曲。因此,我们为什么不让技术设备也创造音乐呢?不仅仅是回放我们的结果,而是拿出原创作品?

韦斯顿·麦金农在 Unsplash 上拍摄的照片

这个方向有一个正在进行的研究领域;DeepMind 凭借其能够生成原始音频的 WaveNet 架构做出了巨大贡献。生成原始音频(生成类似音频曲线的浮点值)的缺点是涉及巨大的计算能力。这是一个障碍,因为计算机可能并不总是可用。

另一个效果惊人的方法是使用不同的格式来表现音乐。想想活页乐谱:虽然它本身不会发出声音,但它可以在下一步中用来产生声音。并且通过简单地生成图像,可以容易地训练 ML 模型来生成活页乐谱。

另一种格式是使用 MIDI 文件。这种格式将音乐存储为符号表示。我们不再保留声音,而是保留产生声音的信息。乐谱将音符值放在五线谱上,而 MIDI 表示包含信息。这些信息包含音符开音符关事件,指示乐器何时演奏。速度同样可以包括在内。

MIDI 文件可以包含从 C_{-1}到 C_{)}范围内的音符;相比之下,一架标准钢琴有 88 个键,那些漂亮的大钢琴有时更多。

在 MIDI 文件中,音符可以有任意的持续时间,并且必须在回放前量化。然后,为了可视化(量化的)MIDI 文件,我们使用钢琴卷帘窗表示。这本质上是一个矩阵,横轴是时标,纵轴是理论上可以同时演奏的音符数。下面描述了一个可视化示例:

钢琴卷帘窗的可视化示例。y 轴表示音高,x 轴表示时间。在时间 t,如果存在蓝色标记,则演奏一个音高(或音符)。图片由作者提供。

现在,用矩阵来表示音乐有什么好处呢?首先,你需要更少的存储空间,典型的 MIDI 文件最多只有几千字节。其次,实际的矩阵可以是布尔型或 int8 型。与原始音频相比,这大大减小了张量的大小。

简而言之:你把音乐表现为一种形象。

反过来也很容易做到。网络的输出也是一个矩阵(或图像),因此可以解释为钢琴曲。然后这个钢琴卷帘窗保存了事件信息,我们用它来(重新)构建一个 MIDI 文件。

现在的问题是:听起来怎么样?

训练越多越好。

但是你可以在这里自己听一听。默认情况下,我们最好的模型会被选中。换一个训练步数更少的,听听区别。

在一个项目中,我有机会成为一个使用 MIDI 文件的小组的一员,并尝试了各种 ML 模型。最初,我们训练自动编码器、变型自动编码器、生成对抗网络、它们的组合,以及不可避免的变形器。

最终,我们选定了由谷歌大脑团队开发的音乐转换器架构。然后我们在内部的 MIDI 文件数据集上训练这个模型。这个数据集包含了所有时代的音乐,但也包含了伟大的作曲家,如巴赫、柏辽兹、海顿和莫扎特。

由于我们为一个关于莫扎特的节日做了贡献,我们把重点放在了包括莫扎特在内的古典作曲家的作品上。

为了让访问者可以选择与我们的模型进行交互,我们编写了一个 web 应用程序。这是在 streamlit 的帮助下完成的(这在大多数情况下非常方便,但在一些重要的地方使用起来非常)令人沮丧。

要摆弄模型,从头开始创作新作品,请点击此链接。点击按钮,让人工智能做剩下的事情。

创建在线数据驱动的演示

原文:https://towardsdatascience.com/creating-online-data-driven-presentations-6b25fc626072?source=collection_archive---------29-----------------------

使用 Reveal.js 和 D3.js 创建交互式在线数据科学演示

活动发起人在 Unsplash 上的照片

介绍

能够总结数据科学项目并展示其潜在的商业利益,在获得新客户方面可以发挥非常重要的作用,并使非技术受众更容易理解一些关键的设计概念。

在本文中,我将向您介绍两个免费的编程框架,它们可以用来创建交互式在线演示和基于数据的讲故事报告。

Reveal.js

Reveal.js 是一个完全基于开放网络技术的开源展示框架。使用 Reveal.js,可以轻松地创建基于 web 的演示文稿,并将其导出为 PDF 等其他格式。

Reveal.js 的一些最有趣的特性是 Latex 和 Markdown 支持、CSS 定制、演讲者注释功能和语法高亮代码工具。

设置

Reveal.js 可以通过克隆官方存储库轻松安装:

git clone [https://github.com/hakimel/reveal.js.git](https://github.com/hakimel/reveal.js.git)

我们的演示可以通过修改 reveal.js 目录中提供的index.html文件来开发。使用 Node.js,我们可以很容易地实时观察(在本地服务器上的端口: http://localhost:8000 )我们如何更新index.html文件。

cd reveal.js && npm install
npm start

下面是index.html演示文件的一个简单例子。从代码片段中我们可以看到,我们首先导入 Reveal.js 库,然后将 black 作为幻灯片的主题(更多主题选项列在 Reveal.js 文档页面上!)。每个不同的幻灯片,然后可以通过将它们封装在一个 section 标签中并在里面写入所有需要的内容来创建。嵌套不同的 section 标签,就有可能在演示文稿中创建不同的子部分。最后,在最后一个脚本标记中,Reveal.js 被初始化(传递不同的可选参数,可以添加 Latex 和 Math 格式等功能)。

<html>
  <head>
    <link rel="stylesheet" href="dist/reveal.css">
    <link rel="stylesheet" href="dist/theme/black.css">
  </head>
  <body>
    <div class="reveal">
      <div class="slides">
        <section>First Slide</section>
        <section>Second Slide</section> 
        <section>
         <section>Subsection Slide 1</section>
         <section>Subsection Slide 2</section>
        </section>
      </div>
    </div>
    <script src="dist/reveal.js"></script>
    <script>
      Reveal.initialize();
    </script>
  </body>
</html>

此外,通过使用以下格式实例化幻灯片,还可以在 Markdown 中创建幻灯片,而不是使用 HTML 和 Javascript。

<section data-markdown>
  <textarea data-template>
    ## Slide Title
    Example **text**.
  </textarea>
</section>

使用 Reveal.js 创建的完整工作示例演示可在此链接获得(图 1)。

图 1:视频示例

D3.js

D3.js 是一个开源的 Javascript 库,旨在使用 HTML、CSS 和 SVG 在 web 中创建数据驱动的可视化。D3.js 可以简单地通过在我们的工作文件中添加下面一行来加载。

# As new versions of the library might be released, updated versions # of this link might can be found at [this link.](https://d3js.org/)
<script src="https://d3js.org/d3.v5.min.js"></script>

使用 D3.js,可以通过元素名称或 CSS 选择器来选择元素。此外,D3.js 还提供了一些实用程序,用于加载数据集和预处理可视化数据。

下面是一个简单的示例代码,展示了如何设置 D3.js 来创建椭圆图表。

<html><head>
  <script src="[https://d3js.org/d3.v5.min.js](https://d3js.org/d3.v5.min.js)"></script>
</head><body>
  <h1>D3.js Template Example</h1>
  <script>
    var svg = d3.select("body")
      .append("svg")
      .attr("width", 270)
      .attr("height", 270); svg.append("ellipse")
      .attr("cx", 140)
      .attr("cy", 100)
      .attr("rx", 120)
      .attr("ry", 70)
      .attr("opacity", 0.3)
      .attr("fill", "blue")
  </script>
</body></html>

图 2: D3.js 示例代码输出

然后可以使用 D3.js 图表,通过将它们与 scroller 架构相集成来创建强大的演示。幸运的是,多亏了像吉姆·瓦兰丁汉和库斯伯特·周这样的作者,多用途滚动条(可用于任何类型的叙事)在过去几年已经被开发出来。下面的动画展示了我使用基于 D3.js 的滚动条创建的数据驱动叙事的完整工作示例。这也可以在以下链接中进行测试。

图 3: D3.js 滚动条演示

如果您有兴趣了解更多关于如何创建 D3.js 图表的信息,那么 D3 Graph Gallery 文档是一个很好的起点。

最后,如果你想让你的演示可以离线使用,可以使用 FPDF 和 python-pptx Python 库来分别自动生成 PDF 和 PowerPoints。

希望您喜欢这篇文章,感谢您的阅读!

联系人

如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

  • Linkedin
  • 个人博客
  • 个人网站
  • 中等轮廓
  • GitHub
  • 卡格尔

从头开始创建 ONNX

原文:https://towardsdatascience.com/creating-onnx-from-scratch-4063eab80fcd?source=collection_archive---------3-----------------------

我们将在本教程中构建 ONNX 管道;图片作者。

实践教程

ONNX 提供了一种非常灵活的格式来存储 AI/ML 模型和管道。要了解如何操作,手动构建 ONNX 图是有指导意义的。

ONNX 已经存在了一段时间,它正在成为一种成功的中间格式,将通常沉重的、经过训练的神经网络从一种训练工具转移到另一种工具(例如在 pyTorch 和 Tensorflow 之间转移),或者使用 ONNX 运行时在云中部署模型。在这些情况下,用户通常只是简单地将模型保存为 ONNX 格式,而不用担心生成的 ONNX 图形。

然而,ONNX 可以有更广泛的用途:ONNX 可以轻松地用于手动指定 AI/ML 处理管道,包括现实部署中经常需要的所有预处理和后处理。此外,由于其标准化和开放的结构,存储在 ONNX 中的管道可以很容易地部署,甚至在边缘设备上(例如,通过自动编译到 WebAssembly 以在各种目标上高效部署)。在本教程中,我们将展示如何使用 Python 中的onnx.helper工具从头开始创建 ONNX 管道并有效地部署它。

本教程由以下部分组成:

  1. ONNX 的一些背景。在我们开始之前,从概念上理解 ONNX 是做什么的是有用的。
  2. “找房子”场景。在本教程中,我们将重点创建一个管道来预测广告房屋的价格,并随后判断该房屋是否符合我们的搜索约束条件(即我们的需求)。
  3. 模特培训。虽然不是真正的部署管道的一部分,我们将展示我们如何使用“sklearn”来训练预测模型。
  4. 创建 ONNX 管道。这是本教程的主体,我们将一步一步来:
    预处理:我们将使用我们训练的结果来标准化输入。
    推论:我们将使用训练期间拟合的模型来预测(对数)价格。
    后处理:我们将检查结果是否符合我们的要求。
    综合起来:我们将把预处理、推理和后处理管道合并成一个 ONNX 图。
  5. 部署模型:可以使用 ONNX 运行时部署 ONNX 模型,或者优化拟合图,使用 WebAssembly 部署。我们将简要探讨这两种选择。

ONNX 可轻松用于手动指定 AI/ML 处理管道,包括现实部署中经常需要的所有预处理和后处理

1.ONNX 是什么?

根据 ONNX 官方网站:

“O NNX 是一种开放格式,用于表示机器学习模型。ONNX 定义了一组通用的运算符——机器学习和深度学习模型的构建块——和一种通用的文件格式,使 AI 开发人员能够使用各种框架、工具、运行时和编译器“”(参见)ONNX . AI)。

因此,ONNX 是一种开放文件格式,用于存储(已训练)包含足够细节(关于数据类型等)的机器学习模型/管道。)从一个平台移动到另一个平台。ONNX 的特性甚至允许将存储的操作自动编译成低级语言,以嵌入到各种设备中。实际上,当从一个平台转移到另一个平台时,一个onnx文件将包含重新实例化一个完整的数据处理管道所需的所有信息。

从概念上讲,onnx 格式非常简单:ONNX 文件定义了一个有向图,其中每条边代表一个特定类型的张量,该张量从一个节点“移动”到另一个节点。节点本身被称为操作符,它们对它们的输入(即图中它们的父节点的结果)进行操作,并将它们的操作结果提交给它们的子节点。ONNX 指定了一个操作列表,它们共同允许你指定任何你可能想要执行的 AI/ML 操作(如果不是,操作符的集合很容易扩展)。

为了提供一个概念性的例子,假设我们想要从一个逻辑回归模型中生成推论。给定一个输入向量x,我们将:

1.使用例如Gemm算子将我们的输入向量x乘以学习系数beta来计算线性预测值ylin
2。使用Sigmoid运算符将线性预测值转换为概率标度。
3。使用Less操作符生成对或错的推断。

因此,通过有效地链接多个操作符,我们可以在给定一些特征向量的情况下生成推论。然而,不要被简单的例子所迷惑:由于 ONNXs 张量支持和大量的操作符列表,甚至用于视频处理的复杂 dnn 也可以在 ONNX 中表示。

不要被这个简单的例子所迷惑:由于 ONNXs 张量支持和广泛的操作符列表,甚至用于视频处理的复杂 dnn 也可以在 ONNX 中表示。

2.我们找房子的场景

为了演示如何从头开始创建 ONNX 图,我们引入一个简单的场景:

“假设你正在附近找一栋新房子。给定以前房屋销售的数据集,其中包含已出售房屋的庭院大小yard、居住面积area和房间数量rooms及其价格price,构建一个模型来预测新广告房屋的价格(即,只给你庭院大小、面积和房间数量)。接下来,您感兴趣的是价格低于 400.000 欧元、带院子(即院子大小大于 0)的任何房子。”

在本教程中,我们将构建一个数据处理管道,包括一个用于推理的线性回归模型,该模型给出了一个示例特征向量(yard,area,rooms)提供了一个布尔值,指示该房屋是否是感兴趣的。

3.模特培训

要创建管道,我们首先需要创建用于预测价格的模型。下面的代码打开数据文件houses.csv(此处可用)并生成模型。请注意,我们执行了几个步骤:

  • 我们对输入进行标准化(因此,为了在预处理流水线中进行去标准化,我们将需要每个输入变量的“平均值”和“标准值”)。
  • 我们对价格进行对数转换(因此,在我们的后处理流程中,我们需要将我们的推断转换回正确的比例)。
  • 我们拟合一个简单的线性回归模型(并且我们存储估计的系数用于我们的处理流水线)。

以下是注释代码(或点击此处查看完整笔记本):

import numpy as np
from sklearn import linear_model as lm# Open the training data:
data = np.loadtxt(open(“houses.csv”, “rb”), delimiter=”,”, skiprows=1)# Retreive feature vectors and outcomes:
datX = data[:, [1,2,3]] # Input features (yard, area, rooms)
datY = data[:, [0]] # Price# Standardize the inputs:
barX = np.mean(datX, 0) # Mean for each of the inputs
sdX = np.std(datX, 0) # Sd for each of the inputs
datZ = (datX — barX) / sdX# Log transform the output
logY = np.log(datY)# Fit a linear model
lin_mod = lm.LinearRegression()
lin_mod.fit(datZ, logY)# retrieve intercept and fitted coefficients:
intercept = lin_mod.intercept_
beta = lin_mod.coef_## Storing what we need for inference in our processing pipeline.
print(“ — — Values retrieved from training — — “)
print(“For input statdardization / pre-processing we need:”)
print(“ — The column means {}”.format(barX))
print(“ — The column sds {}”.format(sdX))print(“For the prediction we need:”)
print(“ — The estimated coefficients: {}”.format(beta))
print(“ — The intercept: {}”.format(intercept))# store the training results in an object to make the code more readable later on:
training_results = {
 “barX” : barX.astype(np.float32),
 “sdX” : sdX.astype(np.float32),
 “beta” : beta.astype(np.float32),
 “intercept” : intercept.astype(np.float32),
}# And, also creating the constraints (for usage in block 3):
constraints = {
 “maxprice” : np.array([400000]),
 “minyard” : np.array([1]),
}

虽然training_resultsconstraints对象是我们在这个训练阶段在 ONNX 中实现我们的处理管道所需要的,但是演示如何在不转换到 ONNX 的情况下生成推理是有启发性的。以下代码演示了我们旨在使用简单 python 代码构建的完整管道,并使用我们训练集中的第一个实例作为示例:

# Get the data from a single house
first_row_example = data[1,:]
input_example = first_row_example[[1,2,3]]  # The features
output_example = first_row_example[0]  # The observed price# 1\. Standardize input for input to the model:
standardized_input_example = (input_example - training_results['barX'])/ training_results['sdX']# 2\. Predict the *log* price (using a dot product and the intercept)
predicted_log_price_example = training_results['intercept'] + np.dot(standardized_input_example, training_results['beta'].flatten())# Compute the actual prediction on the original scale
predicted_price_example = np.exp(predicted_log_price_example)
print("Observed price: {}, predicted price: {}".format(output_example, predicted_price_example))# See if it is interesting according to our simple decision rules:
interesting = input_example[1] > 0 and predicted_price_example < 400000
print("Interesting? {}".format(interesting))

4.创建 ONNX 管道。

给定一个由长度为 3 (yard,area,rooms)的输入向量描述的示例实例,我们的 ONNX 管道应该:

  1. [预处理]通过减去平均值(如在训练集中观察到的)并除以标准差来标准化输入
  2. [推论]在对数标度上预测示例实例的房价(使用来自上述训练好的sklearn模型的系数)
  3. [后处理]将价格转换回原始规模,并检查 a)房子是否负担得起,b)是否有院子。

更准确地说,引入所使用的 ONNX 操作符,我们将生成以下管道:

图片作者。

请注意,在下面的代码块中,我们将使用此图片中介绍的命名约定。

4a。预处理

我们将使用 Python 中提供的onnx.helper工具来构建我们的管道。我们首先创建常数,然后是操作节点(尽管常数也是操作符),接着是图形:

# The required constants:
c1 = h.make_node(‘Constant’, inputs=[], outputs=[‘c1’], name=”c1-node”, 
 value=h.make_tensor(name=”c1v”, data_type=tp.FLOAT, 
 dims=training_results[‘barX’].shape, 
 vals=training_results[‘barX’].flatten()))c2 = h.make_node(‘Constant’, inputs=[], outputs=[‘c2’], name=”c2-node”, 
 value=h.make_tensor(name=”c2v”, data_type=tp.FLOAT, 
 dims=training_results[‘sdX’].shape, 
 vals=training_results[‘sdX’].flatten()))# The functional nodes:
n1 = h.make_node(‘Sub’, inputs=[‘x’, ‘c1’], outputs=[‘xmin’], name=’n1')
n2 = h.make_node(‘Div’, inputs=[‘xmin’, ‘c2’], outputs=[‘zx’], name=”n2")# Create the graph
g1 = h.make_graph([c1, n1, c2, n2], ‘preprocessing’,
 [h.make_tensor_value_info(‘x’, tp.FLOAT, [3])],
 [h.make_tensor_value_info(‘zx’, tp.FLOAT, [3])])# Create the model and check
m1 = helper.make_model(g1, producer_name=’scailable-demo’)
checker.check_model(m1)# Save the model
save(m1, ‘pre-processing.onnx’)

上面的代码创建了预处理管道,并以onnx格式存储。在 Python 中,我们可以使用onnxruntime直接测试存储的模型:

# A few lines to evaluate the stored model, useful for debugging:
import onnxruntime as rt# test
sess = rt.InferenceSession(“pre-processing.onnx”) # Start the inference session and open the model
xin = input_example.astype(np.float32) # Use the input_example from block 0 as input
zx = sess.run([“zx”], {“x”: xin}) # Compute the standardized outputprint(“Check:”)
print(“The standardized input using onnx pipeline is: {}”.format(zx))
print(“ — Compare to standardized first row in block 0: {}”.format(datZ[1,:]))

评估表明,我们的预处理管道确实正确地标准化了示例实例。

预处理管道,作者图像。

4b。推理

创建预处理管道后,我们按照类似的方法创建推理管道:

# The constants:
c3 = h.make_node(‘Constant’, inputs=[], outputs=[‘c3’], name=”c3-node”, 
 value=h.make_tensor(name=”c3v”, data_type=tp.FLOAT, 
 dims=training_results[‘beta’].shape, 
 vals=training_results[‘beta’].flatten()))c4 = h.make_node(‘Constant’, inputs=[], outputs=[‘c4’], name=”c4-node”, 
 value=h.make_tensor(name=”c4v”, data_type=tp.FLOAT, 
 dims=training_results[‘intercept’].shape, 
 vals=training_results[‘intercept’].flatten()))# The operating nodes, Multiply, reduceSum, and Add
n3 = h.make_node(‘Mul’, inputs=[‘zx’, ‘c3’], outputs=[‘mulx’], name=”multiplyBeta”)
n4 = h.make_node(‘ReduceSum’, inputs=[‘mulx’], outputs=[‘sumx’], name=”reduceSum”, keepdims=0)
n5 = h.make_node(‘Add’, inputs=[‘sumx’, ‘c4’], outputs=[‘yhatlog’], name=’addIntercept’)# The graph
g2 = h.make_graph([c3, c4, n3, n4, n5], ‘linear_regression’,
 [h.make_tensor_value_info(‘zx’, tp.FLOAT, [3])],
 [h.make_tensor_value_info(‘yhatlog’, tp.FLOAT, [1])])# The model and check:
m2 = h.make_model(g2, producer_name=’scailable-demo’)
checker.check_model(m2)# Save the model
save(m2, ‘linear-regression.onnx’)

同样,很容易验证预测是否正确:

# test
sess = rt.InferenceSession(“linear-regression.onnx”) # Start the inference session and open the model
xin = standardized_input_example.astype(np.float32) # Use the input_example from block 0 as input
yhatlog = sess.run([“yhatlog”], {“zx”: xin}) # Compute the standardized outputprint(“Check:”)
print(“The log predicted price from ONNX is: {}”.format(yhatlog))
print(“ — Compare to analysis in block 0: {}”.format(predicted_log_price_example))

推理管道,作者图片。

4c。后加工

后处理流水线稍微复杂一点,因为它检查房子是否符合我们的需要(即predicted_price < 400000yard > 0,因此使用各种输入源(注意“Slice”操作符有点复杂):

# Constants (note using the constraints object created in block 0 above)
c5 = h.make_node(‘Constant’, inputs=[], outputs=[‘c5’], name=”c5-node”, 
 value=h.make_tensor(name=”c5v”, data_type=tp.FLOAT, 
 dims=constraints[‘maxprice’].shape, 
 vals=constraints[‘maxprice’].flatten()))
c6 = h.make_node(‘Constant’, inputs=[], outputs=[‘c6’], name=”c6-node”, 
 value=h.make_tensor(name=”c6v”, data_type=tp.FLOAT, 
 dims=constraints[‘minyard’].shape, 
 vals=constraints[‘minyard’].flatten()))# Auxiliary constants for the slice operator:
caux1 = h.make_node(‘Constant’, inputs=[], outputs=[‘caux1’], name=”caux1-node”,
 value=h.make_tensor(name=’caux1v’, data_type=tp.INT32,
 dims=np.array([0]).shape, vals=np.array([0]).flatten()))
caux2 = h.make_node(‘Constant’, inputs=[], outputs=[‘caux2’], name=”caux2-node”,
 value=h.make_tensor(name=’caux2v’, data_type=tp.INT32,
 dims=np.array([1]).shape, vals=np.array([1]).flatten()))
caux3 = h.make_node(‘Constant’, inputs=[], outputs=[‘caux3’], name=”caux3-node”,
 value=h.make_tensor(name=’caux3v’, data_type=tp.INT32,
 dims=np.array([0]).shape, vals=np.array([0]).flatten()))
caux4 = h.make_node(‘Constant’, inputs=[], outputs=[‘caux4’], name=”caux4-node”,
 value=h.make_tensor(name=’caux4v’, data_type=tp.INT32,
 dims=np.array([1]).shape, vals=np.array([1]).flatten()))

# Nodes:
n6 = h.make_node(‘Exp’, inputs=[‘yhatlog’], outputs=[‘yhat’], name=’exponent’)
n7 = h.make_node(‘Less’, inputs=[‘yhat’, ‘c5’], outputs=[‘price_ok’], name=’priceLess’)n8 = h.make_node(‘Slice’, inputs=[‘x’, ‘caux1’, ‘caux2’, ‘caux3’, ‘caux4’], outputs=[‘yard’],)
n9 = h.make_node(‘Less’, inputs=[‘c6’, ‘yard’], outputs=[‘yard_ok’], name=”yardMore”) # note reversaln10 = h.make_node(‘And’, inputs=[‘price_ok’, ‘yard_ok’], outputs=[‘result’], name=’andBools’)# The graph
g3 = h.make_graph([c5, c6, caux1, caux2, caux3, caux4, n6, n7, n8, n9, n10], ‘postprocessing’,
 [h.make_tensor_value_info(‘x’, tp.FLOAT, [3]), h.make_tensor_value_info(‘yhatlog’, tp.FLOAT, [1])],
 [h.make_tensor_value_info(‘result’, tp.BOOL, [1])])# The model and check:
m3 = h.make_model(g3, producer_name=’scailable-demo’)
checker.check_model(m3)# Save the model
save(m3, ‘post-processing.onnx’)

同样,结果很容易验证:

# test
sess = rt.InferenceSession(“post-processing.onnx”) # Start the inference session and open the model
x = input_example.astype(np.float32) # Use the input_example from block 0 as inputyhatlog = np.array(yhatlog).flatten()
result = sess.run([“result”], {“x”: x, “yhatlog” : yhatlog}) # Compute the standardized outputprint(“Check:”)
print(“Predicted price {} and yardsize {} are appealing {}.”.format(np.exp(yhatlog), input_example[0], result))

后处理流水线。图片作者。

4d。把所有的放在一起

虽然将处理管道的每个部分都转换为 ONNX 以便于部署很好,但 ONNX 的强大之处之一是能够将一组操作链接到另一组操作。因此,我们可以轻松地在一个 ONNX 图中指定完整的管道:

g_full = h.make_graph([c1, n1, c2, n2, c3, c4, n3, n4, n5, c5, c6, caux1, caux2, caux3, caux4, n6, n7, n8, n9, n10], 
 ‘fullpipeline’,
 [h.make_tensor_value_info(‘x’, tp.FLOAT, [3])],
 [h.make_tensor_value_info(‘result’, tp.BOOL, [1])])m_full = h.make_model(g_full, producer_name=’scailable-demo’)
checker.check_model(m_full)# Save the model
save(m_full, ‘full-pipeline.onnx’)

同样,很容易验证我们的结果:

# test
sess = rt.InferenceSession(“full-pipeline.onnx”) # Start the inference session and open the model
xin = input_example.astype(np.float32) # Use the input_example from block 0 as inputyhatlog = np.array(yhatlog).flatten()
result = sess.run([“result”], {“x”: xin}) # Compute the standardized outputprint(“Check:”)
print(“Example {} is appealing: {}.”.format(xin, result))

上面的代码演示了我们数据集中的第一所房子不符合我们的需求,因为预测价格超过 400.000E。

当使用 Netron 查看时,我们得到的 ONNX 管道如下所示:

ONNX 中创建的完整数据处理管道。图片作者。

请注意,只要输入和输出匹配,就可以将部分图形组合成其他图形,这使得在 ONNX 中存储常见的预处理和后处理操作并在各种项目中重用它们变得很容易。

5.部署。

上面我们希望展示 ONNX 不仅仅是各种复杂的人工智能训练工具使用的抽象文件格式。ONNX 还通过将手工制作的 ONNX 块链接在一起,使手动构建预处理和后处理流水线变得容易。因此,ONNX 是一个非常有效的工具,可以创建可以在任何地方使用(和重用)的数据分析管道。

一旦有了 ONNX 管道,它的部署就有了各种选项:

  1. 您可以使用 onnxruntime (这是我们在上面的一些快速测试中使用的)。如果您想在云上部署,一个选择是创建一个简单的 REST 端点(例如使用 Flask )来执行onnxruntime,并使用 Docker 来部署它。虽然这相对容易,但也经常效率很低(并且消耗内存)。
  2. 您可以使用 Scailable 提供的工具将 ONNX 模型传输到 WebAssembly,以实现极其高效的部署。实际上,由于其详细程度,ONNX 使得基于 ONNX 图自动生成低级语言的独立可执行文件成为可能。这提供了本机执行速度(当移植到c时),并且(当移植到像.wasm这样的可移植目标时)允许您将完全相同的模型从云移动到边缘,甚至移动到小型(I)物联网设备。

相当酷。

最后,简单比较一下上面提到的两种部署选项的大小和速度:

  1. 我们在上面创建的完整 ONNX 管道消耗不到 1Kb 的内存。然而,为了运行,onnxruntime本身需要 200Mb 多一点。使用这个内存足迹,我可以在我的本地机器上,在 1.9 秒内执行我们的管道 1000 次(当每次重新启动会话时)。
  2. 使用到 WebAssembly 的转换(就像 Scailable 为任何 ONNX 图所做的那样)对于.wasm二进制文件来说,内存占用大约是 70Kb(这大于.onnx规范,因为包括了必要操作符的功能规范),但是对于运行时来说只有 60Kb。这样,总共不到< 0.2 Mb 。使用这个内存足迹,我可以在同一台本地机器上,在 0.7 秒内生成 1000 个推理(类似地,每次重新加载;在没有重新加载的情况下,ONNX 和 WebAssembly 运行时之间的时间差实际上是 0,因为一旦初始化,两者都以接近本机的速度运行。

所以是的,结合 ONNX 和 WebAssembly 提供了跨所有目标的表现力(ONNX)和效率(WASM)。

所以是的,结合 ONNX 和 WebAssembly 提供了跨所有目标的表现力(ONNX)和效率(WASM)。

我希望你喜欢这个教程;如有任何与 ONNX / WebAssembly 部署相关的问题,请随时联系我们!

放弃

值得注意的是我自己的参与:我是 杰罗尼姆斯数据科学院 的数据科学教授,也是Scailable的联合创始人之一。因此,毫无疑问,我对 Scailable 有既得利益;我有兴趣让它成长,这样我们就可以最终将人工智能投入生产并兑现它的承诺。这里表达的观点是我自己的。

用赋格创造熊猫和火花兼容功能

原文:https://towardsdatascience.com/creating-pandas-and-spark-compatible-functions-with-fugue-8617c0b3d3a8?source=collection_archive---------32-----------------------

用一行代码在熊猫和 Spark 之间无缝切换

动机

数据科学团队通常会投资一套通用的工具,并构建一个共享的 Python 库。这个库包括清理和转换数据的常用方法,以及用于机器学习的实用函数(如自定义指标或特定的训练测试拆分)。

拥有这样一个库为更快地启动新项目提供了基础。理想情况下,随着团队承担更多的项目,共享库会继续成长和成熟。

虽然拥有一个共享库在概念上很棒,但是在不同的设置中使用相同的代码会有一些问题。有不同的用例需要不同的工具。有些数据集大约有数万行,有些数据集可能有数亿行。大数据通常要求 Spark 利用分布式计算。然而,如果一个项目足够小,可以在 Pandas 上完成,那么就没有必要使用集群,也没有必要增加使用 Spark 的开销。正如所料,使用两个框架会导致维护共享库时出现问题。在一个框架中开发的功能不适合另一个框架。

熊猫和星火的区别

为了展示不同框架在语法上的不同,下面是一个用例示例。与任何数据科学工作一样,存在数据缺失的情况,我们会尝试填补它。在下表中,我们对使用某人的家庭状态感兴趣。如果家庭状态不可用,我们得到工作状态。如果工作状态也不可用,我们将尝试使用电话号码区号来推断状态。

| id  | home_state | work _state | phone          |
|-----|------------|-------------|----------------|
| "A" | "IL"       | "IL"        | "217-123-4567" |
| "B" | None       | "WI"        | "312-123-4567" |
| "C" | "FL"       | "FL"        | "352-234-5678" |
| "D" | "CA"       | "CA"        | "415-345-6789" |
| "E" | None       | None        | "217-123-4567" |
| "F" | "IL"       | None        | "312-234-5678" |

以上问题的 Pandas 和 Spark 实现可以在下面的 Github Gist 中看到。对于一个相对简单的转换,Pandas 和 Spark 之间的代码看起来已经非常不同。除了语法之外,更大的问题是我们有一个定制的业务逻辑不能在 Pandas 和 Spark 应用程序之间循环使用。

随着时间的推移,随着项目规模的增加,以及涉及到更复杂的逻辑来转换数据,被锁定到一个框架中变得更加复杂。最终,代码基础逻辑变得与框架紧密耦合,切换框架的开销逐渐增加。

如何才能跨熊猫和 Spark 回收自定义逻辑?我们是否需要实现每个功能的两个版本(一个用于 Spark,一个用于 Pandas)?或者有没有办法把逻辑和计算分开?我们能否专注于定义逻辑,然后选择运行它的底层引擎(Spark 或 Pandas)?

逻辑和执行的解耦允许以与规模和框架无关的方式编写代码。即使数据现在可以由熊猫处理,1 年后它仍然足够小吗?两年后呢?与规模和框架无关的代码允许数据科学家根据数据量在执行引擎之间无缝切换。为 Spark 回收代码不需要重写。

火花和熊猫兼容代码与赋格

神游标志

这就是赋格出现的地方。Fugue 是一个开源框架,作为一个适应不同计算框架的抽象层。它统一了分布式计算的核心概念,并将逻辑从用于处理数据的框架(如 Spark、Pandas、Dask)中分离出来。神游适应用户,而不是用户适应神游。

赋格建筑

它还旨在使分布式计算民主化,并使不熟悉 Spark 的人更容易使用它。通过使用 Fugue,用户可以用原生 Python 编写代码,然后轻松地通过逻辑将其移植到 Spark 或 Dask,而不必重写代码。

赋格例子

让我们重温一下上面的例子,用原生 Python 和赋格来求解。

赋格示例代码

代码示例中首先要注意的是,第 9–16 行定义的函数是用基本 Python 编写的,没有赋格依赖项。使用的所有数据类型都是原生 Python。函数是纯逻辑的,没有熊猫或者 Spark 的影响。

第二件事是第 9 行中的模式提示。模式在赋格中是强制的,它强制更明确和描述性的代码。如果用户不再神游,这个功能仍然可以被修改为用应用语句来处理熊猫或 Spark。模式提示只是一个注释,但仍然是有用的。

最后要注意的是第 18 行中定义的 FugueWorkflow 上下文管理器。默认的执行引擎是 Pandas,但是如果我们想要将整个工作流引入 Spark,我们可以通过一行代码的修改来实现。

with FugueWorkflow(SparkExecutionEngine) as dag:

现在,FugueWorkflow 上下文管理器中的所有内容都将在 Spark 中运行。

神游的好处

随着工作流复杂性的增加,神游的好处也随之增加。最明显的好处是,同样的逻辑将适用于熊猫和 Spark jobs。对于需求快速增长的团队来说,这给了我们灵活性和敏捷性来无缝地适应更大的数据量。即使数据科学团队可以处理熊猫当前的数据量,最终仍有可能需要 Spark。使用 Fugue,转换是毫不费力的,因为改变计算引擎只需要改变一行代码。

此外,Fugue 允许用户在更易管理的数据上构建原型,并在需要时可靠地扩展。这有可能提高开发人员的工作效率并降低集群成本。当准备好在完整数据集上测试代码时,可以交换执行引擎。Spark 作业每次运行的集群成本很容易达到数百美元。这节省了资金,因为集群不需要启动来测试代码。

最后,Fugue 允许用户为更小、更易测试的功能编写单元测试。逻辑是明确的,并且独立于框架。这增强了代码库的可维护性。

神游和考拉的区别

Databricks 有一个名为考拉的库,允许熊猫用户在 Spark 上使用相同的 DataFrame API。在某些情况下,更改 import 语句将允许用户从 Pandas 执行更改为 Spark 执行。

这里的一个问题是,不是所有的熊猫函数都在考拉中实现,这意味着一些熊猫编写的代码不会通过改变导入语句立即工作。

即使实现了这些功能,Pandas 和 Spark 之间也存在难以调和的差异。例如,Pandas 允许混合类型的列(包含整数和字符串),而 Spark DataFrames 不允许。使用混合类型的考拉会导致错误。赋格遵循火花,和阿帕奇箭头,在强有力的和明确的打字。

结论

我们已经看到了如何使用 Fugue 来创建 Python 函数,能够在 Pandas 和 Spark 之间使用而不做任何更改。这消除了维护每个函数的两个版本的需要,并且还将逻辑与底层执行引擎解耦。

用神游写一个代码库,让用户一行代码变化就能在熊猫和 Spark 之间变化。

联系我们

如果你对使用赋格感兴趣,想给我们反馈,或者有任何问题,我们很乐意在 Slack 上聊天!我们还将为对在数据工作流中应用 Fugue 感兴趣的数据团队举办更详细的研讨会。

文档
Git 回购
社区懈怠

创建 Python 虚拟环境

原文:https://towardsdatascience.com/creating-python-virtual-environments-f7bc4cbbd328?source=collection_archive---------10-----------------------

了解如何用 Python 创建虚拟环境,并使用 requirements.txt 安装依赖项

照片由迈克尔·泽兹奇在 Unsplash 拍摄

在 Python 中,虚拟环境是运行 Python 程序的隔离环境。使用虚拟环境允许你的程序拥有自己的依赖项(不同版本的包)。例如,程序 A 使用特定版本的 packageX,而程序 B 使用旧版本的 packageX。这是一个直观的问题:

作者图片

如果你把两个程序放在同一个默认环境中,你会遇到 packageX 的问题——如果你试图安装一个特定版本的 packageX,它会覆盖另一个版本。

更好的解决方案是创建两个隔离的环境——又名 虚拟环境 。每个虚拟环境将托管每个程序所需的特定版本的 packageX,如下所示:

作者图片

在本文中,我将向您展示如何使用 conda 包管理器创建虚拟环境。此外,我还将向您展示如何获得已经安装在您的环境中的包的列表(通过**pip**命令),并使用**requirements.txt**文件在另一个虚拟环境中执行相同的安装。

Conda是一个运行在 Windows、Mac OS 和 Linux 上的开源包和环境管理系统。

本文假设您的计算机上安装了 Anaconda(https://www.anaconda.com/products/individual-d)。

创建新的虚拟环境

要创建一个新的虚拟环境,使用带有以下选项的**conda**命令:

**conda create --name Project1 python=3.9**

上面的命令创建了一个名为 Project1 的虚拟环境,Python 版本设置为 3.9:

查看虚拟环境列表

创建虚拟环境后,您可以使用以下命令查看您计算机上的虚拟环境列表:

**conda info --envs**

您应该会看到如下所示的内容:

(base) weimenglee@Wei-Mengs-Mini ~ % **conda info --envs**
# conda environments:
#
base                *  /Users/weimenglee/miniforge3
**Project1               /Users/weimenglee/miniforge3/envs/Project1**

激活虚拟环境

创建了新的虚拟环境后,是时候激活它了:

(base) weimenglee@Wei-Mengs-Mini ~ % **conda activate Project1****(Project1)** weimenglee@Wei-Mengs-Mini ~ %

正如您在上面看到的,一旦 Project1 虚拟环境被激活,您将在命令提示符前面看到虚拟环境的名称 (Project1) :

**(Project1)** weimenglee@Wei-Mengs-Mini ~ %

查看当前环境中安装的 Python 包列表

要了解您的虚拟环境中当前安装了哪些包,请使用**pip freeze**命令:

(Project1) weimenglee@Wei-Mengs-Mini ~ % **pip freeze**

该命令将返回当前环境中安装的软件包列表,以及它们的版本号。以下是我的项目 1 虚拟环境的输出示例:

certifi==2021.5.30

有时,**pip freeze**命令会包含从直接 URL 引用安装的发行版的直接引用,如下所示:

certifi==2021.5.30**chardet @ file:///Users/runner/miniforge3/conda-bld/chardet_1610093454858/work**

为了防止这种情况发生,对**pip freeze**使用以下替代命令:

**pip list --format=freeze**

这将确保结果始终采用以下格式:

*<package_name>==<version_number>*

现在让我们尝试使用**pip install**命令在我们的项目 1 虚拟环境中安装一些额外的包:

(Project1) weimenglee@Wei-Mengs-Mini ~ % **pip install pandas numpy matplotlib**

以上命令安装以下软件包:

  • 熊猫
  • NumPy
  • Matplotlib

您现在可以使用**pip freeze**命令(或**pip list —-format=freeze**)来查看您拥有的软件包列表,包括您刚刚安装的软件包。

(Project1) weimenglee@Wei-Mengs-Mini ~ % **pip freeze**
certifi==2021.5.30
cycler==0.10.0
kiwisolver==1.3.2
matplotlib==3.4.3
numpy==1.21.2
pandas==1.3.2
Pillow==8.3.2
pyparsing==2.4.7
python-dateutil==2.8.2
pytz==2021.1
six==1.16.0

此外,您还将把列表保存到一个名为 requirements.txt 的文件中:

(Project1) weimenglee@Wei-Mengs-Mini ~ % **pip freeze > requirements.txt**

**requirements.txt**文件包含当前环境中安装的软件包列表。稍后,您将利用它在另一个虚拟环境中重新安装所有软件包。

K ey takeaway —无论您在这个虚拟环境中安装了什么包,它都将留在这个虚拟环境中。它不会与您在另一个虚拟环境中安装的其他类似软件包冲突。

测试新环境

您现在可以测试环境是否正常工作。键入以下命令启动 Python 解释器:

(Project1) weimenglee@Wei-Mengs-Mini ~ % **python**

然后,导入熊猫包并打印其版本:

>>> **import pandas**
>>> **print(pandas.__version__)**

如果您能够看到上面的输出,那么软件包安装正确。

键入**exit()**退出 Python 解释器。

停用环境

当您完成环境后,您可以使用**conda deactivate** 命令将您带回基本环境:

(Project1) weimenglee@Wei-Mengs-Mini ~ % **conda deactivate**

移除环境

完成项目后,如果不再需要该环境,可以使用以下命令删除该环境:

(base) weimenglee@Wei-Mengs-Mini ~ % **conda env remove --name Project1***Remove all packages in environment /Users/weimenglee/miniforge3/envs/Project1:*

使用 requirements.txt 文件创建另一个虚拟环境并安装软件包

现在让我们创建另一个虚拟环境,称之为项目 2 :

(base) weimenglee@Wei-Mengs-Mini ~ % **conda create --name Project2 python=3.9**

创建后,激活新的虚拟环境:

(base) weimenglee@Wei-Mengs-Mini ~ % **conda activate Project2
(Project2)** weimenglee@Wei-Mengs-Mini ~ %

让我们试试 Python 解释器,看看 Pandas 模块是否可用:

(Project2) weimenglee@Wei-Mengs-Mini ~ % python
Python 3.9.6 (default, Aug 16 2021, 12:43:27)
[Clang 12.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> **import pandas**
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
*ModuleNotFoundError: No module named 'pandas'*
>>> **exit()**

正如预测的那样,Pandas 是默认不安装的。如果您想要安装已经安装在项目 1 虚拟环境中的软件包,现在您可以使用您之前创建的**requirements.txt** 文件:

(Project2) weimenglee@Wei-Mengs-Mini ~ % **pip install -r requirements.txt** Requirement already satisfied: certifi==2021.5.30 in ./miniforge3/envs/Project2/lib/python3.9/site-packages (from -r requirements.txt (line 1)) (2021.5.30)
Collecting cycler==0.10.0...Collecting matplotlib==3.4.3
Using cached matplotlib-3.4.3-cp39-cp39-macosx_11_0_arm64.whl
Collecting numpy==1.21.2
Using cached numpy-1.21.2-cp39-cp39-macosx_11_0_arm64.whl (12.4 MB)
Collecting pandas==1.3.2
Using cached pandas-1.3.2-cp39-cp39-macosx_11_0_arm64.whl...Installing collected packages: six, pytz, python-dateutil, pyparsing, Pillow, numpy, kiwisolver, cycler, pandas, matplotlib
Successfully installed Pillow-8.3.2 cycler-0.10.0 kiwisolver-1.3.2 matplotlib-3.4.3 numpy-1.21.2 pandas-1.3.2 pyparsing-2.4.7 python-dateutil-2.8.2 pytz-2021.1 six-1.16.0

**requirements.txt**文件中指定的所有包现在将被安装在项目 2 虚拟环境中。

结论

使用**requirements.txt**文件是指定 Python 程序依赖关系的好方法。在这个文件中,您放置了您的应用程序需要的所有包名(以及它们的特定版本号),这样无论谁运行您的程序,都只需要使用**requirements.txt**文件执行一个**pip install**

用 Python 创建用于分析实时数据的可扩展机器学习系统—第 1 部分

原文:https://towardsdatascience.com/creating-scalable-machine-learning-systems-for-analyzing-real-time-data-in-python-part-1-c303fbf79424?source=collection_archive---------4-----------------------

本系列展示了如何实时输入数据、分析数据并将响应发送回感兴趣的受众。

最近,人们对用于分析实时数据并将结果实时发送给感兴趣的群体的可扩展机器学习(ML)系统产生了浓厚的兴趣。越来越多的企业热衷于为其业务部署实时预测或分析,这不仅是为了与众不同,也是为了在当今竞争激烈的和快节奏的市场中提高整体绩效、客户体验和保留率。

从股票交易到使用天气数据预测航班延误,动物和人类的实时行为分析,或者构建客户支持聊天机器人,有不同的实时问题和不同的解决方法-数据分类和聚类,实时训练 ML 模型和反馈循环以在发生时进行完善,实时决策树,以及许多这样的不断发展的算法。

几年前,跟踪这些算法、验证、实施、测试、改进和循环使用是一个非常困难的问题。但是,因为像 TensorFlow 、 PyTorch 、 NumPy 、 Scikit 这样的机器学习和科学计算工具的兴起,这些任务都变得‘琐碎’了。此外,所有这些工具都支持 Python 或基于 Python,因此 Python 是解决这些问题的最合适的选择。

虽然分析部分由这些工具负责,但添加实时通信和实现接近零的延迟也有其自身的挑战——排队、有时限的保证交付和确认、离线交付等。幸运的是,我们有另一个 python 库来拯救我们,mes ibo——它使解决方案变得完整,完全用 Python 编写。

在本文中,我们将学习如何用 Python 开发可扩展的机器学习系统来分析实时数据,这将带来无限的可能性;处理实时股票市场或地理传感器只是一些随机的例子。如果您是 Python 开发人员,您会发现这篇文章是一个很好的起点。

为了分析任何数据,我们首先需要访问数据。因此,在第一部分中,我们将描述如何向 Python 应用程序添加实时通信,如何实时输入源数据并发送输出。然后,我们将在第二部分描述将整个实时平台下载到您的服务器,与您的数据库进行交互,以及添加 Tensorflow 和其他工具。

实时与传统数据处理

在我们使用 mesibo 实时库之前,有必要快速了解一下实时和传统数据处理之间的区别。传统的和当今最主要的数据处理模型基于请求-响应模型,通常称为 REST,被超过 90%的应用程序使用。尽管 REST 对于静态或缓慢变化的数据非常优秀,但它不适合实时数据。实时数据处理应用程序保持实时连接,以零延迟方式发送和接收数据。如果您使用过传统的基于 REST 的 API,您可能会发现实时 API 略有不同,如下所述。

使用 mesibo 实时 Python 库

让我们从在 Python 应用程序中添加实时通信开始。首先,您需要使用pip命令从 Python 包索引中下载 mesibo 库。或者,您也可以从 mesibo Python 库下载库源代码。Mesibo python 库支持所有 Linux 发行版、Mac OS,甚至 Raspberry Pi,因此您可以在几乎所有开发人员友好的平台上下载它。

**pip3 install mesibo**

一旦安装了 mesibo,就可以将 mesibo 导入到 Python 脚本中,如下所示

将 mesibo 导入 Python 脚本

mesibo 有一套定义非常好的 API。它有各种发送实时数据的函数和一个回调接口,一旦接收到实时传入数据就调用该接口。下面的脚本是一个简单的 mesibo 回调示例,当接收到一个实时消息(Mesibo_OnMessage)或者当一个实时消息被发送、传递、读取等时,就会调用这个示例。(Mesibo_OnMessageStatus)。还有更多回调函数,但为了简单起见,这里省略了。

但是,mesibo 不知道您的侦听器类,因此您应该首先向 mesibo 注册它,以便它可以在需要时调用您的侦听器类函数。您可以将它作为初始化的一部分,如下所示(细节将在后面解释)。

梅西博初始化

上面的代码不言自明。

  1. 它创建了一个 mesibo API 的实例。
  2. 通过调用函数*addListener*(),用我们的监听器初始化 mesibo。
  3. 通过调用函数*setAccessToken*()初始化 API 凭证,这将在下一节中解释。
  4. 通过调用函数*setDatabase*()设置数据库以存储收到的消息
  5. 启动 mesibo,通过调用函数*start*()开始发送和接收实时消息

一旦你启动了 mesibo,你不需要做任何事情就可以获得你的实时数据或消息。 您不会像使用 REST API时那样轮询或持续检查新消息。相反,一旦接收到新的实时数据,mesibo 将自动调用监听器函数,没有任何延迟。

但是,您的脚本如何知道谁发送了您刚刚收到的数据,或者如何将数据发送到特定的目的地或组?这就带来了实时端点的概念。

实时端点和地址

当你给你的朋友发电子邮件时,你使用他们的电子邮件地址。同样,当你的朋友收到一封电子邮件时,他们知道这是你发来的,因为邮件中包含了你的电子邮件地址。类似地,在实时系统中,每个端点都有一个地址。端点可以是任何东西,您的 Python 脚本、聊天用户或群组。在 mesibo 中,地址可以是任何唯一的字符串,无论是电子邮件地址、电话号码还是任何随机的唯一字符串。

创建端点
然后,端点使用这些地址相互进行实时通信。当您创建一个端点时,mesibo 会生成一个令牌,您可以在*setAccessToken*()中初始化时使用这个令牌。

例如,您可以通过调用 mesibo 后端 API 创建一个地址为123的端点,

curl 请求调用 mesibo 后端 API

上面请求中的token是 mesibo API 密钥(也称为 App token)。强烈建议您阅读 mesibo 教程以了解如何将 mesibo 后端 API 与您自己的 App token 一起使用。

上面的 API 将返回一个 JSON 响应,

来自 mesibo 后端 API 的 JSON 响应

然后,您可以在 Python *setAccessToken*() API 中使用上述响应中返回的用户令牌。

在初始化 mesibo 和设置 listener 之后,您现在已经设置好了。我们现在将学习如何发送实时数据

发送实时数据

向另一个端点发送实时数据很简单。你只需要指定地址,消息,并调用*api.sendMessage*()函数,

只要发送一条消息,接收端就会立即调用*Mesibo_OnMessage*功能。参考上面的清单,我们已经定义了监听器函数*Mesibo_OnMessage*

同样的,你可以给群发消息,参考梅斯博教程了解更多关于创建群的知识。一旦您向群组发送消息,所有群组成员将立即调用*Mesibo_OnMessage*功能。

运行和测试您的脚本

我们现在准备运行我们的脚本。为了方便起见,完整的脚本在这里,它是从 mesibo Python 库下载的。

要使用您的脚本运行和测试实时通信,如上所述创建两个端点,比如说123456,并为每个端点生成令牌。然后创建脚本的两个副本,并替换每个端点的令牌值。此外,替换另一个端点的目的地地址,例如,如果您使用端点的令牌123,则在 sendMessage 中使用目的地456,反之亦然。

现在运行脚本,您将看到两者都能够向对方发送实时数据。您还会看到连接状态。一旦成功执行了脚本,就可以探索更多的 mesibo APIs 来发送各种数据。

关于第二部分的结论和信息

在第一部分中,我们探索了如何发送和接收实时数据。对于第一部分,我们使用了 mesibo 托管的 API。在第二部分中,我们将学习如何将整个 mesibo 平台下载到您的服务器,将其与您的数据库连接,然后添加 Tensorflow。同时,我建议浏览一下 mesibo 教程,它更详细地描述了本文中显示的步骤。你也可以尝试 mesibo 支持的其他平台(Android、iOS、Javascript、C++),并把它们与你的 Python 脚本接口。

我希望您喜欢阅读第 1 部分,并且能够通过实时通信运行您的脚本。如果您有任何问题,或者您希望我在第二部分中解决一些具体的问题,请发表评论。

创建独立于比例的 SVG 图表

原文:https://towardsdatascience.com/creating-scale-independent-svg-charts-98dfd4a78ba0?source=collection_archive---------36-----------------------

使用皮革优化探索性制图

艾萨克·史密斯在 Unsplash 上拍摄的照片

数据可视化在数据分析中起着重要的作用,因为人眼一看到一些图表或图形,就会试图在图形中找到模式。

数据可视化是使用不同的图/图形/图表直观地表示数据,以找出模式、异常值以及数据集不同属性之间的关系。它是数据的图形表示。

Leather 是一个开源 python 库,用于创建与比例无关的 SVG 图表。它可以绘制你传递给它的任何数据。它完全是用 python 开发的,没有其他依赖。

在这篇文章中,我们将探讨如何使用皮革创建不同的图表和情节。

让我们开始吧…

安装所需的库

我们将开始安装皮革像任何其他图书馆使用 pip 安装。

pip install leather

导入所需的库

在这一步中,我们将导入使用皮革创建图表和绘图所需的库。

import leather

使用皮革创建图表

接下来,我们将开始创建条形图和曲线图:

  1. 条形图
data = [
    (3, 'Hello'),
    (5, 'How'),
    (9, 'Are'),
    (4, 'You')
]chart = leather.Chart('Bars')
chart.add_bars(data)
chart.to_svg('bars.svg')

来源:作者

2。点阵图

data = [
    (0, 3),
    (4, 5),
    (7, 9),
    (8, 4)
]chart = leather.Chart('Dots')
chart.add_dots(data)
chart.to_svg('dots.svg')

来源:作者

3。折线图

data = [
    (0, 3),
    (4, 5),
    (7, 9),
    (8, 4)
]chart = leather.Chart('Line')
chart.add_line(data)
chart.to_svg('lines.svg')

来源:作者

4。使用 CSV 阅读器绘图

import csvimport leatherwith open('gii.csv') as f:
    reader = csv.reader(f)
    next(reader)
    data = list(reader)[:10]for row in data:
        row[1] = float(row[1]) if row[1] is not None else Nonechart = leather.Chart('Data from CSV reader')
chart.add_bars(data, x=1, y=0)
chart.to_svg('csv_reader.svg')

来源:作者

这就是你如何使用皮革创建不同类型的图表和情节。

继续尝试不同的数据集,并让我知道您在回复部分的评论。

本文是与皮尤什·英格尔合作完成的

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

创建可共享的数据可视化报告

原文:https://towardsdatascience.com/creating-shareable-data-visualization-reports-75129aa9cbd6?source=collection_archive---------38-----------------------

使用 Datapane 进行数据分析和可视化

来源:作者

可以使用不同的 Python 库创建用于数据分析的数据可视化。我们只需要创建不同的可视化,如条形图,直方图等。有各种各样的用于数据可视化的 python 库,可以创建 N 种可视化,但是这些可视化的问题是,您不能以报告格式共享它们,也不能将它们嵌入报告中。

创建数据可视化报告有助于进行演示,或者与客户或老板分享。当您创建一个包含可视化和降价的报表时,它会产生良好的影响。此外,您还可以共享这些报告。

Datapane 是一个开源的 python 库,用于创建数据可视化和分析报告,我们可以将所有的可视化和分析汇总到一个报告中,该报告可以在 Datapane 服务器上发布,并可以轻松共享。

让我们开始吧…

创建数据面板帐户

在创建您的报告之前,您首先需要在 Datapane 上创建一个帐户,以便我们可以在该帐户上发布我们的报告,并与任何人共享链接。要创建帐户,您可以通过下面的链接。一旦您创建了一个帐户,您就可以看到一个数据面板访问密钥,我们将使用它从我们的 Jupyter 笔记本上发布我们的报告。

https://datapane.com/accounts/signup/

安装所需的库

我们将从使用 pip 安装 Datapane 开始。下面给出的命令可以做到这一点。

pip install datapane

安装后,我们还将加载用于向我们的帐户发布报告的登录令牌(访问密钥)。

!datapane login --token=<YOUR TOKEN>

导入所需的库

在这一步中,我们将导入所需的库来创建可视化。

import datapane as dp
import pandas as pd
import seaborn as sns

导入数据集

我们将从导入所需的数据集开始。对于本文,我们使用 seaborn 库中已经定义的名为 Tips 的数据集。

df = sns.load_dataset('tips')
df.head()

数据集(来源:作者)

创建可视化

现在,我们将创建一些可视化效果,并添加到我们的报告中。

plot1 = sns.regplot(x="total_bill", y="tip", data=df)
plot2 = df.hist()
plot 3 = df.boxplot(column=['total_bill'])

创建并发布报告

这是最后一步,我们将创建并发布报告。

report = dp.Report(
    dp.Text("Visualization Report"),
    dp.Plot(plot1),
    dp.Plot(plo2),
    dp.Plot(plot3)
)report.publish(name='My First Report', open=True)

发布报告后,您可以在提供给您的链接上看到它,并且可以通过任何人的邮件 id 与他们分享。

继续尝试不同的数据集,为数据分析创建漂亮的可视化报告。如果您发现任何困难,请在回复部分告诉我。

本文是与 Piyush Ingale 合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

使用 Matplotlib 中的线图创建测井数据的简单测井图

原文:https://towardsdatascience.com/creating-simple-well-log-plots-using-the-matplotlib-library-in-python-670325462f9e?source=collection_archive---------20-----------------------

使用 Python 中的 matplotlib 库可视化测井数据与深度

使用 matplotlib Python 库创建的测井曲线。图片作者。

介绍

测井曲线是地球科学和岩石物理学中常用的可视化工具。它们使得沿井眼长度(深度)采集的数据(例如,伽马射线、中子孔隙度、体积密度等)易于可视化。在这些图上,我们在 x 轴上显示测井测量值,在 y 轴上显示测量深度或真实垂直深度。

在这篇短文中,我们将看到如何从一口 Volve 井创建一个简单的测井曲线可视化,该井是 Equinor 在 2018 年作为更大数据集的一部分发布的。

我之前已经在以下文章中介绍了制作这些情节的不同方面:

  • 使用 Python 在测井图上显示岩性数据
  • 用 Python 显示随钻测井(LWD)图像测井
  • 使用绘图填充增强测井曲线的可视化

对于本教程,笔记本可以在这里找到,下面的视频也是附带的。

导入库和加载 LAS 数据

任何 python 项目或笔记本的第一步都是导入所需的库。在这种情况下,我们将使用lasio来加载我们的 las 文件,pandas来存储我们的测井记录数据,而matplotlib用于可视化我们的数据。

import pandas as pd
import lasio
import matplotlib.pyplot as plt

为了读取数据,我们将使用 lasio 库,这是我们在之前的笔记本和视频中探索过的。

las = lasio.read("Data/15-9-19_SR_COMP.LAS")

一旦文件被加载,我们可以通过使用df.head()来检查文件的内容。这将返回数据帧的前五行。

df = las.df()
df.head()

Equinor Volve 数据集 15/9–19-SR 井的前五行

我们可以从返回的结果中看到,我们有几列数据,每列代表测井工具沿井眼移动时进行的测量。

这些列表示以下内容:

  • AC 代表声波压缩慢度
  • 井径仪校准
  • 容积密度的 DEN
  • 伽马射线的 GR
  • 中子孔隙度的 NEU
  • RDEP 深电阻
  • 中等电阻率 RMED

为了更容易使用我们的数据帧,我们可以将设置为深度的数据帧索引转换为数据帧中的列。我们可以通过像这样重置索引来实现这一点。

df.reset_index(inplace=True)

请注意,inplace=True允许我们对原始 dataframe 对象进行更改。

我们可以再次调用df.head()来确保我们的新列已经创建。

df.head()

Equinor Volve 数据集 15/9–19-SR 井的前五行

我们还需要对 DEPT 列稍加重命名,并将其改为 DEPTH

df.rename(columns={'DEPT':'DEPTH'}, inplace=True)df.head()

部门列重命名后,Equinor Volve 数据集 15/9–19-SR 井的前五行

现在我们的数据格式正确,列也标记正确,我们可以继续生成对数图了。

用 Matplotlib 创建测井曲线

创建简单的线形图

通过调用df.plot()并传递我们的两个列,我们可以很容易地创建一个简单的情节

df.plot('GR', 'DEPTH')

伽马射线与深度的简单线图。

当我们运行这个单元格时,我们得到一个非常简单的图,很难阅读,也是颠倒的。

快速支线剧情

如果我们想查看数据框中的所有列,我们可以生成一个子图网格。

这是通过使用与之前相同的线(df.plot())来完成的,我们没有传入曲线名称,而是传入了subplots=True。我们还可以指定一个图形大小(figsize()),它控制图形将显示多大。

df.plot(subplots=True, figsize=(15, 15))

使用 df.plot()的测井数据的多个子图

现在我们可以看到一个网格图,数据框中的每一列都有一个网格图。这是检查我们哪里有数据以及哪里可能有差距的有用方法。

然而,我们对这个情节没有多少控制权。在接下来的章节中,我们将了解如何通过多次测量建立测井曲线。

在 Matplotlib 中使用子情节

在使用 matplotlib 中有许多方法可以生成支线剧情。对于这个特别的教程,我们将使用subplot2grid

fig = plt.subplots(figsize=(10,10))

#Set up the plot axis
ax1 = plt.subplot2grid((1,1), (0,0), rowspan=1, colspan = 1) 

ax1.plot("GR", "DEPTH", data = df, color = "green") # Call the data from the df dataframe
ax1.set_xlabel("Gamma") # Assign a track title
ax1.set_xlim(0, 200) # Change the limits for the curve being plotted
ax1.set_ylim(4700, 3500) # Set the depth range
ax1.grid() # Display the grid

在上面的代码中,我们首先要定义一个图形(fig)并将其赋给plt.subplots。在支线剧情参数中,我们可以传入图形大小,我们将它设置为 10 乘 10。

接下来,我们需要在我们的图形对象上创建一个轴。我们可以通过赋值ax1等于plt.subplot2grid()来做到这一点..我们首先传递子情节网格的形状,在本例中,我们将 1 对 1 设置。

接下来,我们使用索引位置来指定子情节的位置。由于我们只有 1 个子情节,我们将把位置设置为零,零(0,0)。Rowspan 和 colspan 都设置为 1,这意味着它们只有 1 列宽 1 行高。

然后,我们需要告诉 matplotlib 我们想要绘制的内容。在这种情况下,我们将使用 ax1.plot,并传入伽马射线和深度列。

使用 ax 符号,我们可以通过设置 x 和 y 限制以及显示网格来进一步定制绘图。

当我们运行这段代码时,我们生成了下面的图。

太好了!这里我们有了一个更好看的图,现在我们可以开始添加新的轨迹/支线剧情到我们的整体日志图中。

添加电阻率测井

为了给我们的图形添加一个新的轨迹/子图,我们可以重复上面所做的,添加一个新的轴,ax2

然后我们增加布局参数plt.subplot2grid()的第二个数字,所以现在是 1 行,2 列。

对于ax2,我们需要把它放在第二个子情节中,这是通过把位置参数从(0,0)改为(0,1)来完成的。

我们最后得到:

ax1 = plt.subplot2grid((1,2), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,2), (0,1), rowspan=1, colspan = 1)

此外,由于电阻率通常是对数标度,我们需要添加行:ax2.semilogx()

fig = plt.subplots(figsize=(10,10))

#Set up the plot axes
ax1 = plt.subplot2grid((1,2), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,2), (0,1), rowspan=1, colspan = 1)

ax1.plot("GR", "DEPTH", data = df, color = "green") # Call the data from the well dataframe
ax1.set_xlabel("Gamma") # Assign a track title
ax1.set_xlim(0, 200) # Change the limits for the curve being plotted
ax1.set_ylim(4700, 3500) # Set the depth range
ax1.grid() # Display the grid

ax2.plot("RDEP", "DEPTH", data = df, color = "red")
ax2.set_xlabel("Deep Res.")
ax2.set_xlim(0.2, 2000)
ax2.semilogx()
ax2.set_ylim(4700, 3500)
ax2.grid()

使用 matplotlib 创建的伽马射线和电阻率测井图。图片由作者提供。

添加密度日志

要添加第三个轨道/子情节,我们可以通过添加密度作为新的子情节来重复上面的操作。

fig = plt.subplots(figsize=(10,10))

#Set up the plot axes
ax1 = plt.subplot2grid((1,3), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,3), (0,1), rowspan=1, colspan = 1)
ax3 = plt.subplot2grid((1,3), (0,2), rowspan=1, colspan = 1)

ax1.plot("GR", "DEPTH", data = df, color = "green") # Call the data from the well dataframe
ax1.set_xlabel("Gamma") # Assign a track title
ax1.set_xlim(0, 200) # Change the limits for the curve being plotted
ax1.set_ylim(4700, 3500) # Set the depth range
ax1.grid() # Display the grid

ax2.plot("RDEP", "DEPTH", data = df, color = "red")
ax2.set_xlabel("Deep Res.")
ax2.set_xlim(0.2, 2000)
ax2.semilogx()
ax2.set_ylim(4700, 3500)
ax2.grid()

ax3.plot("DEN", "DEPTH", data = df, color = "red")
ax3.set_xlabel("Density")
ax3.set_xlim(1.95, 2.95)
ax3.set_ylim(4700, 3500)
ax3.grid()

使用 matplotlib 创建的伽马射线、电阻率和体积密度测井图。图片由作者提供。

整理常见元素

我们可以从前面的代码片段中看到,我们有许多元素在每个轴调用中都重复出现,比如ax.set_ylim(4700, 3500)。我们可以把它们分开,这样我们只需要调用这些函数一次。这节省了我们需要编写的行数,并使代码更具可读性。

为了实现这一点,我们添加了一个新的 for 循环,它将遍历 fig.axes 中的轴。

for i, ax in enumerate(fig.axes):
    ax.set_ylim(4700, 3500) # Set the depth range
    ax.grid()
    ax.set_xlabel(curve_names[i])

在分离出公共元素后,我们的最终代码如下所示:

fig, axes = plt.subplots(figsize=(10,10))

curve_names = ['Gamma', 'Deep Res', 'Density']

#Set up the plot axes
ax1 = plt.subplot2grid((1,3), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,3), (0,1), rowspan=1, colspan = 1)
ax3 = plt.subplot2grid((1,3), (0,2), rowspan=1, colspan = 1)

ax1.plot("GR", "DEPTH", data = df, color = "green")
ax1.set_xlim(0, 200) 

ax2.plot("RDEP", "DEPTH", data = df, color = "red")
ax2.set_xlim(0.2, 2000)
ax2.semilogx()

ax3.plot("DEN", "DEPTH", data = df, color = "red")
ax3.set_xlim(1.95, 2.95)

for i, ax in enumerate(fig.axes):
    ax.set_ylim(4700, 3500) # Set the depth range
    ax.grid()
    ax.set_xlabel(curve_names[i])

使用 matplotlib 创建的伽马射线、电阻率和体积密度测井图。图片由作者提供。

减少支线剧情之间的间隙

为了更好地整理剧情,我们可以移除每个子情节/轨道之间的深度标签,并减少它们之间的空间。这是通过仅在 ax2 和 ax3 上循环,以及通过调整图之间的填充宽度来实现的。

#Hide tick labels on the y-axis 
for ax in [ax2, ax3]:
    plt.setp(ax.get_yticklabels(), visible = False)

#Reduce the space between each subplot
fig.subplots_adjust(wspace = 0.05)

然后我们得出以下结论:

fig, axes = plt.subplots(figsize=(10,10))

curve_names = ['Gamma', 'Deep Res', 'Density']

#Set up the plot axes
ax1 = plt.subplot2grid((1,3), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,3), (0,1), rowspan=1, colspan = 1)
ax3 = plt.subplot2grid((1,3), (0,2), rowspan=1, colspan = 1)

#Set up the individual log tracks / subplots
ax1.plot("GR", "DEPTH", data = df, color = "green")
ax1.set_xlim(0, 200) 

ax2.plot("RDEP", "DEPTH", data = df, color = "red")
ax2.set_xlim(0.2, 2000)
ax2.semilogx()

ax3.plot("DEN", "DEPTH", data = df, color = "red")
ax3.set_xlim(1.95, 2.95)

#Set up the common elements between the subplots
for i, ax in enumerate(fig.axes):
    ax.set_ylim(4700, 3500) # Set the depth range
    ax.grid()
    ax.set_xlabel(curve_names[i])

#Hide tick labels on the y-axis 
for ax in [ax2, ax3]:
    plt.setp(ax.get_yticklabels(), visible = False)

#Reduce the space between each subplot
fig.subplots_adjust(wspace = 0.05)

移除 y 标签并减少图之间的空白后,使用 matplotlib 创建伽马射线、电阻率和体积密度测井图。图片由作者提供。

为中子孔隙度的子图添加次轴

标准做法是在同一子图/轨迹上绘制体积密度和中子孔隙度。这两条曲线的相互作用使我们能够识别岩性变化和碳氢化合物的存在。

由于两次测量的单位和尺度不同(堆密度为 1.95 至 2.95 g/cc,中子孔隙度为-15 至 60),我们需要使用 twiny 函数在顶部添加另一个子图。这允许我们在图之间使用相同的 y 轴,但是 x 轴可以变化。

使用ax.xaxis.set_ticks_position('top')ax.xaxis.set_label_position('top').将所有标签移动到图的顶部

然后,我们需要修改主 for 循环,以检查何时到达 ax4(当 i = 3 时,因为 Python 从 0 开始索引),然后调整脊椎,使其位于密度标签上方。

fig, axes = plt.subplots(figsize=(10,10))

curve_names = ['Gamma', 'Deep Res', 'Density', 'Neutron']

#Set up the plot axes
ax1 = plt.subplot2grid((1,3), (0,0), rowspan=1, colspan = 1) 
ax2 = plt.subplot2grid((1,3), (0,1), rowspan=1, colspan = 1)
ax3 = plt.subplot2grid((1,3), (0,2), rowspan=1, colspan = 1)
ax4 = ax3.twiny()

#Set up the individual log tracks / subplots
ax1.plot("GR", "DEPTH", data = df, color = "green", lw = 0.5)
ax1.set_xlim(0, 200) 

ax2.plot("RDEP", "DEPTH", data = df, color = "red", lw = 0.5)
ax2.set_xlim(0.2, 2000)
ax2.semilogx()

ax3.plot("DEN", "DEPTH", data = df, color = "red", lw = 0.5)
ax3.set_xlim(1.95, 2.95)

ax4.plot("NEU", "DEPTH", data = df, color = "blue", lw = 0.5)
ax4.set_xlim(45, -15)

#Set up the common elements between the subplots
for i, ax in enumerate(fig.axes):
    ax.set_ylim(4700, 3500) # Set the depth range

    ax.xaxis.set_ticks_position("top")
    ax.xaxis.set_label_position("top")
    ax.set_xlabel(curve_names[i])

    if i == 3:
        ax.spines["top"].set_position(("axes", 1.08))
    else:
        ax.grid()

#Hide tick labels on the y-axis 
for ax in [ax2, ax3]:
    plt.setp(ax.get_yticklabels(), visible = False)

#Reduce the space between each subplot
fig.subplots_adjust(wspace = 0.05)

最终测井曲线显示了轨迹 1 中的伽马射线、轨迹 2 中的电阻率(对数标度)和轨迹 3 中的密度/neturon(每种标度都不同)。图片作者。

摘要

在这个简短的教程中,我们已经讲述了如何使用 matplotlib 显示测井曲线,如何添加多个轨迹/子曲线,以及如何绘制两条曲线。Matplotlib 提供了一种从头构建简单日志图的好方法,是一个值得学习的好库。

感谢阅读!

如果你觉得这篇文章有用,请随时查看我的其他文章,这些文章从不同的角度研究了 Python 和测井数据。你也可以在 GitHub 找到我在这篇文章和其他文章中使用的代码。

如果你想联系我,你可以在LinkedIn或者我的 网站 找到我。

有兴趣了解更多关于 python 和测井数据或岩石物理学的知识吗?跟我上

为机器学习创建合成数据

原文:https://towardsdatascience.com/creating-synthetic-data-for-machine-learning-dab5728f6411?source=collection_archive---------14-----------------------

本教程旨在探索如何创建合成数据来训练对象检测模型

训练本身基于 Jacob Solawetz 关于用 YOLOv5 训练自定义对象的教程

所以我将使用 Ultralytics 的 YOLOv5 库。

本教程将指导您完成创建合成数据所需的步骤,并展示如何使用 YOLOv5 对其进行训练,以便处理真实图像。

如果您想访问完整的脚本或下载数据集,您可以在这个 Git 资源库中找到所有内容。

例如,我将训练分类器来检测树上的橙子。

什么是合成数据,我们为什么需要它?

在一个完美的世界中,数据集将是丰富的,我们可以继续在真实图像上训练我们的模型,以便做出更好的预测。然而在现实中,ML 编码者的大部分时间将花费在收集数据和正确注释上。

像谷歌/脸书/亚马逊/苹果这样的大公司,甚至拥有资源的中型公司,都可以着手启动这样的项目。首先,因为他们有数据本身——在我们的例子中是图像。其次,因为他们有能力对数据进行注释,以创建无错误的数据集。但是,即使这些公司也不能确定数据是否被正确标注,所以正常的流程是对每张图片进行多次标注,然后寻找差异。

对于一个小公司或者像我这样试图从头开始构建一个 ML 项目的人来说,这是一个太大的任务。所以我发现自己在使用网上的一个数据集。有许多很好的数据集,在某些情况下,创建一个新的数据集真的没有必要。但是过了一段时间,我开始意识到我所有的项目都没有完全按照我的要求去做,因为它们是在一种不同的数据上被训练的。

对于这个项目,我想在树上数橘子,但找不到合适的数据集。

所以我开始下载图片,并试图给它们加注释。

举个例子,我从维基媒体的下面这张图片开始。

图片来自维基媒体

这不是一棵完整的树,但是很快我就明白了,我不能给这张图片做注释。

我想我可以试着选择简单的图像,但我不确定在训练网络时它们会如何站起来。

图片来自维基媒体

继续看更复杂的图片,比如这张(也来自维基媒体),我明白这不再是一个选项,并开始摆弄我可以在网上找到的不同数据集。

这不是我想做的,很快我就泄气了。

这是我发现自己在寻找一种不同的解决方案,并观看了亚当·凯利斯(我默塞里极限)的伟大教程,他在其中训练了一个网络,使用合成数据识别杂草。你可以在这里观看他的视频 AI 杂草探测器。

虽然我对结果没有太多印象(他似乎有),因为我需要更好的结果,我意识到如果我要继续这个项目,这是要走的路。

因此,为了适应我需要的新关键词,我开始在谷歌上搜索,找到了下面这篇由 Maryam Rahnemoonfar 和 Clay Sheppard 撰写的论文

在他们继续进行并根据无需起身开始拍摄图像就能生成的数据训练他们的网络之后,这篇论文似乎正是我想要的。更有甚者,他们试图做一些和我正在做的事情非常相似的事情。

他们没有提供数据集,看着他们的照片,我想我可以做得更好。

总的来说,他们建议采取以下步骤

图片来自文章

但在我看来,他们没有考虑到水果可能被树叶遮挡的事实,他们也没有计算边界框。

尽管如此,当我被这个成功的事实所鼓舞时,我开始创建我自己的合成数据。

步伐

我意识到,为了让网络能够统计真实数据,我需要做以下事情

  1. 收集关于我可能遇到的背景的信息

2.创建一个由这些颜色构成的背景图像

3.创建不同大小的圆圈来代替橙子

4.创建一个前景,从树叶的颜色,将阻碍一些橙子

为此,我编写了一个简单的 python 程序,它将为我创建图像—(代码被简化了,所以如果你想下载完整的代码,读者可以很容易地阅读它)

from PIL import Image, ImageDraw
from PIL import ImageFilter
from PIL import ImageColor
from pascal import PascalVOC, PascalObject, BndBox, size_block
from pathlib import Path
import cv2
import numpy as np
import random

我们从一些导入开始,我使用 PIL (pillow)来创建图像,使用 pascal (PascalVoc)来保存信息作为注释。

我从网上下载了一些橘子树的图片,并开始采样像素。他们的颜色被保存到三个数组中的一个

树叶,天空,地面

此时,我没有对橙子取样,因为我对它们使用了不同的方法

def prepare_colors():
    txt_leaves = ['#608d2a', '#a8b146', '#ccf0bc']
    txt_sky = ['#e9e3c3', '#99949e', '#9bb5cf']
    txt_ground = ['#3d2c15', '#dfcba6'] bg_colors = []
    fg_colors = [] for t in txt_leaves:
        bg_colors.append(ImageColor.getrgb(t))
        fg_colors.append(ImageColor.getrgb(t))
    for t in txt_sky:
        bg_colors.append(ImageColor.getrgb(t))
    for t in txt_ground:
        bg_colors.append(ImageColor.getrgb(t)) return bg_colors, fg_colors

这很简单,但值得一提的是,我采样的颜色比上面代码中的多(你可以在 Git 中找到我采样的所有颜色),但为了清晰起见,我减少了采样

下一步是编写一个函数,将颜色随机放置在图层上

def plot_random_color_blobs(draw, colors, count, mins, maxs):
    for i in range(count):
        x = random.randint(0,width)
        y = random.randint(0,height)
        w = random.randint(mins,maxs)
        l = random.randint(mins,maxs)
        c = bg_colors[random.randint(0,len(colors)-1)]
        draw.ellipse((x, y, x+w, y+l), fill=c, outline=None)

这个函数接收一个 ImageDraw。从 PIL 绘制对象,并在随机点添加椭圆计数

假设我们使用了红色、绿色和蓝色,并且使用了大量的计数(在本例中为 1500 ),那么图层的结果可能看起来像这样

所以现在是时候构建背景层了

def create_bg(colors, width, height):
    im_bg = Image.new('RGBA', (width, height), 
                      ImageColor.getrgb('#7FCBFDFF'))
    draw_bg = ImageDraw.Draw(im_bg)
    plot_random_blobs(draw_bg, colors, 1500, 10, 25)
    im_bg = im_bg.filter(ImageFilter.MedianFilter(size=9))
    return im_bg

正如你所看到的,图像是用浅蓝色背景创建的,以消除随机椭圆没有瞄准的任何区域。

绘制完斑点后,我使用模糊滤镜来模糊图像,结果是这样的

这开始看起来好像我是在正确的方向。

但我担心网络会学会如何区分图像的模糊部分和非模糊部分,在我们的例子中是水果,所以我调低了它,并转移到一个 MedianFilter,它允许合并颜色,但仍保留背景的整体清晰度。

接下来,我创建了前景层——这一层将被放置在水果层,以掩盖一些水果

def create_fg(colors, width, height):
    im_fg = Image.new('RGBA', (width, height), (0, 0, 0, 0))
    draw_fg = ImageDraw.Draw(im_fg)
    plot_random_el(draw_fg, colors, 40, 10, 25)
    im_fg = im_fg.filter(ImageFilter.MedianFilter(size=9))
    return im_fg

正如你所看到的,这个函数几乎是相同的,除了我将背景设置为透明,并使用了更少的斑点(40 个)来确保大部分水果都能被看到

最后,是时候创建水果层了

def plot_random_fruit(color_range, count, width, height, mins, 
                       maxs):
    im_fruit = Image.new('RGBA', (width, height), (0, 0, 0, 0))
    draw_fruit = ImageDraw.Draw(im_fruit) fruit_info = []
    for i in range(count):
        x = random.randint(0,width-10)
        y = random.randint(0,height-10)
        w = random.randint(mins,maxs)
        c = (random.randint(color_range[0][0],color_range[0][1]),
             random.randint(color_range[1][0], color_range[1][1]),
             random.randint(color_range[2][0], color_range[2][1]))
        fruit_info.append([x, y, w, w, c])
        draw_fruit.ellipse((x, y, x+w, y+w), fill=c, outline=None)
    return im_fruit, fruit_info

与其他图层相似,这一层在图像周围随机地点绘制水果。然而,这一层有四点不同。

  1. 绘图总是一个圆形,因为这是水果更常见的形状。
  2. 它使用一系列颜色(在我的例子中是所有的橙色变体)来随机选择一种颜色。
  3. 没有给图像分配滤镜。
  4. 该图像将水果的边界框及其颜色存储在一个数组中,该数组作为水果信息返回。
def create_layered_image(im_bg, im_fruit, im_fg):
    img = im_bg.copy()
    img.paste(im_fruit, (0, 0), im_fruit)
    img.paste(im_fg, (0, 0), im_fg)
    return img

最后一个函数只是将图像一个接一个地粘贴起来

结果会像这样

显然,这看起来不像一棵果树,但它包括网络可能需要看到的正确颜色和情况,以便能够正确训练。

下一步是创建一个注释文件,我决定使用 PascalObject,因为我对它更熟悉,但是其他任何注释都可以。

def create_annotation(img, fruit_info, obj_name,
                      img_name ,ann_name):
    pobjs = []
    for i in range(len(fruit_info)):
        pct = 0
        circle = fruit_info[i]
        color = circle[4]
        for i in range(circle[2]):
            if (circle[0]+i >= width):
                continue;
            for j in range(circle[3]):
                if (circle[1]+j >= height):
                    continue;
                r = img.getpixel((circle[0]+i, circle[1]+j))
                if (r[0] == color[0]):
                    pct = pct +1
        diffculty = pct/(circle[2]*circle[3]) if (diffculty > 0.1):
            dif = True
            if (diffculty > 0.4):
                dif = False
            pobjs.append(
                PascalObject(obj_name, "", truncated=False,
                             difficult=dif,
                             bndbox=BndBox(circle[0], circle[1],
                                           circle[0]+circle[2],
                                           circle[1]+circle[3])))
    pascal_ann = PascalVOC(img_name,
                           size=size_block(width, height, 3),
                           objects=pobjs)
    pascal_ann.save(ann_name)

在将边界框添加到注释之前,该函数检查有多少水果没有被前景遮挡。这使得网络可以决定在计算这个水果时的错误是否严重。

然而,PascalObject 中的难度参数是一个布尔值,所以我选择以下 3 个截止点。如果看到的水果少于 10%,我就简单地忽略该信息,任何被遮挡超过 40%的水果都被认为是困难的。

把所有这些放在一起,我现在准备开始生成图像

def create_training_image(counter, bg_colors, fg_colors,
                          fruit_color_range):
    fruit_count = random.randint(0, 20)
    ext = '{}_{}'.format(counter, fruit_count)
    img_name = '{}/fruit_{}.png'.format(img_path, ext)
    ann_name = '{}/ann_{}.xml'.format(ann_path, ext) im_bg = create_bg(bg_colors, width, height)
    im_fg = create_fg(fg_colors, width, height)
    im_fruit, fruit_info = plot_random_fruit(fruit_color_range,
                                             fruit_count, width, 
                                             height, 10, 25)
    img = create_layered_image(im_bg, im_fruit, im_fg) #create the anootation File
    create_annotation(img, fruit_info, 'oranges',
                      img_name, ann_name)
    img.save(img_name)
    return img, img_name, ann_name

这个函数现在应该是不言自明的,并且创建一个单独的图像及其注释文件。

现在为了制作更多的图像,我补充道

def create_training_set(num, start_at=0):
    bg_colors, fg_colors = prepare_colors()
    fruit_color_range = [[180,230],[50,130],[0,5]]
    for i in range(num):
        create_training_image(num+start_at, bg_colors,
                              fg_colors, fruit_color_range)

结果是

为测试而创建的批次中的 3 个样品

创建数据集

一旦我准备好了图像和注释,我就按照 Solawetz 教程进行操作,并使用 Roboflow 将其转换为 YOLOv5 的可读数据集——由于 Roboflow 免费使用的最大图像量是 1000 张图像,我确保不要创建太多图像,未来我将尝试通过简单地在代码中创建数据集来克服这一点,但现在应该可以了。

按照 Roboflow 设置中简单的 5 个步骤,我能够在几分钟内构建数据集。

我选择在这一点上不创建增强,但最终将它们用于缩放目的,以允许网络检测更大的对象。

训练网络

根据 Solawetz 的教程设置环境后,培训减少到一行代码

%%time
%cd /content/yolov5/!python train.py --img 416 --batch 16 --epochs 100 --data '../data.yaml' --cfg ./models/custom_yolov5s.yaml --weights '' --name yolov5s_results  --cache

为了训练你自己的模型,我建议看看罗博弗洛的笔记本。

我最初写了我自己的笔记本,可以在 Git 资源库中找到,但在查看后,我发现上面的笔记本只是写得更好,所以向他们致敬:)。

由于我更习惯于使用 Tensorflow,而不太熟悉 PyTorch,并且由于培训的目的是测试合成数据,所以我选择不更改培训代码,也不尝试调整它。将来,我也打算探索这个问题。

仅仅过了几分钟(在使用 Collab 的 GPU 上运行)和仅仅运行 100 个 epochs,我就获得了精度接近 91%的训练结果。事实上,该网络能够在不到 40 个纪元的时间内收敛到这样的精度。惊艳。

但是当然,这都是基于合成数据。

是检验真实数据的时候了。

一如既往,图片胜过 1000 字。

对真实图像的推理结果

警告

并不是所有的都很完美。

具有占据屏幕大部分的大橙子的图像效果不好,我猜这是因为我的训练集中的所有橙子都相对较小。我使用带有 zoom 增强功能的 Roboflows 增强功能重新训练了数据集,并获得了更好的结果。但在进一步的测试中,我计划创建包括更大范围的斑点和橙色尺寸的图像。

为背景选择的颜色可能是至关重要的——在我的第一次测试中,我没有添加任何可能出现在图像中的通用颜色,如肤色,在某些情况下,它选择了橙色。但是在背景色中加入一些肤色之后,这个问题似乎就消失了。

结论

总之,使用合成数据被证明是有用和容易的。

我可以很容易地在视频上运行它,因为 Yolov5s 非常快,它实际上可以实时运行。

如果你想下载完整的代码和数据集,你可以查看我的 Git

我现在进入下一步,将通过许多不同的框架跟踪这些橙子,以允许在不同的视图中进行更强的验证,并最终进行作物估计。

诚挚的问候

大阿米佐拉赫