TowardsDataScience-博客中文翻译-2016-2018-二百三十七-

38 阅读1小时+

TowardsDataScience 博客中文翻译 2016~2018(二百三十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

金融 Python:股票投资组合分析

原文:towardsdatascience.com/python-for-…

我最近的两篇博文是关于用 Python 扩展分析洞察力的;第一部分可以在这里找到,第二部分可以在这里找到。我写这些已经有几个月了,主要是因为去年 11 月我把家搬到了西雅图,加入了亚马逊;我花了大部分时间在我的主要项目上,确定我们的全球推广计划和相关的商业智能路线图。

在我离开我以前的公司 FloSports 之前,我们正在对整个组织的分析报告进行彻底检查(数据、营销、产品等),这次彻底检查的一部分包括我们的财务报告。虽然我很早就离开了这个实现,但在过去的几个月里,我继续广泛使用 Python 进行财务分析,尤其是pandas。在这篇文章中,我将分享我如何利用一些非常有用的在线资源,Yahoo Finance API(需要一个解决方案,可能需要未来的数据源替换),以及Jupyter notebook来在很大程度上自动跟踪和衡量股票投资组合的表现。

PME 和基准个股表现概述

作为一个快速的背景,我从 2002 年开始投资我自己的股票投资组合,并在几年前为我的投资组合开发了一个金融模型。多年来,我会下载历史价格并将数据加载到金融模型中——虽然在线经纪人计算已实现和未实现的回报,以及收入和股息,但我喜欢在模型中拥有历史数据,因为我自己进行分析来评估头寸。我从未在在线经纪人和服务中发现的一个观点/报告是类似于“公共市场等价物”的分析。简而言之,公开市场等价物(PME)是私募股权行业中使用的一组分析,用于比较私募股权基金相对于行业基准的表现。更多细节在这里。

与此相关,绝大多数股票投资组合经理无法选择长期表现优于大盘(如标准普尔 500)的股票投资组合(20 只积极管理的国内基金中有 1 只跑赢指数基金)。即使一些个股表现出色,其他股票的表现不佳也往往超过表现更好的股票,这意味着总体而言,投资者的情况比单纯投资指数基金更糟。在商学院期间,我了解了 PME,并把一个概念上类似的分析纳入了对我目前持有的公共股票的评估。为了正确地做到这一点,你应该衡量每个投资组合头寸(持有期)相对于相同持有期内标准普尔 500 等值美元投资的投资流入时间。举例来说,如果你在 2016 年 6 月 1 日购买了一只股票,并且你仍然持有它,你会想要比较这只股票在这一时期的回报率与 2016 年 6 月 1 日同等美元投资在标准普尔 500 指数中的回报率(我们的基准例子)。除此之外,你可能会发现,即使一只股票表现相对较好,它仍可能落后于同期标准普尔 500 指数的回报。

过去,我从雅虎财经(Yahoo Finance)下载历史价格数据,并在 excel 中使用指数和匹配功能来计算每个头寸相对于标准普尔 500 的相对持有期表现。虽然这是实现这一目标的好方法,但在 Jupyter notebook 中使用pandas进行同样的操作更具可伸缩性和可扩展性。每当您下载新数据并加载到 excel 中时,您不可避免地需要修改一些公式并验证错误。使用pandas,添加新的计算,比如累积 ROI 倍数(我将介绍),几乎不需要时间就可以实现。我使用Plotly的视觉化效果是高度可重复的,在产生洞察力方面更有用。

披露: 本帖无任何内容应视为投资建议。过去的表现不一定代表未来的回报。这些是关于如何使用 pandas 导入不同时间间隔的小样本股票数据,并根据某个指数衡量其个别表现的一般示例。你应该向你的财务顾问提出所有与投资相关的问题。

除了贡献本教程之外,我还将继续修改和构建这种方法,并在本文的最后概述了进一步开发的一些考虑因素。我相信这篇文章会对初级到中级的面向数据科学的金融专业人士有所帮助,特别是因为这应该扩展到许多其他类型的金融分析。这种方法是“类似 PME”的,因为它在相等的持有期内测量投资流入。由于公开市场投资比私募股权投资更具流动性,并且假设你遵循跟踪止损方法,在我看来,更重要的是专注于积极持股——通常可取的做法是减持表现低于基准的股票,或者出于各种原因你不再想持有的股票,而我采取长期观点,只要他们拥有我,我就很高兴持有表现出色的股票。

资源:

  • 我目前是 DataCamp 的订户(未来的帖子将在 DataCamp 上发布),这个关于 Python 金融的社区教程非常棒
  • 我为这篇文章创建了回购,包括 Python 笔记本和 excel 文件
  • 如果你想看完整的互动版(因为 Jupyter > GitHub 集成太牛逼了),可以在这里用 nbviewer 查看。

我们想要实现的目标概述:

  • 使用 Yahoo Finance API 导入标准普尔 500 和样本股票数据
  • 创建一个合并的投资组合“主”文件,该文件将样本投资组合数据框架与历史股票行情和历史标准普尔 500 数据相结合
  • 确定每笔投资收购日的标准普尔 500 收盘价,这样我们就可以用同样的投资金额计算标准普尔 500 的等价股票头寸
  • 计算这段时间内投资组合头寸相对于标准普尔 500 回报的相对百分比和美元价值回报
  • 计算累积投资组合回报和投资回报率倍数,以评估该示例投资组合与市场指数相比的表现
  • 更重要的一点是:动态计算每个头寸相对于跟踪止损的表现,例如,如果一个头寸收盘时比收盘高点低 25%,考虑在下一个交易日卖出该头寸。
  • 形象化
  • 总回报比较——每个头寸相对于指数基准的回报百分比
  • 一段时间内的累积回报——每个头寸相对于基准的收益/(损失)
  • 一段时间内的累计投资——鉴于上述情况,与同等权重和时间周期的标准普尔 500 投资相比,总体投资回报如何?
  • 最高价比较的调整收盘百分比——自买入以来,每个头寸相对于其调整收盘最高价的最近收盘百分比是多少?

投资组合 Python 笔记本

数据导入和数据框操作

您将从导入必要的 Python 库开始,导入Plotly离线模块,并读入我们的样例组合数据框架。

*# Import initial libraries*import pandas **as** pd
import numpy **as** np
import datetime
import matplotlib.pyplot **as** plt
import plotly.graph_objs **as** go
**%**matplotlib inline*# Imports in order to be able to use Plotly offline.*
from plotly import __version__
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot**print**(__version__) *# requires version >= 1.9.0*init_notebook_mode(connected**=**True)*# Import the Sample worksheet with acquisition dates and initial cost basis:*portfolio_df **=** pd**.**read_excel('Sample stocks acquisition dates_costs.xlsx', sheetname**=**'Sample')portfolio_df**.**head(10)

现在,您已经阅读了样本投资组合文件,您将创建几个变量来捕获标准普尔 500 和所有投资组合报价机的日期范围。请注意,这是该笔记本要求每周更新的少数几个方面之一(调整日期范围,以包括最近的交易周,在这里,我们正在运行截至 2018 年 3 月 9 日的价格)。

*# Date Ranges for SP 500 and for all tickers*
*# Modify these date ranges each week.**# The below will pull back stock prices from the start date until end date specified.*
start_sp **=** datetime**.**datetime(2013, 1, 1)
end_sp **=** datetime**.**datetime(2018, 3, 9)*# This variable is used for YTD performance.*
end_of_last_year **=** datetime**.**datetime(2017, 12, 29)*# These are separate if for some reason want different date range than SP.*
stocks_start **=** datetime**.**datetime(2013, 1, 1)
stocks_end **=** datetime**.**datetime(2018, 3, 9)

正如 Python 金融培训帖子中提到的,pandas-datareader包使我们能够从像 Google、Yahoo!金融与世界银行。这里我将重点介绍雅虎!金融,尽管我已经和 Quantopian 初步合作过,并且也已经开始把quandl作为一个数据源。正如 DataCamp 帖子中提到的,Yahoo API 端点最近发生了变化,这需要安装一个临时修复程序,以便 Yahoo!金融到工作。我在下面的代码中做了一些必要的小调整。我注意到一些小的数据问题,数据并不总是如预期的那样读入,或者最后一个交易日有时会丢失。虽然这些问题相对较少,但我会继续关注雅虎!金融将是未来最好、最可靠的数据来源。

*# Leveraged from the helpful Datacamp Python Finance trading blog post.*from pandas_datareader import data **as** pdr
import fix_yahoo_finance **as** yf
yf**.**pdr_override() *# <== that's all it takes :-)*sp500 **=** pdr**.**get_data_yahoo('^GSPC', 
                           start_sp,
                             end_sp)

sp500**.**head()

如果你用你自己的笔记本在跟踪,一旦你成功地从雅虎的 API 中读取数据,你应该会看到类似下面的内容:

在加载标准普尔 500 数据后,您将看到我检查了数据帧的头部和尾部,并压缩数据帧,使其只包含Adj Close列。Adjusted Close栏和Close栏的不同之处在于,调整后的收盘反映了股息(参见下面的未来发展领域)。当一家公司派发股息时,股价会因每股股息的大小而下跌,因为该公司正在分配公司收益的一部分。为了这个分析的目的,您只需要分析这个列。我还创建了一个数据框架,其中只包括标准普尔在 2017 年最后一天(2018 年初)调整后的收盘价;这是为了对单个股票相对于标准普尔 500 指数的表现进行年初至今的比较。

在下面的代码中,您在我们的投资组合样本数据框架中创建了一个所有报价机的数组。然后,您编写一个函数,将所有报价机及其相关数据读入一个新的数据框架,这与您对 S&P500 采取的方法基本相同,但适用于投资组合的所有报价机。

*# Generate a dynamic list of tickers to pull from Yahoo Finance API based on the imported file with tickers.*
tickers **=** portfolio_df['Ticker']**.**unique()
tickers*# Stock comparison code***def** **get**(tickers, startdate, enddate):
    **def** **data**(ticker):
        **return** (pdr**.**get_data_yahoo(ticker, start**=**startdate, end**=**enddate))
    datas **=** map(data, tickers)
    **return**(pd**.**concat(datas, keys**=**tickers, names**=**['Ticker', 'Date']))

all_data **=** get(tickers, stocks_start, stocks_end)

与标准普尔 500 数据框架一样,您将创建一个adj_close数据框架,其中只有用于您所有股票报价机的Adj Close列。如果你看看我上面链接的 repo 中的笔记本,这段代码被分成了比下面更多的代码块。为了在这里进行描述,我在下面列出了导致我们最初的merged_portfolio数据帧的所有代码。

*# Also only pulling the ticker, date and adj. close columns for our tickers.*adj_close **=** all_data[['Adj Close']]**.**reset_index()
adj_close**.**head()*# Grabbing the ticker close from the end of last year*
adj_close_start **=** adj_close[adj_close['Date']**==**end_of_last_year]
adj_close_start**.**head()*# Grab the latest stock close price*adj_close_latest **=** adj_close[adj_close['Date']**==**stocks_end]
adj_close_latestadj_close_latest**.**set_index('Ticker', inplace**=**True)
adj_close_latest**.**head()*# Set portfolio index prior to merging with the adj close latest.*
portfolio_df**.**set_index(['Ticker'], inplace**=**True)portfolio_df**.**head()*# Merge the portfolio dataframe with the adj close dataframe; they are being joined by their indexes.*merged_portfolio **=** pd**.**merge(portfolio_df, adj_close_latest, left_index**=**True, right_index**=**True)
merged_portfolio**.**head()*# The below creates a new column which is the ticker return; takes the latest adjusted close for each position*
*# and divides that by the initial share cost.*merged_portfolio['ticker return'] **=** merged_portfolio['Adj Close'] **/** merged_portfolio['Unit Cost'] **-** 1merged_portfolio

根据你对pandas的熟悉程度,这将会非常简单,甚至有点让人不知所措。下面,我将解开这些行是做什么的:

  • 你所采取的整体方法是一个分割-应用-组合的例子(注意这下载了一个 PDF)。
  • all_data[['Adj Close']]行创建一个新的 dataframe,只包含列表中提供的列;这里Adj Close是列表中唯一提供的项目。
  • 使用这一行代码adj_close[adj_close['Date']==end_of_last_year],您将过滤adj_close数据帧,只过滤数据的Date列等于您之前在end_of_last_year变量(2017,12,29)中指定的日期的行。
  • 您还可以设置adj_close_latestportfolio_df数据帧的索引。我这样做是因为这是合并两个数据帧的方法。merge函数非常类似于 SQL 连接,是我经常使用的一个非常有用的函数。
  • merge函数中,指定左侧数据帧(portfolio_df)和右侧数据帧(adj_close_latest)。通过指定left_indexright_index等于 True,您声明这两个数据帧共享一个公共索引,并且您将在这个索引上连接这两个数据帧。
  • 最后,创建一个名为'ticker return'的新列。这通过将Adj Close除以Unit Cost(股票的初始购买价格)并减去 1 来计算每个股票头寸的百分比回报。这类似于在 excel 中计算一个公式并将其携带下来,但在pandas中,这是用一行代码完成的。

你已经获得了标准普尔 500 和个股的单个数据框架,你开始开发一个“主”数据框架,我们将使用它进行计算、可视化和任何进一步的分析。接下来,您将进一步使用 pandas merge函数,继续构建这个“主”数据框架。下面,您重置当前数据帧的索引,并开始将较小的数据帧与主数据帧连接起来。同样,下面的代码块在Jupyter笔记本中被进一步分解;在这里,我采取了与之前类似的方法,我将分享下面的代码,然后分解代码块下面的关键标注。

merged_portfolio**.**reset_index(inplace**=**True)*# Here we are merging the new dataframe with the sp500 adjusted closes since the sp start price based on* 
*# each ticker's acquisition date and sp500 close date.*merged_portfolio_sp **=** pd**.**merge(merged_portfolio, sp_500_adj_close, left_on**=**'Acquisition Date', right_on**=**'Date')
*# .set_index('Ticker')**# We will delete the additional date column which is created from this merge.*
*# We then rename columns to Latest Date and then reflect Ticker Adj Close and SP 500 Initial Close.***del** merged_portfolio_sp['Date_y']merged_portfolio_sp**.**rename(columns**=**{'Date_x': 'Latest Date', 'Adj Close_x': 'Ticker Adj Close'
                                    , 'Adj Close_y': 'SP 500 Initial Close'}, inplace**=**True)*# This new column determines what SP 500 equivalent purchase would have been at purchase date of stock.*
merged_portfolio_sp['Equiv SP Shares'] **=** merged_portfolio_sp['Cost Basis'] **/** merged_portfolio_sp['SP 500 Initial Close']
merged_portfolio_sp**.**head()*# We are joining the developing dataframe with the sp500 closes again, this time with the latest close for SP.*
merged_portfolio_sp_latest **=** pd**.**merge(merged_portfolio_sp, sp_500_adj_close, left_on**=**'Latest Date', right_on**=**'Date')*# Once again need to delete the new Date column added as it's redundant to Latest Date.* 
*# Modify Adj Close from the sp dataframe to distinguish it by calling it the SP 500 Latest Close.***del** merged_portfolio_sp_latest['Date']merged_portfolio_sp_latest**.**rename(columns**=**{'Adj Close': 'SP 500 Latest Close'}, inplace**=**True)merged_portfolio_sp_latest**.**head()
  • 使用merged_portfolio上的reset_index来展平主数据框,并连接较小数据框的相关列。
  • merged_portfolio_sp行,将当前主数据帧(merged_portfolio)与sp_500_adj_close合并;你这样做是为了得到标准普尔在每个头寸购买日的收盘价——这允许你跟踪标准普尔在持有每个头寸的同一时间段(从购买日到最近的市场收盘日)的表现。
  • 这里的合并与之前略有不同,我们在左侧数据帧的Acquisition Date列和右侧数据帧的Date列进行了连接。
  • 完成合并后,您将拥有不需要的额外列——因为我们的主数据框架最终将拥有大量用于分析的列,所以在此过程中删除重复和不必要的列非常重要。
  • 有几种方法可以删除不必要的列并执行各种列名清理;为了简单起见,我使用python del,然后用熊猫rename的方法重命名几列,通过重命名为Ticker Adj Close来澄清股票代码的Adj Close列;你可以用SP 500 Initial Close来区分 S & P 的初始调整关闭。
  • 当您计算merged_portfolio_sp['Equiv SP Shares']时,您这样做是为了能够计算出在您获得每个股票头寸的日期收盘时标准普尔 500 的等值:如果您在一个新的股票头寸上花费了 5000 美元,您可能已经在标准普尔 500 上花费了 5000 美元;继续这个例子,如果标准普尔 500 指数在购买时的交易价格是每股 2500 美元,你就可以购买 2 股。之后,如果标准普尔 500 指数的交易价格为每股 3000 美元,你的股份将价值 6000 美元(相当于 2 股*每股 3000 美元),在可比的时间段内,你将有 1000 美元的账面利润。
  • 在代码块的其余部分,您接下来执行类似的合并,这一次加入标准普尔 500 的最新收盘数据—这提供了计算 S&P 相对于每个头寸持有期的可比回报所需的第二部分:每个股票收购日的标准普尔 500 价格和标准普尔 500 的最新收盘数据。

现在,您已经用以下内容进一步开发了您的“主”数据框架:

  • 每个投资组合头寸在头寸收购日的价格、份额和价值,以及最新的市场收盘价。
  • 每只股票在等价头寸收购日的等价标准普尔 500 价格、股份和价值,以及最新的标准普尔 500 收盘价。

鉴于上述情况,您接下来将执行必要的计算,以比较每个头寸的表现,以及该策略/一篮子股票相对于可比美元投资和标准普尔 500 持有时间的整体表现。

下面是您添加到“主”数据框架的新列的摘要。

  • 在第一列['SP Return']中,您创建了一个列来计算标准普尔 500 指数在每个头寸的持有期内的绝对百分比回报(注意,这是绝对回报,而不是年化回报)。在第二列(['Abs. Return Compare'])中,您比较了同一时间段内['ticker return'](每个仓位的回报)与['SP Return']
  • 在接下来的三列['Ticker Share Value']['SP 500 Value']['Abs Value Compare']中,我们根据我们持有的股票乘以最新调整后的收盘价来计算美元价值(市值)(并从股票行情自动收录器中减去 S & P 回报,以计算超额/(低于)业绩)。
  • 最后,['Stock Gain / (Loss)']['SP 500 Gain / (Loss)']栏计算我们每个头寸的未实现美元损益和可比标准普尔 500 的损益;这让我们能够比较每个头寸与简单地将这些美元投资于标准普尔 500 指数的价值影响。
*# Percent return of SP from acquisition date of position through latest trading day.*
merged_portfolio_sp_latest['SP Return'] **=** merged_portfolio_sp_latest['SP 500 Latest Close'] **/** merged_portfolio_sp_latest['SP 500 Initial Close'] **-** 1*# This is a new column which takes the tickers return and subtracts the sp 500 equivalent range return.*
merged_portfolio_sp_latest['Abs. Return Compare'] **=** merged_portfolio_sp_latest['ticker return'] **-** merged_portfolio_sp_latest['SP Return']*# This is a new column where we calculate the ticker's share value by multiplying the original quantity by the latest close.*
merged_portfolio_sp_latest['Ticker Share Value'] **=** merged_portfolio_sp_latest['Quantity'] ***** merged_portfolio_sp_latest['Ticker Adj Close']*# We calculate the equivalent SP 500 Value if we take the original SP shares * the latest SP 500 share price.*
merged_portfolio_sp_latest['SP 500 Value'] **=** merged_portfolio_sp_latest['Equiv SP Shares'] ***** merged_portfolio_sp_latest['SP 500 Latest Close']*# This is a new column where we take the current market value for the shares and subtract the SP 500 value.*
merged_portfolio_sp_latest['Abs Value Compare'] **=** merged_portfolio_sp_latest['Ticker Share Value'] **-** merged_portfolio_sp_latest['SP 500 Value']*# This column calculates profit / loss for stock position.*
merged_portfolio_sp_latest['Stock Gain / (Loss)'] **=** merged_portfolio_sp_latest['Ticker Share Value'] **-** merged_portfolio_sp_latest['Cost Basis']*# This column calculates profit / loss for SP 500.*
merged_portfolio_sp_latest['SP 500 Gain / (Loss)'] **=** merged_portfolio_sp_latest['SP 500 Value'] **-** merged_portfolio_sp_latest['Cost Basis']merged_portfolio_sp_latest**.**head()

现在,您已经了解了将您的投资组合的表现与同等投资于标准普尔 500 的投资组合进行比较所需的内容。接下来的两个代码块部分允许您 I)比较每个头寸相对于标准普尔 500 的 YTD 表现(衡量动量和您的头寸如何调整),以及 ii)比较每个投资组合头寸相对于其最近收盘高点的最近收盘价(这允许您评估头寸是否触发了跟踪止损,例如,收盘时比收盘高点低 25%。

下面,我将从 YTD 性能代码块开始,并在下面进一步提供有关代码的细节。

*# Merge the overall dataframe with the adj close start of year dataframe for YTD tracking of tickers.*merged_portfolio_sp_latest_YTD **=** pd**.**merge(merged_portfolio_sp_latest, adj_close_start, on**=**'Ticker')
*# , how='outer'**# Deleting date again as it's an unnecessary column.  Explaining that new column is the Ticker Start of Year Close.***del** merged_portfolio_sp_latest_YTD['Date']merged_portfolio_sp_latest_YTD**.**rename(columns**=**{'Adj Close': 'Ticker Start Year Close'}, inplace**=**True)*# Join the SP 500 start of year with current dataframe for SP 500 ytd comparisons to tickers.*merged_portfolio_sp_latest_YTD_sp **=** pd**.**merge(merged_portfolio_sp_latest_YTD, sp_500_adj_close_start
                                             , left_on**=**'Start of Year', right_on**=**'Date')*# Deleting another unneeded Date column.***del** merged_portfolio_sp_latest_YTD_sp['Date']*# Renaming so that it's clear this column is SP 500 start of year close.*
merged_portfolio_sp_latest_YTD_sp**.**rename(columns**=**{'Adj Close': 'SP Start Year Close'}, inplace**=**True)*# YTD return for portfolio position.*
merged_portfolio_sp_latest_YTD_sp['Share YTD'] **=** merged_portfolio_sp_latest_YTD_sp['Ticker Adj Close'] **/** merged_portfolio_sp_latest_YTD_sp['Ticker Start Year Close'] **-** 1*# YTD return for SP to run compares.*
merged_portfolio_sp_latest_YTD_sp['SP 500 YTD'] **=** merged_portfolio_sp_latest_YTD_sp['SP 500 Latest Close'] **/** merged_portfolio_sp_latest_YTD_sp['SP Start Year Close'] **-** 1
  • 创建merged_portfolio_sp_latest_YTD数据帧时,您现在将“主”数据帧与adj_close_start数据帧合并;作为一个快速提醒,您是通过过滤adj_close数据帧来创建这个数据帧的,其中'Date'列等于变量end_of_last_year;你这样做是因为这是衡量 YTD(年初至今)股票和指数表现的方法;去年的收盘价格是下一年的起始价格。
  • 从这里开始,我们再次使用del删除不必要的列,并使用rename方法阐明“主”数据帧新添加的列。
  • 最后,我们获取每个股票(在['Ticker Adj Close']列中)并计算每个股票的 YTD 回报(对于'SP 500 Latest Close'列中的每个值,我们还有一个 S & P 500 等值)。

在下面的代码块中,您使用sort_values方法对我们的“主”数据框架进行重新排序,然后计算累积投资组合投资(您的持仓获取成本的总和),以及投资组合持仓的累积价值和理论标准普尔 500 指数投资的累积价值。这使你能够看到你的总投资组合,包括在整个期间不同时间的投资,与你只投资于一个指数的策略相比是如何的。稍后,您将使用['Cum Ticker ROI Mult']来帮助您形象化每项投资对您的总体投资回报(ROI)的贡献或减少。

merged_portfolio_sp_latest_YTD_sp **=** merged_portfolio_sp_latest_YTD_sp**.**sort_values(by**=**'Ticker', ascending**=**True)*# Cumulative sum of original investment*
merged_portfolio_sp_latest_YTD_sp['Cum Invst'] **=** merged_portfolio_sp_latest_YTD_sp['Cost Basis']**.**cumsum()*# Cumulative sum of Ticker Share Value (latest FMV based on initial quantity purchased).*
merged_portfolio_sp_latest_YTD_sp['Cum Ticker Returns'] **=** merged_portfolio_sp_latest_YTD_sp['Ticker Share Value']**.**cumsum()*# Cumulative sum of SP Share Value (latest FMV driven off of initial SP equiv purchase).*
merged_portfolio_sp_latest_YTD_sp['Cum SP Returns'] **=** merged_portfolio_sp_latest_YTD_sp['SP 500 Value']**.**cumsum()*# Cumulative CoC multiple return for stock investments*
merged_portfolio_sp_latest_YTD_sp['Cum Ticker ROI Mult'] **=** merged_portfolio_sp_latest_YTD_sp['Cum Ticker Returns'] **/** merged_portfolio_sp_latest_YTD_sp['Cum Invst']merged_portfolio_sp_latest_YTD_sp**.**head()

现在,您已经接近尾声,几乎准备好开始可视化您的数据,并评估您的投资组合的单个股票和整体策略表现的优势和劣势。

和以前一样,我包含了主要的代码块,用于确定头寸相对于最近收盘价的交易位置;然后,我将在下面进一步解包代码。

*# Need to factor in that some positions were purchased much more recently than others.*
*# Join adj_close dataframe with portfolio in order to have acquisition date.*portfolio_df**.**reset_index(inplace**=**True)adj_close_acq_date **=** pd**.**merge(adj_close, portfolio_df, on**=**'Ticker')*# delete_columns = ['Quantity', 'Unit Cost', 'Cost Basis', 'Start of Year']***del** adj_close_acq_date['Quantity']
**del** adj_close_acq_date['Unit Cost']
**del** adj_close_acq_date['Cost Basis']
**del** adj_close_acq_date['Start of Year']*# Sort by these columns in this order in order to make it clearer where compare for each position should begin.*
adj_close_acq_date**.**sort_values(by**=**['Ticker', 'Acquisition Date', 'Date'], ascending**=**[True, True, True], inplace**=**True)*# Anything less than 0 means that the stock close was prior to acquisition.*
adj_close_acq_date['Date Delta'] **=** adj_close_acq_date['Date'] **-** adj_close_acq_date['Acquisition Date']adj_close_acq_date['Date Delta'] **=** adj_close_acq_date[['Date Delta']]**.**apply(pd**.**to_numeric)*# Modified the dataframe being evaluated to look at highest close which occurred after Acquisition Date (aka, not prior to purchase).*adj_close_acq_date_modified **=** adj_close_acq_date[adj_close_acq_date['Date Delta']**>=**0]*# This pivot table will index on the Ticker and Acquisition Date, and find the max adjusted close.*adj_close_pivot **=** adj_close_acq_date_modified**.**pivot_table(index**=**['Ticker', 'Acquisition Date'], values**=**'Adj Close', aggfunc**=**np**.**max)adj_close_pivot**.**reset_index(inplace**=**True)*# Merge the adj close pivot table with the adj_close table in order to grab the date of the Adj Close High (good to know).*adj_close_pivot_merged **=** pd**.**merge(adj_close_pivot, adj_close
                                             , on**=**['Ticker', 'Adj Close'])*# Merge the Adj Close pivot table with the master dataframe to have the closing high since you have owned the stock.*merged_portfolio_sp_latest_YTD_sp_closing_high **=** pd**.**merge(merged_portfolio_sp_latest_YTD_sp, adj_close_pivot_merged
                                             , on**=**['Ticker', 'Acquisition Date'])*# Renaming so that it's clear that the new columns are closing high and closing high date.*
merged_portfolio_sp_latest_YTD_sp_closing_high**.**rename(columns**=**{'Adj Close': 'Closing High Adj Close', 'Date': 'Closing High Adj Close Date'}, inplace**=**True)merged_portfolio_sp_latest_YTD_sp_closing_high['Pct off High'] **=** merged_portfolio_sp_latest_YTD_sp_closing_high['Ticker Adj Close'] **/** merged_portfolio_sp_latest_YTD_sp_closing_high['Closing High Adj Close'] **-** 1 merged_portfolio_sp_latest_YTD_sp_closing_high
  • 首先,将adj_close数据帧与portfolio_df数据帧合并;这是你第三次利用这个adj_close数据框架来进行单独的分析,然后将它与整个“主”数据框架相结合。
  • 这种初始合并不是特别有用,因为你有日期和调整后的收盘价,这些日期和价格都在你收购每个头寸的日期之前;因此,我们将对收购日期后的数据进行子集化,然后找到从那时起的max收盘价。
  • 我再次使用del删除合并后的 dataframe 中不需要的列;这是我应该重构的代码,因为创建一个列表,例如cols_to_keep,然后用它过滤数据帧将是一个更好的方法——作为参考,多次运行del代码块将会抛出一个错误,您需要重新初始化您的数据帧,然后再次运行del代码块。
  • 在删除不必要的列之后,使用sort_values方法,按照'Ticker''Acquisition Date''Date'列对值进行排序(都是升序);您这样做是为了确保所有的股票行都排序在一起,我们按收购日期(以防我们不止一次购买同一只股票)和日期升序排序,以便过滤出您的头寸收购日期之前的日期。换句话说,你只关心收盘高点,因为你已经建仓了。
  • 为了过滤我们的数据框架,您创建了一个新列['Date Delta'],它是通过日期和采集日期列之间的差异计算的。
  • 然后将该列转换成数字列,并创建一个名为adj_close_acq_date_modified的新数据帧,其中['Date Delta']为> = 0。这确保了你只评估自你买入每个头寸之日起的收盘高点。
  • 现在您已经有了adj_close_acq_date_modified数据框架,我们将使用一个非常强大的名为pivot_table的 pandas 函数。如果您熟悉 Excel 中的数据透视表,该函数与此类似,您可以基于单个或多个索引透视数据,指定要计算的值和要透视的列,还可以使用agg functions(利用numpy)。
  • 使用pivot_table函数,我们以报价机和采集日期为中心,并指定我们希望找到每个位置的最大值(np.max)Adj Close;这允许您将每个头寸的最近调整收盘价与此最高调整收盘价进行比较。
  • 现在您有了一个adj_close_pivot数据帧,您重置了索引并在adj_close数据帧上再次连接它。这就创建了adj_close_pivot_merged数据框架,它告诉你何时买入了每个头寸,以及自买入以来触及收盘高点的日期。
  • 最后,我们将“主”数据帧与最后一个较小的数据帧adj_close_pivot_merged合并。
  • 这样做之后,您现在能够计算所需的最后一列['Pct off High']。你用['Ticker Adj Close']除以['Closing High Adj Close'],然后减去 1。请注意,该百分比将始终为负,除非该股票碰巧在最近评估的交易日有最高收盘价(在这种情况下为零)(如果是这样,这通常是一个非常好的迹象)。

这是一个非常重要的提升,现在是我们期待已久的可视化的时候了。如果你继续在你自己的笔记本上跟随,你现在有一个非常丰富的数据框架,有许多计算的投资组合指标,如下所示:

总回报和累计回报可视化

对于所有这些可视化,您将使用Plotly,它允许您完全不用代码就可以制作 D3 图表。虽然我也用MatplotlibSeaborn,但是我真的很看重Plotly的互动性;一旦你习惯了,语法变得相当简单,动态图表也很容易获得。

下面的第一个图表比较了每个头寸相对于标准普尔 500 的总回报(头寸和标准普尔 500 假设投资的持有期相同)。在下面,你会看到在他们不同的持有期,8 个位置中的 6 个跑赢了标准普尔。最后两个,Twitter(实际上有负回报)和沃尔玛跑输了同等时间的标准普尔 500 投资。

由于这些可视化相对相似,我将解释生成上述 Plotly 可视化所需的代码,对于其余的,我将只总结每个可视化的观察结果。

trace1 **=** go**.**Bar(
    x **=** merged_portfolio_sp_latest_YTD_sp_closing_high['Ticker'][0:10],
    y **=** merged_portfolio_sp_latest_YTD_sp_closing_high['ticker return'][0:10],
    name **=** 'Ticker Total Return')trace2 **=** go**.**Scatter(
    x **=** merged_portfolio_sp_latest_YTD_sp_closing_high['Ticker'][0:10],
    y **=** merged_portfolio_sp_latest_YTD_sp_closing_high['SP Return'][0:10],
    name **=** 'SP500 Total Return')

data **=** [trace1, trace2]layout **=** go**.**Layout(title **=** 'Total Return vs S&P 500'
    , barmode **=** 'group'
    , yaxis**=**dict(title**=**'Returns', tickformat**=**".2%")
    , xaxis**=**dict(title**=**'Ticker')
    , legend**=**dict(x**=.**8,y**=**1)
    )fig **=** go**.**Figure(data**=**data, layout**=**layout)
iplot(fig)
  • 当使用Plotly时,您创建traces,它将绘制您指定的 x 和 y 数据。在这里,您在 trace1 中指定要绘制一个条形图,每个报价器在 x 轴上,每个报价器的回报率在 y 轴上。
  • 在 trace2 中,为了稍微分解一下数据,我们将使用一个散点图,在 x 轴上显示股票,在 y 轴上显示 S&P 回报率。
  • 当棒线在线上时,单个股票(8 次中的 6 次)的表现超过了标准普尔 500。
  • 然后用这些跟踪创建一个数据对象,然后为图表提供一个布局;在这种情况下,您需要指定标题、barmode 和图例的位置。您还可以为 y 轴系列传入标题和刻度格式(小数点后两位的百分比格式)。
  • 然后您使用go.Figure创建一个图形对象,指定数据和布局对象,您之前将它们命名为datalayout

下面的图表显示了每个仓位相对于标准普尔 500 的盈利/(亏损)金额,以及股票总回报率%。虽然通常建议您为您的头寸分配相等的头寸规模(或可能根据隐含波动率确定头寸规模),但情况可能并非总是如此。对于波动性较小的投资,您可能会比风险较高的头寸投资更多(或者您可能有其他头寸规模调整规则)。有鉴于此,这种可视化显示了每个位置的回报和美元价值的贡献,你的整体投资组合的回报。

在这里,你可以看到,虽然你在脸书的投资比其他头寸略少,但这只股票在这个模拟投资组合中获得了约 2 万美元的回报,比同期同等标准普尔 500 投资的 4 倍回报率还要高。

下面的图表利用了您创建的累积列:'Cum Invst''Cum SP Returns''Cum Ticker Returns''Cum Ticker ROI Mult'

  • 在 x 轴上,你按字母顺序对投资组合进行了排序。每个头寸显示该头寸的初始投资和总价值(投资加上收益或减去损失),以及之前的头寸。
  • 为了进一步解释,根据在 AAPL 的约 8k 美元投资,这增长到约 22.5k 美元(收益为 14k 美元),而标准普尔的总价值为 15k 美元。这是对 AAPL 初始投资的 2.75 倍回报(8k 美元投资的 22.5k 价值是约 2.75 倍 ROI)。
  • 继续说 FB,你总共投资了约 1.6 万美元(两个头寸都是 8 万美元),现在已经超过 5 万美元,总回报超过 3 倍,这意味着 FB 扩大了你的整体投资组合投资回报率。
  • 沿着 x 轴往下,您会看到 TWTR 和 WMT 都降低了整体投资组合的投资回报率,这是显而易见的,因为两者的表现都不如 S&P,但我相信通过这种可视化,贡献的幅度会更明显。
  • 需要注意的是,考虑到不同的持有期,这种累积方法对于一些基于买入时间的头寸来说有点像苹果和橘子的组合。但是,您可以通过细分成更小的数据框架来隔离这种分析,并单独比较持有期更一致的头寸。例如,你可以分别比较你在 2H 2016 年和 1H 2017 年的购买情况。

高比较的调整收盘百分比

您的最终图表比较了每个头寸的最新收盘价与买入后调整后的收盘价的差距。这通常是要考虑的一个重要的可视化:

  • 当一只股票以更高的价格收盘时,通常建议你也调整跟踪止损。举例来说,这里有一个例子:
  • 一个头寸以 10 美元买入,翻倍至 20 美元——使用 25%的跟踪止损,如果第二天该头寸收于 15 美元(15/ 15/ 20–1 =(25%)),你会想考虑卖出该头寸。
  • 如果仓位增加到 25 美元,你可以考虑将你的跟踪止损移动到 18.75 美元(18.75/ 18.75/ 25–1 =(25%))。
  • 如前所述,本文无意成为财务建议;不同的交易系统有不同的跟踪止损规则,这是一个说明性的例子。
  • 跟踪止损意在帮助保持收益,通常对减轻投资情绪很重要;虽然很容易看到你的头寸的当前回报,但往往需要手动(或者如果你使用跟踪止损服务,有点昂贵)计算你的头寸离跟踪止损有多近。
  • 这种最终的可视化使您可以很容易地评估您正在查看的任何日期;在图表中,我们看到 AAPL、MTCH 和 NFLX 都在 2018 年 3 月 9 日收盘于收盘高点(通常是一个非常好的迹象)。
  • 然而,TWTR 比最高收盘价低 25%以上(截至 2018 年 3 月 9 日,比最高收盘价低 33%),WMT 比最高收盘价低约 20%。
  • 在这种情况下,你可能想卖掉 TWTR,继续密切关注 WMT 的表现。

方法的限制和总结

现在,您有了一个相对可扩展的 Jupyter 笔记本和投资组合数据集,您可以使用它来评估您的股票投资组合,并在您认为合适的时候添加新的指标和可视化。

请注意,虽然本笔记本对投资组合进行了相当全面的审查,但以下内容尚未纳入考虑范围,会对整体比较产生影响,并可能为未来发展提供很大的空间:

  • 如前所述,本笔记本侧重于积极持仓——理想情况下,我们将评估所有头寸,包括已平仓和积极持仓,以便对个人相对于替代方案的投资策略有一个真正全面的了解,如指数比较。
  • 这里的方法不考虑分红。当我们评估调整后的收盘价(反映股息)时,总股东回报结合股价升值和股息来显示股票的总回报;虽然这更难做到,但我正在评估将来是否会包括这一点。
  • 与此相关的是,投资者也可以将股息再投资于某个头寸,而不是进行现金分配;可以说,这甚至比股息会计更复杂,因为收购成本低且分散,在持有一个头寸的几年时间里,你可能每年有四个(或更多)收购日期用于股息再投资股票。

考虑到这些未来的领域,我们在这里取得了很多成就;这包括使用雅虎导入标准普尔 500 和股票数据。金融的 API,并创建一个主数据框架,将您的投资组合与历史股票和比较标准普尔 500 价格相结合。这样,你就可以计算每个头寸的绝对百分比和美元价值回报(并与同期标准普尔 500 投资进行比较),以及每个头寸对你的整体投资组合表现的累积影响。你也可以根据自己的交易规则动态监控你的跟踪止损。你还创造了可视化效果,让你更好地洞察你的主数据框架,关注不同的指标和每个位置对每个指标的贡献。

我希望你觉得这个教程有用,我欢迎评论中的任何反馈。你也可以在推特上联系我, @kevinboller ,我的个人博客可以在这里找到。

面向 Matlab 用户的 Python

原文:towardsdatascience.com/python-for-…

我注意到人们面临的一个普遍问题(尤其是在工程界)是从学术界到工业界的过渡。大多数学校更喜欢让我们使用 Matlab。无论你是电子工程师、化学工程师还是纳米工程师,你很可能在整个大学生涯中都不得不使用 Matlab(除了一点点 C/C++)。业界最近的一个趋势是从 Matlab 过渡到 Python。这可能是由于 1000 多美元的许可费,内存分配的低效率,缺乏开源库,甚至是大多数软件开发人员讨厌 Matlab 语法的事实。幸运的是,Matlab 和 Python 中的语法非常相似(如果你忽略 Matlab 索引从 1 开始而不是从 0 开始的事实)。在本教程中,我为 Matlab 用户介绍了数据分析和可视化领域的 Python 基础知识。

虽然代码可以在这个博客上找到,但我也在 youtube 上发布了相同的材料:

矩阵操作

Matlab 用户首先感兴趣的事情之一是线性代数和矩阵操作。Python 的数学库 numpy 附带了各种工具来执行简单的数学运算。

import numpy as np

让我们假设我们希望首先导出下面的矩阵, A :

对于那些习惯于简单 matlab 语法的人,可以使用以下内容:

A = np.matrix('1,1,1 ; 2,4,5 ; 5,7,6')

然而,Python 逻辑是以向量的形式工作的。因此,最终习惯以下语法很重要:

A = np.matrix([[1,1,1],[2,4,6],[5,7,6]])

现在我们已经定义了我们的矩阵,我们可以首先得到(0,0)值:

A[0,0]

输出: T3 1

接下来,我们只能得到第一列:

A[:,0]

输出: [[1] 【2】 【5】]

最后,就第一行:

A[0,:]

输出: [[1 1 1]]

数学运算

既然我们已经成功地复制了矩阵操作,让我们尝试执行一些基本的数学运算。我们可以使用相同的 Numpy 库和上一节的矩阵 A

添加第一行的值:

np.sum(A[0,:])

输出: 3

A 与其自身的点积:

np.dot(A,A)

输出: [【8,12,13】, 【40,60,62】, 【49,75,83】]

A 与其自身的叉积:

np.cross(A,A)

输出: [[0,0,0], 【0,0,0】, 【0,0,0】]

数据绘图

最后,在可视化数据时,绘图非常重要。Python 的 Matplotlib 函数提供了一组广泛的函数来执行绘图操作。

import matplotlib.pyplot as pltplt.figure()
plt.plot(A[:,0])
plt.plot(A[:,1])
plt.title('Sample Matlab type Plot')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.show()

输出:

面向运动科学家的 Python:描述性统计

原文:towardsdatascience.com/python-for-…

了解如何使用易于理解的 Python 代码开始分析运动员相关数据集

Python 在过去的几年里越来越受欢迎,是世界上许多数据科学家的首选语言。它也越来越受体育科学家的欢迎,这并非偶然,因为他们每天都要处理大量的数据。

虽然这篇文章可能对初学 Python 的体育科学家有所帮助,但它并不是对这种语言本身的介绍。更确切地说,它是对如何以一种更实用的方式解决问题和分析数据进行推理的介绍。

此外,本文将使用基本的描述性统计来说明如何构建可组合的函数式 Python 代码来解决问题。

在第一部分,我将介绍集中趋势的两种基本计算方法:平均值和中值。第二部分应用同样的原理计算标准差和方差。最后一部分通过计算两个变量之间的关系来介绍双变量分析。

第 1 部分:平均值和中位数

体育科学家一直在研究关于运动员的数据集,能够调用数据点列表上的mean来获得对它的总体了解是很有用的。在有异常值的数据集的情况下(我们毕竟是在和运动员一起工作),我们可能需要使用median来找出第 50 百分位。

定义平均值

虽然 Python 有统计库可以导入这些函数,但我相信,研究这些统计库对于为以后解决更复杂的问题打下基础非常有帮助。当我们使用平方和或均方误差等可组合函数时,这将更有意义。

让我们首先创建一个.py文件并定义函数mean。下面是一个返回平均值的纯函数:

*# Python 3*
def mean (x):
  return sum(x) / len(x)

注意,sum()len()是 python 自带的函数,它们返回 Python 数据结构的总和长度。这里的mean函数是一个简单的函数,这意味着它没有副作用(给定相同的输入,它总是返回相同的结果。)

定义中位数

计算中值比平均值稍微复杂一些,但是足够简单。寻找数字列表的中值取决于找到排序列表的一半长度:half = lambda arr: len(arr) / 2。然而,这个函数有两个问题,假设我们要用它来查找索引(从 0 开始。)第一个问题是,它返回一个 float,我们需要一个整数来寻找索引处的值。第二个问题是,如果数字的长度是偶数,我们希望它返回中间两个索引中的第一个。我们可以使用int()函数来解决这个问题。让我们将它添加到我们的文件中:

half()函数现在返回中间的索引(或者在偶数列表的情况下,返回两个中间索引中的第一个):

evenList = [11, 12, 13, 14]
oddList = [21, 22, 23]half(evenList)
# 1half(oddList)
# 1

定义median的下一步是返回该索引处的值。如果长度是偶数,我们需要返回arr[half(arr)]arr[half(arr) + 1]值的平均值来得到中值。因此,让我们最后编写中值函数,并将其添加到我们的文件中:

def median (arr):
    sortedList = sorted(arr)
    index = half(sortedList)
    if isEven(len(sortedList)):
        return mean([ sortedList[index], sortedList[index + 1] ])
    else:
        return sortedList[index]

瞧啊。从上面调用median(evenList)会返回12.5,调用median(oddList)会返回22

这很酷,因为我们使用了刚刚定义的mean()函数!这是用函数编程最有趣的部分——它们作为简单的构件,可以用来解决任何问题。此外,请注意,我们必须在对数据集进行操作之前使用本机sorted()函数返回数据集的排序副本,这对于获得正确的中值至关重要。

把它放在一起

让我们在一个有点实际的例子中使用这两个函数。我将使用一个基本数据集,其中包含一些来自培训课程的 GPS 数据:

data = [
  {"name": "John",  "distance": 5602,  "high-speed-running": 504},
  {"name": "Mike",  "distance": 5242,  "high-speed-running": 622},
  {"name": "Chad",  "distance": 4825,  "high-speed-running": 453},
  {"name": "Phil",  "distance": 611,   "high-speed-running": 500},
  {"name": "Tyler", "distance": 5436,  "high-speed-running": 409}
]

这是一个字典列表,所以我们不能就这样叫mean(data[“distance”])。让我们在文件顶部导入方便的pandas库,将数据集转换成 Pandas 数据帧,这样我们就可以简单地对数据集的元素调用mean:

现在我们可以调用mean(df['distance'])返回4343.2。调用median(df[‘distance’])返回5242

要考虑的事情: 在这个特定的数据集中,为什么我们可能要在分析中使用*median*函数而不是*mean*?或者反之亦然。

第 2 部分:标准差和方差

标准差和方差密切相关。例如,方差被定义为标准偏差的平方(或者标准偏差是方差的平方根)。对于可组合的函数,这几乎太容易了!

差异

我们可以从方差开始,因为我们要做的就是对它求平方来得到标准差。我们在第 1 部分中定义的mean函数也将派上用场,还有 Python 的原生len函数。

查看样本方差的等式,并考虑到我们将对其求平方以获得标准差,继续定义一个值的平方函数似乎是一个好主意:

def square(x):
    return x * x

下一位有点复杂,但是我们可以用一个叫做sumOfSquaredDifferences的函数来计算分子:

def sumOfSquaredDifferences (arr):
    xBar = mean(arr)
    differences = map(lambda x: x - xBar, arr)
    squaredDifferences = map(square, differences)
    return sum(squaredDifferences)sprintEfforts = [88, 56, 51, 34, 50, 22, 61, 79, 90, 49]sumOfSquaredDifferences(sprintEfforts)
*# 4444*

这个函数本质上是计算每个值和平均值的差(使用高阶map函数),然后求差的平方,并求出平方差的和。够简单!

现在找到样本方差很容易:

def variance (arr):
    n = len(arr)
    return sumOfSquaredDifferences(arr) / (n-1)variance(sprintEfforts)
*# 493.7*

标准偏差

总的来说,差异很大,但我们希望有一个我们更熟悉的衡量标准。幸运的是,计算方差的标准差轻而易举,因为它就是方差的平方根:

def sqrt (x):
    return x**(1/2)def stDev (arr):
    return sqrt(variance(arr))stDev(sprintEfforts)
*# 22.2*

除了 Python 对幂操作符(**)的古怪语法,这非常简单。让我们将它应用于第 1 部分中的 GPS 分数数据集:

stDev(df['high-speed-running'])
*# 79.62*

第 1 部分中更新后的文件应该是这样的:

关于构成函数的思考

事实证明,将具有单一目的的小而纯的函数组合在一起,有助于将基本的统计概念融入生活。这些统计计算对于实践良好的编程原则来说是完美的。

我们已经用了很多maplambda函数。这些是处理数据列表的基础。为了最有效地构建可组合的功能性代码,尝试掌握并理解如何在任何语言中使用像mapfilterreduce这样的高阶函数是一个好主意。

第 3 部分:相关性

到目前为止,我们已经定义了单变量分析的函数,这些函数对于演示使用单个数据数组非常有用。

现在我们可以应用同样的逻辑,通过探索相关性来进行双变量分析。

绘制数据

使用数据集的首要规则是绘制数据以了解我们在处理什么。为了简单起见,让我们使用import seaborn as sns来创建情节:

该数据集基于第 1 部分和第 2 部分中使用的虚构数据集。但是,如果这些数据代表一个培训课程,则该数据集可以是相同指标的每周总计。这段代码将产生以下情节:

酷!我们马上就能看出“距离”和“高速奔跑”之间有着很强的正线性关系。

皮尔逊氏 r

下一步是通过找出皮尔逊相关系数来对其进行量化,皮尔逊相关系数可以用以下公式表示:

让我们把它分成几部分。我们将需要count代表 nsum代表σ,sqrt,以及square。此外,我们将需要map遍历每个 x 和 y 索引,并将它们相乘,以及对它们求平方。让我们从使用count将 n 添加到我们的文件开始:

# Python3
def n (arr):
  return arr.count()

下一步是映射每个“x”和“y”对,并返回它们乘积的总和:

def product (x, y):
  return x * ydef sumXTimesY (x, y):
  return sum(map(product, x, y))

现在我们可以很容易地定义分子:

def numerator (x, y):
  return n(x) * sumXTimesY(x, y) - sum(x) * sum(y)

分母看起来有点复杂,需要分解成最小的部分。我们来定义一下sumOfSquares:

def sumOfSquares (val):
  return sum(map(square, val))

现在,在第 2 部分的sqrt函数的帮助下,我们有了定义分母的所有工具:

def denominator (x, y):
  return sqrt((n(x) * sumOfSquares(x) - square(sum(x))) * (n(y) * sumOfSquares(y) - square(sum(y))))

现在,我们可以将它们放在文件的最终版本中:

不算太寒酸!我们不仅在**0.88**的 r 处看到了“距离”和“高速奔跑”之间非常强的关系,而且我们已经使用易于推理的功能性和可组合代码将它们放在一起。此外,以这种方式分解皮尔逊 r 公式,可以更深入地理解两个变量之间的关系到底是什么样子。

总结想法

值得重申的是,使用执行统计繁重任务的库是正确的方法,但是本文的重点是使用简单的函数概念来解决复杂的问题。

本文介绍了两个非常强大的数据可视化和分析库:Seaborn 和 Pandas。Seaborn 是一个基于 Matplotlib 的统计可视化库。由于它的简单性和灵活性,它是我进行高级统计绘图的首选库。Pandas 是一个非常棒的数据分析工具包,对于有电子表格工作背景的体育科学家来说非常有吸引力。

我写这篇文章的目的是为体育科学家提供构建功能代码库的工具,并理解如何以模块化和功能化的方式分析数据集。

Python 有一个内置的 Logo Turtle,非常适合强化学习

原文:towardsdatascience.com/python-has-…

不久前,我在伯克利教授一门关于数据分析的课程,其中一个练习让学生通过 Python stdlib 来寻找感兴趣的模块。我也浏览了文档,很高兴地发现 Python 有一只乌龟!你还记得吗?

FORWARD 10
LEFT 90

我在 90 年代上的高中还不够富裕,无法拥有一只内置钢笔的机器乌龟(小小提琴开始演奏),但我记得我被这个神奇生物在屏幕上的动作迷住了,我想当时它正在一个橡子阿基米德上运行,这是今天芯片巨头 ARM 的早期产品。我从来不需要一个肺活量描记器,因为海龟在数学曼荼罗的生产中充分地占据了它的位置。

Thanks SchoolCoders (www.flickr.com/photos/scho…)

我在这里这里之前写过关于强化学习的文章:这是一个我特别感兴趣的话题,因为它提供了一条通往 AGI(奇点)的道路,同时真正暴露了今天深度学习和人工智能的局限性。

框架问题和 Python 的海龟

我想创造一个代理,它能教会自己尽可能长时间地在屏幕上移动:避开屏幕的边缘,也避免撞到自己(像旧的贪吃蛇游戏那样)。

The turtle agent taking some mostly random actions early in training

直觉上,这应该会导致海龟盘绕在自己身上。

我很快发现了 Python 的内置 turtle 的一个可悲的问题:它绘制到一个 Tkinter 画布(如果你以前没有用 Python 做过 GUI 开发,就把它想象成‘某个对象’——像我一样!)而且没有办法从那个画布上读回像素。

所以,我实现了自己的 turtle 库,它包装了内置的(仍然使用它来绘制到屏幕),但也保持画布的 NumPy 数组可用(以及指定数量的先前帧,这对 RL 很有用)。它为 RL 提供了其他一些方便的功能,你可以在我的 Github 这里抓取这个库。我用来做这个项目的最终代码在那个 repo 的examples 文件夹里。

下面是我构建的env.step()函数。你可以看到有 3 种可能的动作,两种结束游戏的情况(海龟离开屏幕或回到它的尾巴),在一集结束时给出的累积奖励(向前移动会产生更高的奖励),以及该动作的即时奖励(每个动作获得 1 个奖励)。

My ‘env.step’ function follows OpenAI’s (state, reward, done, msg) model. Going forward yields a higher reward than spinning around in place. ‘UserConditionException’ is when the turtle attempts to go back over its trail — it dies.

强化学习原则

早期的文章提供了更多的背景知识,但是原理非常简单:

  • 一个代理在一个环境中做出一个动作,并获得一个奖励。
  • 奖励由两部分组成:即时奖励(即密集奖励)(代理人吃了一个苹果),以及延期奖励(即稀疏奖励)(代理人吃了 10 个苹果,赢得了游戏)。
  • 代理人的批评部分比较它对奖励的期望(给定环境的状态和它采取的行动;那些期望开始是随机的)与它收到的实际回报。它们排列得越紧密越好:这意味着它可以用作亏损信号。
  • 延期奖励(从现在到游戏结束的每一步乘以一些折扣因子)被添加到早期奖励中,这样代理人在每一时间步都知道自己在该时间步的行为最终是否带来了好的奖励。

这是演员兼评论家 RL,因为本质上有两个代理人:一个演员,和一个评论家。我们用一个有两个头的神经网络来实现它们。

行动者网络具有对应于可能动作数量的多个输出;选择的动作是其中的软最大值。(输出层的每个神经元的激活或值被解释为一种概率,softmax 确保在 3 种可能的操作下,每个神经元的最大激活为 0.33,因此很容易选择具有最高值的一个)。

不仅仅是批评者在学习如何更好地估计回报,行动者也在学习如何更好地行动:

  • 当不可能的行动产生高回报时,损失信号增加,当行动确定性增加时,损失信号减少。一般来说,随着时间的推移,产生回报的行为应该变得更加确定。

因为行动损失和价值损失都被归为‘损失’(谁能说它们的走向是否一致?),而且因为演员和评论家的网络没有太大的差异——显然需要大量的数据(迭代、时代、剧集、播放次数)才能实现融合。

最后一个重要因素是鼓励探索而不是开发,也就是说,避免局部最小值。有几种方法可以做到这一点,在我制作的代理中结合了这些方法:

  • Epsilon greedy(选择一个随机行动,有时随着时间的推移,概率会下降epsilon——当概率呈指数下降时,我们说‘退火’而不是下降,以防你想知道)
  • 随机地干扰来自环境的奖励信号
  • 任何神经网络的输出都不太可能达到 1.0 的概率。不要每次只选择与最大输出相对应的动作,而是从它的概率分布中取样。
  • 神经网络中的丢失增加了固有的随机性。

这些方法中的每一种都需要更多的训练周期,但它们确实会产生更聪明的代理。幸运的是,在这种玩游戏的 RL 中不缺少数据;只要我们允许,代理可以玩。

代理及其结果

我制作的代理最终非常简单:两个卷积层,两个具有不同非线性的完全连接层,以及前面提到的由线性层组成的两个头。

It learns to avoid the edges of the canvas and avoid itself by going in a spiral

作为网络的输入,我制作了一个当前帧/画布的堆栈,加上前两个帧。(每一帧只有一个像素和/或海龟的方向不同)。

An unremarkable actor-critic network with epsilon-greedy learning built in.

我做这个学到的东西

如果你以前读过我的文章,你可能知道,我不会说制作这只 RL 海龟很容易。我学到的一些东西:

  • 一如既往,奖励设计(即时和游戏结束时)是困难的,挑剔的,不完全直观的。
  • 更多的噪音和熵源确实有助于探索阶段。不要以为一个就够了。
  • 动作头和值头仅仅包含一个线性层是不够的。每个磁头有两层,中间有非线性,当固定在网络的主要“主体”上时,工作得更好。
  • RL 很容易达到稳定状态。通常五分钟训练和五小时训练后的损失没有太大区别。
  • 将类似“last_action”的信号注入网络的后续层(绕过卷积层,并试图为网络提供一些有用的时间相关上下文)不一定有帮助。
  • 随机选择海龟的起始位置和角度使得问题变得更加复杂。我认为这将有助于代理学习泛化,但至少在我给它的训练时间里,它大大降低了收敛速度。
  • 一个 200x200 的网格,其中大部分是稀疏的(没有太多进展),只有一个单一的像素线厚度,并且在我提供给网络的 3 个时间序列帧之间没有太大的差异,导致学习相当缓慢。

The training loop — where the ‘magic’ happens.

愚蠢的特工问题,未来的工作

随着时间的推移,随着它在边缘附近左转或右转的概率变得更高,我制作的代理在避免它方面变得更好,而不是学习永不超出屏幕边界的硬性规则。它没有常识!很难说代理人学到了什么。

那么,你如何将习得的或部分习得的概率分布具体化为实际的规则呢?这可以给一个更有效的代理,也可以学习得更快。有时可以打破的规则,或者当一些规则不再有用时,彻底忘记它们,又如何呢?

当然,还有一个经典的 RL 问题,代理在这里学到的东西在例如太空入侵者的游戏中是没有用的。代理没有海龟和它的踪迹以及屏幕边缘的概念,只有一串张量,它不知疲倦地一遍又一遍地相乘,并根据一些导数进行调整。奖励信号是手工编码的,当然,尽可能长时间的演奏本身就是一种不错的奖励。为什么还没有人找到内在激励人工智能的方法?

AGI 就要来了,但我们仍然需要解决巨大的工程和哲学挑战。谦逊的 Python 海龟继续为我提供了一个有趣的测试平台。

感谢您的阅读!我喜欢和人们谈论 AGI,特别是我们如何从现在的位置开始建设,所以如果你愿意,请联系我们。接下来还有更多:)

Python 是解决任何问题的完美工具

原文:towardsdatascience.com/python-is-t…

反思我的第一个 Python 程序

反思总是一种有益的(有时是有趣的)练习。出于怀旧的原因——如果一个人可以怀旧两年前的东西——我想分享我的第一个 Python 程序。当我还是一名航空航天工程专业的学生时,我最初选择 Python 是为了避免使用电子表格,当时我并不知道这将是一个多么好的决定。

我的 Python 教育始于 Al Sweigart 的书 用 Python 自动化枯燥的东西 ,这是一本优秀的基于应用程序的书,用简单的程序完成有用的任务。当我学习一个新的主题时,我会寻找任何使用它的机会,我需要用 Python 解决一个问题。幸运的是,我找到了一个课堂所需的 200 美元的教科书。我个人对教科书的限制是大约 20 美元(自动化枯燥的东西在网上是免费的),我甚至拒绝租借这本书。我急切地想在第一次作业前拿到这本书,于是我看到这本书可以通过亚马逊的新账户免费试用一周。我拿到这本书一个星期,就可以做第一个作业了。虽然我可以一周一次地创建新账户,但我需要一个更好的解决方案。进入 Python 和我的第一个编程应用。

中许多有用的库之一是 pyautogui ,它允许你通过 Python 控制键盘和鼠标。他们说,当你有一把锤子时,每个问题看起来都像钉子,这里的情况就是如此。Python 和 pyautogui 允许我按箭头键并截屏,我将这两者结合起来,提出了一个解决图书问题的方案。我写了我的第一个程序来自动翻阅书中的每一页并截图。结束程序只有 10 行长,但我为它感到自豪,就像我在航空航天工程中做的任何事情一样!以下是整个计划:

import pyautogui
import time# Sleep for 5 seconds to allow me to open book
time.sleep(5)# Range can be changed depending on the number of pages
for i in range(1000): # Turn page
 pyautogui.keyDown('right')
 pyautogui.keyUp('right') # Take and save a screenshot
 pyautogui.screenshot('images/page_%d.pdf' % i)
 time.sleep(0.05)

运行这个程序非常简单(我鼓励任何人去尝试)。我将脚本保存为 book_screenshot.py,然后在同一个文件夹中弹出一个命令提示符并键入:

python book_screenshot.py

然后我会有 5 秒钟的时间翻到这本书,并把它全屏显示。该程序将完成剩下的工作,翻阅每一页,并截图保存为 pdf 格式。然后,我可以将所有的 pdf 文件合并成一个文件,并拥有这本书的副本(法律问题)!诚然,这是一个相当可怕的副本,因为它无法被搜索,但我尽可能使用我的“书”的任何借口。

I could watch this for hours

这个例子展示了我在继续接受数据科学教育的过程中一直铭记的两个要点:

  1. 学习新技能的最好方法是找到你需要解决的问题。
  2. 你不需要完全掌握一项技能才有用。

仅用几行代码和一本免费的在线书籍,我就编写了一个实际上已经投入使用的程序。学习基础知识可能很乏味,我第一次学习 Python 的尝试在几个小时内就失败了,因为我陷入了数据结构和循环之类的想法。改变策略,我开始开发解决实际问题的方法,并最终学到了基本原理。编程和数据科学需要掌握的东西太多了,但你不需要一下子学会所有的东西。挑一个你需要解决的问题,开始行动吧!

从那以后,我制作了几个更复杂的节目,但我仍然津津有味地记得这第一个剧本!

分享你的第一个节目!我欢迎讨论、反馈和建设性的批评。可以通过 Twitter @koehrsen_will 联系到我。

用 Python 绘制马科维茨有效边界

原文:towardsdatascience.com/python-mark…

这篇文章是关于计算夏普比率的文章的后续。在知道如何获得夏普比率后,我们将模拟几千种可能的投资组合配置,并将结果绘制成图表。有了这个,我们可以很容易地找到我们愿意承担的任何给定风险水平的股票的最佳配置。

与上一篇文章一样,我们需要加载数据。我将使用四个简单的文件,有两列——日期和收盘价。你可以用自己的数据,或者在 Quandl 里找点东西,这个用途很好。我们有 4 家公司——亚马逊、IBM、思科和苹果。每个文件分别加载为 amznibm思科aapl 。下面印的是 aapl 的头像。

我们希望将所有价格合并到一个名为股票的数据框架中,这里有一种方法。

我们需要对这个数据框架做的一件事是标准化数据。我将使用对数回报,因为它更方便,而且它负责项目其余部分的标准化。将一切转换成对数回报很简单。可以把它想象成一个算术日收益率的对数(它是通过把第 n 天的价格除以第 n-1 天的价格得到的)。

围绕这一点,事情开始变得有趣起来!我们需要为循环准备一个*,它将模拟四只股票的几种不同组合,并保存它们的夏普比率。我要用 6000 个作品集,但是如果你的电脑太慢的话可以少用一点。代码顶部的随机种子确保我每次都得到相同的随机数,以保证可重复性。*

从这里,我们可以获得模拟中出现的最大夏普比率以及它出现的行,因此我们可以获得其中的权重。

所以最佳投资组合在指数 5451 上。让我们检查该指数中的分配权重,并保存回报率和波动性数据,以便稍后在图表中使用。

我们有了绘制图表所需的一切,可以根据波动率(或风险)和回报率来比较所有组合,并用夏普比率来着色。红点是从上面的计算中获得的,它代表具有最大夏普比率的模拟的回报和波动性。

我们已经可以在图表中看到子弹形状,这种形状勾勒出了我们稍后将绘制的有效边界。为此,我们需要定义更多的函数。第一个函数 get_ret_vol_sr 将返回一个数组,其中包含任意给定权重集的 return波动率夏普比率

第二个函数 neg_sharpe 将从一些权重中返回负的 sharpe 比率(稍后我们将使用它来最小化)。

第三个函数 check_sum 将检查权重的总和,其必须为 1。如果总和为 1,它将返回 0(零)。

接下来,我们需要创建一个变量来包含我们的约束,比如 check_sum 。我们还将定义一个初始猜测和具体的界限,以帮助最小化更快更有效。我们最初的猜测将是每只股票 25%(或 0.25),每只股票的界限将是一个元组(0,1),因为权重的范围可以从 0 到 1。

进入最小化功能。我选择了“SLSQP”方法,因为这是大多数一般最小化问题使用的方法。如果你想知道,它代表序列最小二乘规划。确保用上面定义的变量传递初始方法、边界和约束。如果我们打印变量,它看起来会像这样:

我们需要字典中的键 x ,它是一个数组,包含具有最大夏普比率的投资组合的权重。如果我们使用我们的函数 get_ret_vol_sr ,我们得到回报、波动率和夏普比率:

因此,我们获得了比之前模拟更好的夏普比率(1.0307,而不是之前的 1.0287)。

我们现在准备检查所有的最优投资组合,这基本上是我们的有效边界。有效边界是在任何给定的风险水平下,使我们获得最高预期回报的投资组合集合。或者从另一个角度来看,期望回报的最小风险。为了追踪这条线,我们可以定义一个变量 frontier_y 。回到上面的图表,我们可以看到最大回报不会比 0.3 高太多,所以 frontier_y 将被定义为从 0 到 0.3。

为了完成边界的绘制,我们定义了最后一个函数来帮助我们最小化波动性。它将返回给定权重的波动率(指数 1)。

现在,帮助我们得到有效边界的 x 值的最后一点代码。我们使用与上面相同的代码,只是对约束做了一些修改。循环的基本上是遍历我们之前定义的 frontier_y 中的每一个可能值,并获得波动率(图表中我们的 x 轴)的最小结果(这是关键的【乐趣】)。

最后,我们可以通过传递变量 frontier_xfrontier_y 来绘制实际的有效边界。

Markowitz Efficient Frontier mapped in red

这些是使用 Python 进行 Markowitz 投资组合优化的步骤。当你投入更多的股票,对不同的风险策略进行结果测试时,事情就变得更有趣了。当然,这种类型的分析总是基于过去,因此它不能保证未来的结果。尽管如此,它可以给你一个特定策略的预期输出的好主意。

欢迎提问或在下方留言!编码快乐!

如果你对 Python 的金融分析感兴趣,有两本很棒的书,几乎涵盖了你需要的所有内容:

声明:本文中的一些链接是附属链接。这意味着,对你来说零成本,如果你通过链接完成购买,我将赚取代销商佣金!

熊猫 vs. Spark:如何处理数据帧(下)

原文:towardsdatascience.com/python-pand…

“Panda statues on gray concrete stairs during daytime” by chuttersnap on Unsplash. “Scala” means “stairway” in Italian, my native language: hence the choice of the picture. It just seemed appropriate.

前几天我发表了一篇帖子比较 Python 和 Scala 的基本命令:如何处理列表和数组、函数、循环、字典等等。随着我继续练习 Scala,似乎应该继续第二部分,比较如何在两种编程语言中处理数据帧,以便在建模过程之前准备好数据。在 Python 中,我们将通过使用 Pandas 库来完成所有这些,而在 Scala 中,我们将使用 Spark。

在这个练习中,我将使用 Titanic train 数据集,该数据集可以通过链接轻松下载。此外,我在 Databricks 中进行了 Scala 实践:如果你也这样做,记得首先通过点击 Data 导入数据集,然后添加数据。

1.读取数据帧

我将导入并命名我的数据帧 df ,在 Python 中这将只有两行代码。如果您将 train.csv 保存在笔记本所在的同一个文件夹中,这将有效。

import pandas as pd
df = pd.read_csv('train.csv')

Scala 需要更多的输入。

var df = sqlContext
    .read
    .format("csv")
    .option("header", "true")
    .option("inferSchema", "true")
    .load("Filestore/tables/train.csv")

让我们看看这里发生了什么。Scala 不假设你的数据集有一个头,所以我们需要指定它。另外,Python 会自动为 dataframe 列分配一个 dtype,而 Scala 不会这样做,除非我们指定.option("inferSchema", "true")。还要注意,我没有导入 Spark Dataframe,因为我在 Databricks 中练习 Scala,它是预加载的。否则我们将需要这样做。

注意:在 Python 中布尔值是大写的,而在 Scala 中是小写的!

2.显示数据帧的前几行

Python 中,df.head()将默认显示前五行:输出如下。

df.head() output in Python.

如果您希望看到的行数不是 5,您可以在括号中传递一个不同的数字。 Scala 及其df.show(),将默认显示前 20 行。

df.show() in Scala.

如果我们想让它更短,并且去掉省略号,以便阅读列的全部内容,我们可以运行df.show(5, false)

3.数据帧列和数据类型

要检索列名,在这两种情况下我们只需键入df.columns : ScalaPandas 将分别返回一个数组和一个字符串索引。

如果我们想要检查 dtypes,那么对于两种语言来说,命令还是一样的:df.dtypes。Pandas 将返回一个 Series 对象,而 Scala 将返回一个元组数组,每个元组分别包含

df.dtypes in Python

列和数据类型。因此,如果我们在 Python 中想要检查年龄列是什么类型,我们运行df.dtypes['Age'],而在 Scala 中我们需要过滤并使用元组索引:df.dtypes.filter(colTup => colTup._1 == "Age")

4.汇总统计数据

这是每个数据科学家在探索他/她的数据时做的另一件事:汇总统计。对于每一个数字列,我们可以看到诸如计数、均值、中值、偏差等信息,以便立即看到是否有什么地方看起来不对劲。在这两种情况下,这将返回一个数据帧,其中列是原始数据帧的数字列,行是统计值。

Python 中,我们键入df.describe(),而在ScalaT4【中。我们必须在后一种情况下添加.show()的原因是因为 Scala 不会自动输出结果数据帧,而 Python 会自动输出(只要我们不把它赋给新变量)。

5.选择列

假设我们希望看到列的子集,例如名称为和的列保留了下来。

Python 中,我们可以不加区分地使用df[['Name','Survived]]df.loc[:,['Name','Survived]。请记住,这里的:表示“所有行”。

Scala 中,我们会键入df.select("Name","Survived").show()。如果你想把子集赋给一个新变量,记得省略.show()

6.过滤

假设我们想看看幸存乘客的姓名和职业。我们需要在幸存列中过滤一个条件,然后选择其他条件。

Python 中,我们将再次使用.loc,通过在行的位置传递过滤器,然后用列表选择列。基本上和上面的例子一样,但是用一个过滤器代替了:,这意味着df.loc[df['Survived'] == 1, ['Name','Pclass']]

Scala 中我们将使用.filter后跟.select,也就是df.filter("Survived = 1").select("Name","Pclass").show()

6.1.过滤空值

如果我们想要检查空值,例如在开始的列中,它将像普通过滤器一样工作,只是条件不同。

Python 中,我们在传递条件时应用.isnull(),在本例中是df[df['Embarked'].isnull()]。由于我们没有指定任何列,这将返回一个 dataframe,它将包含所有原始列,但只有包含值的行是空的。

Scala 中,我们将再次使用.filter:df.filter("Embarked IS NULL").show()。注意,我们在 Scala 中传递的布尔过滤器有点像 SQL 查询。

7.输入空值

在数据集中输入空值之前,我们应该始终进行一些思考,因为它会影响我们的最终模型,我们希望对此保持谨慎。然而,仅仅出于演示的目的,假设我们想将字符串“N/A”归入数据帧中的空值。

我们可以用df = df.fillna('N/A')df.fillna('N/A', inplace = True)Python 中这样做。

Scala 中,非常类似地,这将通过df = df.na.fill("N/A")来实现。记住在这种情况下不要使用.show(),因为我们正在将修改后的数据帧赋给一个变量。

8.重命名列

这是你在 Scala 中需要确定的事情,因为机器学习模型需要两个名为特征标签的列来训练。然而,举例来说,如果您不喜欢某个列的命名方式,您可能也想在 Pandas 中这样做。为此,我们想将幸存的列改为标签*。*

Python 中,我们将传递一个字典,其中的键和值分别是列的旧名称和新名称。这种情况下会是df.rename(columns = {"Survived": "label"}, inplace = True)

Scala 中,这等于df = df.withColumnRenamed("Survived", "label")

9.分组依据和聚合

假设我们想要分别计算男性和女性的最大年龄,在这种情况下.groubpby会派上用场。不仅检索最大值;在.groupby之后,我们可以使用各种聚合函数:均值、计数、中位数等等。对于这个例子,我们坚持使用.max()

Python 中,这将是df.groupby('Sex').mean()['Age']。如果我们不在.mean()后指定['Age'],这将返回一个 dataframe,其中包含所有数字列的最大值,并按性别分组。

Scala 中,我们首先需要导入我们想要使用的聚合函数。

import org.apache.spark.sql.functions.max
df.groupBy("Sex").agg(max("Age")).show()

10.创建新列

这对于特征工程来说非常有用,我们可能想要结合两个变量来看它们的交互是如何与目标相关的。出于纯粹的演示目的,让我们看看如何创建一个包含在年龄费用之间的产品的列。

在 Python 中,这非常简单。

df['Age_times_Fare'] = df['Age'] * df['Fare']

Scala 中,我们需要将$放在我们想要使用的列的名称之前,以便考虑具有相应名称的列对象。

df = df.withColumn("AgeTimesFare", $"Age" * $"Fare")

11.相互关系

探索数字变量和目标之间的相关性总是很方便的,在 Python 中,只需运行df.corr()就可以获得所有数字变量之间的相关系数矩阵。如果您想查看相关性,假设在年龄票价之间,我们只需指定列:df[['Age','Fare']].corr()

在 Scala 中,我们首先需要导入,然后通过指定列来运行命令。

import org.apache.spark.sql.functions.corr
df.select(corr("Age","Fare")).show()

就是这个!我希望你觉得这篇文章很有用,就像我写这篇文章一样有用。我打算发表第三部分,在那里我可以通过机器学习模型的例子来完成这个循环!

请随意查看:

本帖第一部分

我的其他中帖。

我的 LinkedIn 个人资料。

感谢您的阅读!

Python 绘图 API:通过 flask API 展示您的科学 python 绘图

原文:towardsdatascience.com/python-plot…

在我作为数据科学家的日常工作中,我经常需要将相对复杂的情节集成到后台应用程序中。这些图主要用于说明算法决策,并为运营部门提供数据直觉。

一种可能的方法是构建一个返回数据的 API,并让应用程序的前端使用或多或少复杂的 javascript 图表库来呈现数据。现在,每当我想改变一些东西时,我都需要改变前端和后端。

因此,我寻找一种快速、简单和可维护的解决方案,使绘图在任何 web 前端应用程序中都可用。我还寻找一种解决方案,允许我在一个地方改变我的图,而当例如一些新的功能请求进来时,总是需要改变前端。

我想到的只是用 matplotlibseaborn 等在 python 中构建情节,然后通过 flask 将它们暴露在网络上。听起来容易吗?这很容易!我会一步一步地教你。也许对你和我一样有帮助。

我们需要什么组件:

因此,让我们首先加载数据并绘制图表:

Plotting a plot and return it as BytesIO

A correlation matrix plot

这将导致情节左。如你所见,这里的技巧是将绘图保存到 BytesIO 对象中。我们现在可以通过 flask API 公开这个 BytesIO 对象,这样就完成了!

A simple endpoint to return the plot

在上面的代码片段中,我们创建了一个非常简单的端点,当客户端通过给定的路径请求时,它应该返回一个绘图图像。因此,如果您的服务器运行在 localhost 上,图像将在http://localhost:5000/plots/breast _ cancer _ data/correlation _ matrix下提供。

有了 flask,你可以使用 send_file 函数来帮助你发送一个文件到请求的客户端。在我们的例子中,这个文件是存储在 io 中的生成图。BytesIO 对象。我们只要把它传递给函数,就有了一个工作端点。你现在可以启动 flask 应用程序,你会看到:它的工作!

为了让我们的最终用户访问这个情节,我们现在将在一个 HTML 网站上集成图像。您可以只使用图像标签,它将开箱即用:

现在,您学习了如何通过 API 来展示您的科学计划。这样,您就可以帮助其他人在日常工作中更好地理解数据,而无需启动自己的 jupyter 笔记本服务器。

如果您需要更复杂的需要参数化的图,例如给定的时间范围,您可以使用查询参数,并将它们从 flask 传递到您的绘图函数。

为了说明这一点,我整理了一个更简洁的 gitlab 存储库,为您提供了更多的示例,此外还展示了一种将 dockerized flask 应用程序部署到 Heroku 的方法:

gitlab.com/dice89/pyth…

您可以在以下位置找到部署的应用程序:

python-sci-plotting.herokuapp.com/

我希望这篇博客教了你一个很好的小技巧,对你有所帮助!

Python 绘图基础

原文:towardsdatascience.com/python-plot…

使用 Matplotlib、Seaborn 和 Plotly 的简单图表

本教程将介绍如何使用三个 Python 绘图库的基础知识——Matplotlib、Seaborn 和 Plotly。阅读完本教程后,您应该能够使用这三个库来:

  • 绘制基本条形图和饼图
  • 设置和自定义绘图特征,如标题、轴和标签
  • 设置绘图的常规图形样式/特征,如自定义字体和颜色选择
  • 理解静态 Matplotlib 和交互式 Plotly 图形在使用和风格上的区别

我在这些图表中使用的数据是基于少数故事和来自山谷中的大象的调查结果,这是一项对 200 多名科技界女性的调查。

Matplotlib,Seaborn,和 Plotly 的区别

我听说过 Matplotlib 被称为 python 绘图包的“祖父”。它真的拥有绘制数据所需的一切,而且网上有很多关于如何使用它的例子。我发现它的缺点是,它的默认风格并不总是视觉上吸引人,而且学习如何做出你想要的调整可能很复杂。有时看起来应该很简单的事情需要几行代码。

Seaborn 是 Matplotlib 的补充,从下面的例子可以看出,它是建立在 Matplotlib 功能之上的。它有更美观的默认样式选项和特定图表——特别是可视化统计数据,它使创建引人注目的图形变得容易,而使用 Matplotlib 可能会很复杂。

Plotly 是一个集成了 Python API 的在线可视化库。在您设置您的帐户后,当您创建图表时,它们会自动链接到您的文件中(并且根据您的帐户/文件设置是公开的)。它相对容易使用,并提供交互式绘图功能,可以很容易地嵌入到网站中。它还具有良好的默认风格特征。

设置我们的库和数据框架

我使用 Pandas 来组织这些地块的数据,并首先通过以下导入为我的 Jupyter 笔记本设置参数。请注意,%matplotlib inline 只允许您运行笔记本并在输出中自动生成绘图,您只需设置一次 Plotly 默认凭证。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.font_manager
%matplotlib inlineimport plotly.plotly  as py
import plotly.graph_objs as go
plotly.tools.set_credentials_file(username='***', api_key='***')

我用熊猫建立了一个数据框。我们绘制的信息如下所示:

Fig.1 — Sample Responses from www.elephantinthevalley.com

Matplotlib 条形图示例

以下代码使用 Matplotlib 生成如下所示的条形图。您可以看到,我们首先将我们的图形设置为具有指定图形大小的子图。然后,我们使用处理所有默认样式/值的 rcParams 函数,设置我们希望作为 Matplotlib 绘图的默认文本和颜色参数。请注意,当您在下面的示例中使用 rcParams 时,它充当一个全局参数,并且您在每次使用 Matplotlib 时都要更改默认样式。

在这个例子中,我使用了一个自定义调色板,它是一个颜色列表,但是也可以(对于分组条形图来说是必要的)为您想要用于条形图的每组数据使用一个颜色值。还要注意,除了使用十六进制颜色代码,您还可以使用库支持的颜色名称。

我们设置总标题、轴标签、轴限制,甚至使用 rotation 参数旋转 x 轴刻度标签。

fig, ax = plt.subplots(figsize = (12,6))plt.rcParams['font.sans-serif'] = 'Arial'
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['text.color'] = '#909090'
plt.rcParams['axes.labelcolor']= '#909090'
plt.rcParams['xtick.color'] = '#909090'
plt.rcParams['ytick.color'] = '#909090'
plt.rcParams['font.size']=12color_palette_list = ['#009ACD', '#ADD8E6', '#63D1F4', '#0EBFE9',                         '#C1F0F6', '#0099CC']ind = np.arange(len(df['Question']))bars1 = ax.bar(ind, df['Percentage of Respondents'], 
        color = color_palette_list, 
        label='Percentage of yes responses to question')ax.set_title("Elephant in the Valley Survey Results")
ax.set_ylabel("Percentage of Yes Responses to Question")
ax.set_ylim((0,100))
ax.set_xticks(range(0,len(ind)))
ax.set_xticklabels(list(df['Q Code']), rotation=70)
ax.set_xlabel("Question Key")

这会产生以下输出:

Fig.3 — Matplotlib Bar Chart Example

Matplotlib 饼图示例

下面的代码生成了下图所示的饼图。与我们的条形图示例一样,我们首先将图形设置为子图,然后通过 rcParams 重置默认的 Matplotlib 样式参数。在这种情况下,我们也在下面的代码中定义我们的数据,而不是从我们的数据框中获取。我们选择分解饼图部分,因此设置了一个名为 explode 的变量,我们将颜色选项设置为前面定义的调色板列表中的前两个条目。将轴设置为“相等”可以确保我们得到一个圆形饼图。Autopct 将我们的值格式化为带有一组小数点的字符串。我们还指定了饼图的起始角度,以获得我们想要的格式,并使用 pctdistance 和 labeldistance 放置我们的文本。

在我们设置标题后,我们还选择为该图表使用图例,并指定图例不应有框架/可见边界框,我们通过使用指定的bbox_to_anchor参数“锚定”图例来专门设置图例位置。有用提示——如果您想让图例位于图形之外,首先将位置参数指定为一个特定的角,如“左上角”,然后使用 bbox_to_anchor 指定您想要将图例的“左上角”固定到的位置。

fig, ax = plt.subplots()plt.rcParams['font.sans-serif'] = 'Arial'
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['text.color'] = '#909090'
plt.rcParams['axes.labelcolor']= '#909090'
plt.rcParams['xtick.color'] = '#909090'
plt.rcParams['ytick.color'] = '#909090'
plt.rcParams['font.size']=12labels = ['Bay Area / Silicon Valley', 
         'Non Bay Area / Silicon Valley']
percentages = [91, 9]
explode=(0.1,0)ax.pie(percentages, explode=explode, labels=labels,  
       colors=color_palette_list[0:2], autopct='%1.0f%%', 
       shadow=False, startangle=0,   
       pctdistance=1.2,labeldistance=1.4)
ax.axis('equal')ax.set_title("Elephant in the Valley Survey Respondent Make-up")
ax.legend(frameon=False, bbox_to_anchor=(1.5,0.8))

这会产生以下输出:

Fig. 4 — Matplotlib Pie Chart Example

Seaborn 条形图示例

从下面的代码可以看出,Seaborn 实际上只是 Matplotlib 的一个包装器。在这个特殊的例子中,我们覆盖了默认的 rcParams 并使用了这样一个简单的图表类型,无论您是使用 Matplotlib 还是 Seaborn 绘图都没有任何区别,但是对于不改变默认样式或更复杂的绘图类型的快速图形,我发现 Seaborn 通常是不错的选择。

fig, ax = plt.subplots(figsize = (12,6))plt.rcParams['font.sans-serif'] = 'Arial'
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['text.color'] = '#909090'
plt.rcParams['axes.labelcolor']= '#909090'
plt.rcParams['xtick.color'] = '#909090'
plt.rcParams['ytick.color'] = '#909090'
plt.rcParams['font.size']=12ind = np.arange(len(df['Question']))color_palette_list = ['#009ACD', '#ADD8E6', '#63D1F4', '#0EBFE9',                       '#C1F0F6', '#0099CC']sns.barplot(x=df['Q Code'], y = df['Percentage of Respondents'],  
            data = df, palette=color_palette_list, 
            label="Percentage of yes responses to question", 
            ax=ax, ci=None)ax.set_title("Elephant in the Valley Survey Results")
ax.set_ylabel("Percentage of Yes Responses to Question")
ax.set_ylim(0,100)
ax.set_xlabel("Question Key")
ax.set_xticks(range(0,len(ind)))
ax.set_xticklabels(list(df['Q Code']), rotation=45)

这里唯一的区别是我们使用了sns.barplot,输出可以是相同的:

Fig. 5 — Seaborn Bar Chart Example

Plotly 条形图示例

下面的代码使用 Plotly 设置了我们的条形图。我们正在导入我们的库,并使用相同的调色板。然后我们设置我们的条形图参数,接着是我们的整体布局参数,如我们的标题,然后我们使用字典来设置我们想要的参数,如我们的轴和字体。在这些字典中,我们能够指定子参数,如 x 轴刻度标签旋转和 y 轴范围。然后,我们创建我们的图形,向它提供我们的数据和布局,并将我们的文件输出到我们的 Plotly 帐户,以便我们可以将其作为交互式 web 图形嵌入。

import  plotly.plotly  as py
import plotly.graph_objs as gocolor_palette_list = ['#009ACD', '#ADD8E6', '#63D1F4', '#0EBFE9', 
                      '#C1F0F6', '#0099CC']trace = go.Bar(
            x=df['Q Code'],
            y=df['Percentage of Respondents'],
            marker=dict(
            color=color_palette_list))data = [trace]layout = go.Layout(
    title='Elephant in the Valley Survey Results',
    font=dict(color='#909090'),
    xaxis=dict(
        title='Question Key',
        titlefont=dict(
            family='Arial, sans-serif',
            size=12,
            color='#909090'
        ),
        showticklabels=True,
        tickangle=-45,
        tickfont=dict(
            family='Arial, sans-serif',
            size=12,
            color='#909090'
        ),),
    yaxis=dict(
        range=[0,100],
        title="Percentage of Yes Responses to Question",
        titlefont=dict(
            family='Arial, sans-serif',
            size=12,
            color='#909090'
        ),
        showticklabels=True,
        tickangle=0,
        tickfont=dict(
            family='Arial, sans-serif',
            size=12,
            color='#909090'
        )
    )
)fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename='barplot-elephant-in-the-valley')

这会产生以下输出:

Fig. 6 — Plotly Bar Chart Example

Plotly 饼状图示例

到目前为止,您可能已经了解了我们是如何格式化和调用 Matplotlib 和 Plotly 中的参数来构建可视化的。让我们来看最后一个图表——一个如何使用 Plotly 创建类似于上图的饼状图的例子。

下面的代码设置并输出我们的图表。我们通过旋转参数来指定我们的起始角度,并使用 hover over 参数来记录当我们将鼠标悬停在饼图的每个组件上时应该可以获得哪些信息。

labels = ['Bay Area / Silicon Valley', 
          'Non Bay Area / Silicon Valley']
percentages = [91, 9]trace = go.Pie(labels=labels, 
               hoverinfo='label+percent', 
               values=percentages, 
               textposition='outside',
               marker=dict(colors=color_palette_list[0:2]),
              rotation=90)layout = go.Layout(
                    title="Elephant in the Valley Survey Respondent Make-up",
                    font=dict(family='Arial', size=12, color='#909090'),
                    legend=dict(x=0.9, y=0.5)
                    )data = [trace]fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename='basic_pie_chart_elephant_in_the_valley')

这会产生以下输出:

Fig. 7 — Plotly Pie Chart Example

就这样,我们完成了条形图和饼图的创建和定制。希望这有助于您学习如何使用这些库,以便为您的数据创建定制的图形解决方案。

最后,我想提一下,我认为谨慎使用饼图是很重要的。虽然它们被认为是一种“基本”图表类型,但它们通常不会增加对基础数据的理解,所以要谨慎使用它们,并且只在你知道它们对理解有价值的情况下使用。

密谋愉快!

资源:

15 分钟 Python 编程第 1 部分

原文:towardsdatascience.com/python-prog…

关于 Python

Python 3.0 也称为 Python 3000,是一种简单易学、功能强大的编程语言。它具有高效的高级数据结构和简单而有效的面向对象编程方法。Python 优雅的语法和动态类型,加上它的解释性质,使它成为大多数平台上许多领域中脚本和快速应用程序开发的理想语言。

安装 Python 3

[## 下载 Python

Python 编程语言的官方主页

www.python.org](www.python.org/downloads/)

第一个程序

让我们编写第一个程序,打印“Hello World!”

在 Python 中,我们使用 print(" ")函数在屏幕上显示文本。我们用引号来标记字符串的开始和结束;它们不会出现在结果中。 我们可以用两种方式运行 python 程序:

  1. Python Shell
  2. Python 脚本

使用 Python Shell

在机器上安装 Python 之后,要在命令提示符或终端中打开 Python shell 类型“python3 ”,这将开始一个交互式 Python 会话。此交互式会话不会将您的任何代码保存在文件中;一旦您退出 shell,它就会过期。

在您的 Python shell 中,您将找到当前运行的 Python 版本、一些信息和三个等待您命令的箭头。现在让我们编写代码,在 Python shell 中打印 Hello World。

>>> print(“Hello, World!”)
Hello, World!

>>>

你一按 enter 键,Python 解释器就运行代码并给出输出。

通用 python shell 用于随时测试程序。使用帮助(任何东西)获取文档。它比任何网络界面都要快。

执行 Python 脚本

要运行 Python 脚本,请将 Python 代码保存在. py 文件中,并在命令提示符或终端中使用 python3 file_name.py 运行程序。

例如: hello_world.py

print("Hello, World!")

$python3 hello_world.py 你好,世界!

在执行此操作之前,请确保更改了保存文件的目录。

当你编写大块的 Python 代码时,我们需要使用脚本模式。

您可以使用不同的文本编辑器来编写 Python 脚本,如 Sublime Text、Atom Editor。

数字和变量

我们知道数字无处不在,所以让我们看看 Python 是如何处理数字的。Python shell 可以当计算器用;您可以在 python shell 中执行基本的数学运算,如加法、除法等。

示例:

>>>3 + 3
6

>>>(84949*292)/322
77034

>>>

在 Python 中,我们有三种不同的数字类型,它们是整数、浮点数和复数。整数是没有小数部分的数字,可以是正数、负数或无符号数(零)。浮点值是带有小数部分的数字。

在编程中,变量只不过是某种东西的名称。变量名区分大小写。

要在 Python 中声明一个变量,你必须给出它的名字,后跟一个等号和初始化值。

当您一直将值赋给同一个变量名时,Python 会用新值替换旧值。

Python3 支持以下数据类型:

1.布尔 2。整数 3。浮子 4。复合体 5。线

数据类型. py

python3 数据类型. py

True <class 'bool'>167 <class 'int'>153.5 <class 'float'>(16.789+12323.45j) <class 'complex'>Mustang <class 'str'>

注意:不要以数字开始变量名。

用线串

在 python 中,字符串是用单引号或双引号括起来的字符序列。字符串是不可变的 Unicode 点序列。

示例:

字符串. py

python3 strings.py

<classstr’>
<classstr’>
Stark , CEO at Queen’s Consolidate

Python 格式化

使用。格式()

有时我们可能想用变量值构造字符串,这种字符串的概念性构造称为字符串插值。

示例:

插值. py

python3 插值. py

Hey Agent 47, your code number is 1011010.

数据结构

为了有效地组织和处理内存中的数据,我们使用数据结构,在 Python 中,我们有不同类型的数据结构和对它们执行的几种操作。

现在我们将讨论 Python 中的三种主要数据结构(列表、元组、字典)

列表

列表是有序的、可变的值序列,类似于 C 和 C++中的数组。

为了在 Python 中声明一个列表,我们给出了用逗号分隔的列表名称。

my_list = [item_1, item_2, item_3, item_4]

类似于字符串索引,列表索引从 0 开始,列表可以被切片、连接等等。

示例:

lists.py

python3 列表. py

<class 'list'>
['Paris', 'New York', 'Melbourne', 'Swiss']
Paris
New York
Swiss

注意:负索引从列表末尾开始,索引值为-1。

我们在列表上有几个方法,这里有几个例子。

列表 _ 方法. py

python3 list_methods.py

['Pen', 'Pencil', 'Notepad', 'Eraser']
['Pen', 'Pencil', 'Files', 'Notepad', 'Eraser']

index 方法在列表中查找给定值,并返回索引值。索引方法用于搜索值发生的位置。

这是列表方法的几个例子,要了解更多我们可以使用 help(list)获得所有的列表方法。

元组

元组是有序的、不可变的值序列。声明元组类似于列表,我们只是将值放在一对括号中。

my_tuple = (item_1, item_2, item_3)

元组是不可变的,这意味着我们不能在元组中添加或删除项,而且元组没有索引方法。

为什么要用元组?

元组比列表更快,也更安全。它们是写保护的,一旦声明,我们就不能添加新的项目。

元组. py

python3 tuple.py

<class 'tuple'>
('Oxygen', 'Hydrogen', 'Nitrogen')

词典

字典是无序的键值对集合。键和值可以是不同的数据类型。每个值都有一个惟一的键,作为字典中该值的标识符。

定义字典

my_dictionary = {key_1 : value1, key_2 : value2 , key_3 : value3}

示例:

my_dict.py

python3 my_dict.py

<class 'dict'>
{'jack': 4098, 'sape': 4139, 'robb': 2323}
{'jack': 4098, 'robb': 2323}

条件句(if,elif,else)

我们总是需要检查条件并相应地改变程序行为的能力。条件语句给了我们能力。最简单的形式是“if”语句。

条件语句测试一个表达式,看它是真还是假,并根据结果进行运算。

if expression:
    statement(s)

注意:Python 必须知道当条件为真时必须执行的语句数量。为了实现这一点,出现了缩进的概念。标题下的所有语句(如果在这种情况下)必须保持相同的缩进级别(4 个空格)。

缩进的概念适用于整个 Python 程序。

例如: 临时温度

python3 临时版本

Let’s go to the party!

如果有两种可能的条件,那么我们用 if,else 语句。

例子: movie_plan.py

python3 电影 _ 计划. py

Tickets are available, Let’s go to the movie.

多重条件

如果我们有两个以上的可能性,我们需要两个以上的分支。所以我们使用链式条件语句。elif 这个词是 else if 的缩写。elif 语句没有限制,但是最后一个分支必须是 else 语句。

示例:

calc_bmi.py

python3 clac_bmi.py

Computing…
Your bmi is 23.765432098765434
Perfect ! Normal weight

感谢阅读!

第 2 部分和第 3 部分使用以下链接

[## 15 分钟 Python 编程第 2 部分

控制流程、功能、面向对象。

medium.com](medium.com/towards-dat…) [## 15 分钟 Python 编程第 3 部分

异常、模块、包

medium.com](medium.com/towards-dat…)

参考:Python 编程的现代方法——瓦姆西·鞍马,皮尔森印度公司。

github.com/vamsi/pytho…

感谢 Richa Kulkarni 对故事的贡献。

已编辑:已添加字符串。

15 分钟 Python 编程第 2 部分

原文:towardsdatascience.com/python-prog…

控制流程、功能、面向对象。

控制流程

for 循环

Python 中的 for 循环能够遍历任何序列的项,比如 list 或 string。

它以任何有序的顺序遍历项目,即字符串、列表、元组、字典的键和其他可迭代的术语。python for 循环以关键字 for 开始,后面是一个变量属性,它将保存后面的序列对象的值。

for 循环的语法

for variable in sequence:
    statement(s)

示例:

colors.py

python3 colors.py

Red
Black
Blue
White
Pink

数学 _ 表格. py

在这种情况下,我们只打印语句块中的值。

python3 数学 _ 表格. py

1 times 5 is 5
2 times 5 is 10
3 times 5 is 15
4 times 5 is 20
5 times 5 is 25

While 循环

只要给定的条件为真,Python 编程语言中的 while 循环语句就会重复执行目标语句。与 for 循环不同,while 循环不会运行 n 次,而是直到满足定义的条件。

While 循环的语法

while condition:
    statement(s)

示例:

倒计时 _ 定时器. py

范围功能

Python 中的 range 函数生成一个数字列表,可用于循环迭代和其他少数情况。

现在让我们看看范围函数是如何工作的

range(n)
range(begin, end)

range(n)生成从 1 开始到(n-1)结束的整数。

range(begin,end)生成从 begin 开始到 end-1 结束的整数。

$python3

范围(8)

范围(0,8)

示例:

打印值域函数迭代的数字的平方。

方形. py

python3 广场. py

1
4
9
16
25
36

功能

函数是执行特定任务的可重用代码块。它是一个小的计算单元,可以接受参数,也可以返回值。

注意:函数体必须像“if”语句一样缩进。

声明函数

关键字def**引入了一个函数定义,后跟函数名和带括号的形参列表。构成函数体的语句从下一行开始,必须缩进。

句法上,

*def function_name(formal parameters):
    statement(s)*

注意:声明一个函数并不运行这个函数。为了运行,您必须使用函数名调用函数。

例子

greet.py

python3 greet.py

*Hello ! Welcome to the party.*

在这个程序中,我们创建了一个名为 greet 的函数,没有空括号之类的参数。该函数被定义为打印一个名为“Hello!欢迎参加聚会。”

所以调用函数只是打印给定的字符串。

带参数的函数。

函数可以接受参数,这些参数是你提供给函数的值,这样函数就可以利用这些参数做一些事情。参数在函数定义中的一对括号内指定,用逗号分隔。

示例:

greet_names.py

python3 greet_names.py

*Hello Flash
Hello Arrow
Hello Bat*

factorial.py

python3 factorial.py

*The factorial of number is 120*

参见递归,变量范围。

面向对象 Python 简介

在我们迄今为止编写的所有程序中,我们都是围绕函数来设计程序的,即操作数据的语句块。这被称为面向过程的编程方式。还有另一种组织你的程序的方法,就是把数据和功能结合起来,把它包装在一个叫做类的东西里面。这被称为面向对象编程范例。

快速浏览一下面向对象术语的基础知识。

:类是创建单个对象的蓝图。

对象:一个真实世界的实体,有状态和行为。

让我们用类中的类方法创建一个类 Person。

*class Person():
    def say(self):
        print("Hello")*

现在让我们为这个类创建一个对象实例。

*class Person():
    def say(self):
        print("Hello") jackman = Person()
jackman.say()*

进一步扩展这个情节让我们创建两个带参数的方法,hello 和 bye。

methods_examples.py

python3 method_examples.py

*Hello Lee How are you ?
Nice Meeting You Edison*

注意: Self 是所有实例方法的默认参数

这需要我们为每个类方法重复实例变量,而不是用实例变量创建一个对象。现在是时候使用构造函数了。

构造函数

Python 中的构造函数是在一个特殊的方法 init 下编写的。

现在让我们为一个对象写一个构造函数。在这个例子中,让我们用实例变量 name 和 year_of_birth 创建一个对象。在类中编写构造函数的过程消除了每个实例方法中实例变量的重复。

constructors.py

python3 构造函数. py

*Name of the person is Vihar
Your are 19 Years Old*

类和对象示例:

银行 _ 账户. py

python3 银行账户. py

*100
50
40
90*

使用第 3 部分的以下链接

* [## 15 分钟 Python 编程第 3 部分

异常、模块、包

medium.com](medium.com/towards-dat…)

如果您错过了《15 分钟》第 1 部分中的 Python 编程,请浏览链接。

[## 15 分钟 Python 编程第 1 部分

关于 Python

medium.com](medium.com/towards-dat…)

参考:Python 编程的现代方法——瓦姆西·鞍马,皮尔森印度公司。

github.com/vamsi/pytho…

感谢 Sai Tejaswie 对故事的少许贡献。

请继续关注第三部分。*

15 分钟 Python 编程第 3 部分

原文:towardsdatascience.com/python-prog…

异常、模块、包

错误和异常

Python 中最常见的观点是,它处理所有异常错误。一个异常是一个错误或其他异常情况发生的信号。有几个内置的异常,它指示某些条件,如 IndentationError:意外缩进,ZeroDivisionError:被零除。您还可以定义例外情况。

程序是易受影响的。如果代码总是返回有效的结果就好了,但有时无法计算出正确的结果。

例如,不能将一个数除以零,也不能访问负项列表中的第三个元素。

到目前为止,错误消息还没有被提及,但是如果您尝试过这些例子,您可能已经看到了一些。(至少)有两种不同的错误:

1.语法错误 2。异常

语法错误

语法错误,也称为解析错误,可能是您在学习 Python 时最常见的抱怨。语法错误几乎总是致命的,也就是说,几乎没有办法成功执行一段包含语法错误的代码。

示例:

>>> print("Hello
File "<stdin>", line 1
print("Hello
            ^
SyntaxError: EOL while scanning string literal

该错误是由箭头前面的标记引起的。在本例中,在 print()函数中检测到错误,因为括号没有闭合。

>>> while True print("Hello World !")
File "<stdin>", line 1
while True print("Hello World !")
          ^
SyntaxError: invalid syntax

由于 while 循环的条件后缺少冒号“:”,因此遇到了语法错误。

异常情况

当程序中发生异常情况时,就会发生异常。例如,如果您要读取一个不存在的文件,或者在程序运行时不小心删除了该文件,该怎么办?这种情况使用异常来处理。

类似地,如果你的程序有一些错误的语句呢? 这是由 Python 处理的,它告诉你有一个错误。

示例:

考虑一个简单的打印函数调用。如果我们把 print 这个词拼错成了 Print 呢?注意这里的大写。在这种情况下,Python 会引发语法错误。

>>> Print("Hello there !")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Print' is not defined

观察器:引发了一个 NameError,并且还打印出了检测到错误的位置。

现在让我们看看 Python 中几种错误

当一个数被零除时。

>>> 2/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

IndexError:当索引超出范围时。

>>> list = [1,2,3]
>>> list[4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range

TypeError:当操作或函数应用于不适当类型的对象时引发

>>> '2' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int

KeyError:当字典使用不当时会发生。

>>> dict = {'a' : 'Stark', 'b': 'Steve'}
>>> dict['c']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'c'

异常处理

像许多其他编程语言一样,Python 也有异常处理。我们可以使用 try except for 语句处理异常。我们基本上将常规语句放在 try 块中,并将所有错误处理程序放在 except 块中。

示例:

handling_exception.py

python3 handling_exception.py

You can't divide by zero.

捕捉 Python 中的特定异常

try 子句可以有任意数量的 except 子句来以不同的方式处理它们,但是在出现异常的情况下,只会执行一个子句。

我们可以使用一组值在 except 子句中指定多个异常。下面是一个伪代码示例。

try:
# do something
    passexcept ValueError:
# handle ValueError exception
    passexcept (TypeError, ZeroDivisionError):
# handle multiple exceptions
# TypeError and ZeroDivisionError
    passexcept:
# handle all other exceptions
    pass

引发异常

在 Python 编程中,当运行时出现相应的错误时,会引发异常,但是我们可以使用关键字 raise 强制引发异常。

示例:引发键盘中断

>>> raise KeyboardInterrupt
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
>>>

提高内存错误

>>> raise MemoryError(“Argument”)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
MemoryError: Argument

让我们提出一个值错误并排除这个错误。

提升 _ 错误. py

python3 提升 _error.py

Enter a negative integer: 5
That is not a negative number!

试试……终于

Python 中的 try 语句可以有一个可选的 finally 子句。这个子句无论如何都要执行,一般用来释放外部资源。

文件处理. py

在这里,它尝试打开当前目录中的 text.txt 文件,否则将引发一个 FileNotFoundError 错误。

模块

Python 附带了数百个模块,可以做各种各样事情。也可以从互联网上下载第三方模块。

Python 包括一组称为标准库的模块,例如,math,cmath,它包含实数和复数的数学函数,但还有更多。

使用 import 语句导入模块。

import module_name

现在让我们导入几个模块并在其中运行函数。

>>> import math
>>> math.pi
3.141592653589793
>>> math.sin(0)
0.0
>>> math.cos(45)
0.5253219888177297

这里,我们导入了数学模块,并使用 sin 和 cos 函数来返回值。

>>> import time
>>> print(time.asctime())
Thu Jul 27 01:47:01 2017

在本例中,我们导入了时间模块,并从该模块调用了 asctime 函数,该函数以字符串形式返回当前时间。

还有一种导入方式是使用 import 语句。

>>> from time import asctime
>>> asctime()
'Thu Jul 27 01:49:10 2017'

这里,我们只从时间模块中导入了 asctime 函数。

套餐

考虑一个声音包,组织你的 Python 代码的方式创造了令人敬畏的包。

sound/                        **Top-level package**
    __init__.py               Initialise the sound packageformats/                      **Sub-package** for file format
    __init__.py
    wavread.py
    wavwrite.py
    aiffread.py
    ...effects/                      **Sub-package** for sound effects
    __init__.py
    echo.py
    surround.py
    reverse.py
    ...filters/                      **Sub-package** for filters
    __init__.py
    equalizer.py
    vocoder.py
    karaoke.py
    ...

第三方包

Python 拥有最大的创建 Python 包的社区。在pypi.python.org/pypi有超过 100,000 种包装可供选择。

Python 包是所有模块的集合,这些模块恰当地连接成一个形式,并且是分布式的 PyPi,Python 包索引维护可用 Python 包的列表。现在,当您完成 pip 设置后,进入命令提示符或终端,并说

pip install <package-name>

运行此命令后,包将被安装到您的 python 库中。您可以将包导入到您的程序中。

恭喜您已经完成了基本的 Python 编程!

向所有阅读并支持这篇报道的人致敬。

第 1 部分和第 2 部分使用以下链接。

[## 15 分钟 Python 编程第 1 部分

关于 Python

medium.com](medium.com/towards-dat…) [## 15 分钟 Python 编程第 2 部分

控制流程、功能、面向对象。

medium.com](medium.com/towards-dat…)

写作方式和例子的灵感来自《Python 编程的现代方法》一书。

启动 GitHub 回购,传播爱。

[## vamsi/python-编程-现代方法

python 编程-现代方法-Python 编程工具包:现代方法书。参考书中的步骤…

github.com](github.com/vamsi/pytho…)

感谢 Richa Kulkarni 对故事的少许贡献。

感谢阅读。如果你觉得这个故事有帮助,请点击下面的💚去传播爱。

BigQuery 中的 Python PyPI stats:重新集群

原文:towardsdatascience.com/python-pypi…

Top growing 2018 Python packages (arbitrary selection and highlights)

让我们深入研究 Python 安装活动的原始日志。在这篇文章中,我们将看到如何测量一个包的流行度,哪个 Python 版本使用它,以及如何充分利用我们的查询。

Python 软件基金会为 Python 包索引中的每次下载提供原始元数据,包括从pip install开始的活动。现在,任何人都可以使用他们的免费的每月万亿字节的 BigQuery 分析来把握 Python 社区的脉搏,或者只是跟随他们喜欢的项目的趋势。这也是库作者决定他们应该支持什么平台的一个很好的工具。

你可以直接从来源阅读更多关于它的信息:

[## 分析 PyPI 包下载——Python 打包用户指南

本节将介绍如何使用 PyPI 包数据集来了解关于托管的一个(或多个)包的下载的更多信息…

packaging.python.org](packaging.python.org/guides/anal…)

例如,如果我们想检查 PySpark 自从holden karau推出以来的受欢迎程度,我们可以这样做:

SELECT TIMESTAMP_TRUNC(timestamp, WEEK) week
  , REGEXP_EXTRACT(details.python, r'^\d*\.\d*') python
  , COUNT(*) downloads
FROM `the-psf.pypi.downloads2017*`
WHERE file.project='pyspark'
GROUP BY week, python
ORDER BY week8.4 sec elapsed, 200.88 GB processed # find improvements below

PySpark downloads during 2017. Something seems weird.

在 10 月至 11 月期间,您可以看到一些奇怪的事情发生:Python 3.6 的下载量激增。谁干的?我们不知道——但是使用 BigQuery,我们可以自由地过滤掉这种可疑的活动,以便更好地了解情况:

SELECT TIMESTAMP_TRUNC(timestamp, WEEK) week
  , REGEXP_EXTRACT(details.python, r'^\d*\.\d*') python
  , COUNT(*) downloads
FROM `the-psf.pypi.downloads2017*`
WHERE file.project='pyspark'
GROUP BY week, python
HAVING python != '3.6' AND week<'2017-12-30'
ORDER BY week9.0 sec elapsed, 200.88 GB processed # find improvements below

PySpark downloads during 2017, excluding Python 3.6.

现在这看起来更好了:一旦我们排除 Python 3.6,我们会看到 PySpark 的健康采用曲线——由 Python 2.7 安装所主导。

这表明,获得原始数据比仅仅预先汇总数据更能让我们的数据更有洞察力。您可能已经注意到,我们每次都必须查询 200GB 的数据——很快就耗尽了我们每月的 1tb 免费查询量。

让我们利用集群表的能力来改进这一点。

聚集表上的相同查询

让我们重写一个聚集表上的最后一个查询:

SELECT TIMESTAMP_TRUNC(timestamp, WEEK) week
  , REGEXP_EXTRACT(details.python, r'^\d*\.\d*') python
  , COUNT(*) downloads
FROM `fh-bigquery.pypi.pypi_2017`
WHERE project='pyspark'
AND timestamp>'2000-01-01' # nag
GROUP BY week, python
HAVING python != '3.6' AND week<'2017-12-30'
ORDER BY week5.4 sec elapsed, 9.65 GB processed # winning

这很酷:如果您使用我的集群表而不是现有的官方表,同样的查询将只扫描大约 5%的数据。

注意事项:

  • FROM fh-bigquery.pypi.pypi_2017``是您可以找到我的集群表的地方。我每年创造一个。
  • FROM fh-bigquery.pypi.pypi_20*``让你年年匹配。
  • WHERE project=’pyspark'允许您从集群中受益,集群可以在这些表格中根据项目名称进行修剪。
  • 原始表上的file.project必须由project替换,因为集群不能在嵌套列上工作(还不能)。
  • timestamp>'2000-01-01'这是我强有力地提醒您这些是时间分区表的方式。如果您将查询限制在一年中的一段时间内,那么您查询的数据会相应减少——或者您可以从一个非常早的日期开始明确地询问所有数据。
  • REGEXP_EXTRACT(details.python, r’^\d*\.\d*’)将 Python 版本保留到最高有效位。
  • 这些查询将只与#standardSQL一起运行,因为#legacySQL不支持集群表。

我说“我的集群表”是因为我提供它们作为一个非官方的地方来获取这些日志,同时我们改进这个过程。根据您的反馈和意见,我们将努力将这些改进整合到官方资料库中。

工作日志

重新聚类

为了对每年的现有数据进行重新聚类,我做了如下工作:

CREATE TABLE `fh-bigquery.pypi.pypi_2017`
PARTITION BY DATE(timestamp)
CLUSTER BY project, country_code
OPTIONS(
   description="repartitioned and clustered from [https://bigquery.cloud.google.com/table/the-psf:pypi.downloads20180906](https://bigquery.cloud.google.com/table/the-psf:pypi.downloads20180906)"
   , require_partition_filter=true
)
AS
SELECT file.project project
  , STRUCT(file.filename, file.type, file.version) file
  , * EXCEPT(file)
FROM `the-psf.pypi.downloads2017*`34 min elapsed, 2.44 TB processed

每日更新

每天凌晨 3 点,我将运行一个计划查询,添加前一天的数据:

INSERT INTO `fh-bigquery.pypi.pypi_2018` (project, file, timestamp, country_code, url, details, tls_protocol, tls_cipher)SELECT file.project project
  , STRUCT(file.filename, file.type, file.version) file
  , * EXCEPT(file)
FROM `the-psf.pypi.downloads2018*`
WHERE _TABLE_SUFFIX = FORMAT_TIMESTAMP('%m%d', TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24 HOUR))
AND timestamp > ( # for idempotency
  SELECT MAX(timestamp) 
  FROM `fh-bigquery.pypi.pypi_2018` 
  WHERE timestamp>TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24*2 HOUR)
)48.9 sec elapsed, 24.83 GB processed

Configuring a scheduled query

常见问题解答

BigQuery 说它将处理大量的千兆字节,而我预期的要少一些

使用聚簇表,BigQuery 在运行查询之前给出了最大可计费字节的估计值——但是如果可能的话,查询可能会比这个值小。

一些例子:

SELECT *
FROM `fh-bigquery.pypi.pypi_2017`
WHERE timestamp>='2017-12-01'
LIMIT 1# 1.6s elapsed, 28.6 MB processed
# Stops scanning when it finds the first rowSELECT *
FROM `fh-bigquery.pypi.pypi_2017`
WHERE timestamp>='2017-12-01'
AND project='rpy2'
LIMIT 12.0s elapsed, 386 MB processed
# Finds the cluster that contains 'rpy2' and scans thatSELECT *
FROM `fh-bigquery.pypi.pypi_2017`
WHERE timestamp>='2017-12-01'
AND project='88888'
LIMIT 12.4s elapsed, 4.58 GB processed
# Finds the clusters which could contain '88888', but it's not thereSELECT *
FROM `fh-bigquery.pypi.pypi_2017`
WHERE timestamp>='2017-12-01'
AND project LIKE '%random%'
LIMIT 11.8s elapsed, 171 MB processed
# Opens all the clusters, until one contains a *random* projectSELECT *
FROM `fh-bigquery.pypi.pypi_2017`
WHERE timestamp>='2017-12-01'
AND project LIKE '%DOESNT-EXIST%'
LIMIT 12.7s elapsed, 221 GB processed
# Opens all the clusters, and keeps searching for an un-existing pattern

承认

后续步骤

我们应该将这些聚集的表移动到官方回购中,但让我们先讨论它们:

想要更多的故事?查看我的媒体关注我的推特,订阅 reddit.com/r/bigquery。并且尝试 big query——每个月你都可以从免费获得一个完整的万亿字节的分析。

[## 这些是真正的堆栈溢出趋势:使用页面视图

直到今天,获得 Stack Overflow 的季度浏览量并不容易。了解如何获得这些…

towardsdatascience.com](/these-are-the-real-stack-overflow-trends-use-the-pageviews-c439903cd1a)

Python Seaborn 统计数据可视化备忘单

原文:towardsdatascience.com/python-seab…

您现在很可能已经知道,通过数据可视化完成的数据故事讲述是每个数据科学家的一项基本技能:在您将原始数据转化为理解、见解和知识之后,您还需要将这些发现有效地传达给您的受众。

对于大多数初学者来说,他们使用的第一个 Python 数据可视化库自然是 Matplotlib。这是一个 Python 2D 绘图库,使用户能够制作出版物质量的图形。这是一个相当大的库,当你学习时,一个备忘单肯定会派上用场,但是当你设法有效地使用这个库时,你也将能够获得洞察力并更好地与其他包一起工作,例如 Pandas,它们打算随着时间的推移与 Matplotlib 建立更多的绘图集成。

您将能够处理的另一个包是 Seaborn,它是 Python 的统计数据可视化库。

DataCamp 为那些准备好开始使用这个数据可视化库的人创建了一个 Seaborn cheat sheet,并提供了一个方便的单页参考。

您将看到这个备忘单向您展示了用 Python 制作漂亮的统计图的五个基本步骤。

查看信息图 此处

本备忘单将带您完成绘制这些图所需的五个步骤:您将看到如何加载数据、设置图形美学、绘制、定制,以及最终使用 Seaborn 显示或保存您的图。

一旦你开始使用这个备忘单,以前看起来很难的事情肯定会变得更加清晰!结合 Seaborn Gallery文档和我们的教程使用。

此外,不要错过我们的其他数据科学备忘单,包括SciPyNumpyScikit-Learn

原载于www.datacamp.com

Python 集和集合论

原文:towardsdatascience.com/python-sets…

了解 Python 集合:它们是什么,如何创建它们,何时使用它们,内置函数,以及它们与集合论运算的关系。

集合与列表和元组

列表和元组是在序列中存储值的标准 Python 数据类型。集合是另一种也存储值的标准 Python 数据类型。主要区别在于,与列表或元组不同,集合不能多次出现相同的元素,也不能存储无序值。

Python 集合的优势

因为集合不能多次出现相同的元素,所以集合对于有效地从列表或元组中删除重复值以及执行像联合和交集这样的常见数学运算非常有用。

本教程将向您介绍几个关于 Python 集合和集合论的主题:

  • 如何初始化空集和有值集?
  • 如何在集合中添加和删除值
  • 如何有效地将集合用于成员资格测试和从列表中删除重复值等任务。
  • 如何执行常见的集合运算,如并集、交集、差集和对称差集。
  • 集合和冷冻集合的区别

就这样,让我们开始吧。

初始化集合

集合是不同的(唯一的)不可变值的可变集合,这些值是无序的。

您可以使用set()初始化空集。

emptySet = set()

要用值初始化一个集合,您可以向set()传递一个列表。

dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS']) dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])

如果您查看上面的 dataScientist 和 dataEngineer 变量的输出,请注意集合中的值没有按照中添加的顺序排列。这是因为集合是无序的。

包含值的集合也可以用花括号初始化。

dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'} dataEngineer = {'Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'}

请记住,花括号只能用于初始化包含值的集合。下图显示了使用不带值的花括号是初始化字典而不是集合的方法之一。

添加和删除集合中的值

要在集合中添加或删除值,首先必须初始化集合。

# Initialize set with values 
graphicDesigner = {'InDesign', 'Photoshop', 'Acrobat', 'Premiere', 'Bridge'}

向集合中添加值

您可以使用add方法向集合中添加一个值。

graphicDesigner.add('Illustrator')

需要注意的是,您只能向集合中添加不可变的值(如字符串或元组)。例如,如果您试图向集合中添加列表,将会得到一个 TypeError。

graphicDesigner.add(['Powerpoint', 'Blender'])

有几种方法可以从集合中删除一个值。

选项 1: 您可以使用remove方法从集合中删除一个值。

graphicDesigner.remove('Illustrator')

这种方法的缺点是,如果您试图删除一个不在您的集合中的值,您将得到一个 KeyError。

选项 2: 您可以使用discard方法从集合中移除一个值。

graphicDesigner.discard('Premiere')

这种方法相对于remove方法的好处是,如果您试图删除一个不属于集合的值,您将不会得到一个 KeyError。如果您熟悉字典,您可能会发现这与字典方法 get 的工作方式类似。

选项 3: 您还可以使用pop方法来移除和返回集合中的任意值。

graphicDesigner.pop()

需要注意的是,如果集合为空,该方法会引发一个 KeyError。

从集合中删除所有值

您可以使用clear方法从集合中移除所有值。

graphicDesigner.clear()

遍历一个集合

像许多标准 python 数据类型一样,可以遍历一个集合。

# Initialize a set 
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'} for skill in dataScientist: 
   print(skill)

如果您查看在 dataScientist 中打印每个值的输出,请注意,在集合中打印的值没有按照它们被添加的顺序。这是因为集合是无序的。

将集合转换为有序值

本教程强调了集合是无序的。如果您发现您需要以有序的形式从集合中获取值,那么您可以使用sorted函数,它输出一个有序的列表。

type(sorted(dataScientist))

下面的代码按字母降序输出数据集 dataScientist 中的值(本例中为 Z-A)。

sorted(dataScientist, reverse = True)

从列表中删除重复项

本节的部分内容之前已经在教程 18 个最常见的 Python 列表问题中探讨过,但是需要强调的是,集合是从列表中删除重复项的最快方式。为了说明这一点,让我们研究两种方法之间的性能差异。

方法 1: 使用集合从列表中删除重复项。

print(list(set([1, 2, 3, 1, 7])))

方法 2: 使用列表理解来删除列表中的重复项(如果你想复习列表理解,请参见本教程)。

def remove_duplicates(original):
    unique = []
    [unique.append(n) for n in original if n not in unique]
    return(unique)print(remove_duplicates([1, 2, 3, 1, 7]))

可以使用timeit库来测量性能差异,该库允许您对 Python 代码计时。下面的代码为每种方法运行代码 10000 次,并以秒为单位输出总时间。

import timeit# Approach 1: Execution time 
print(timeit.timeit('list(set([1, 2, 3, 1, 7]))', number=10000))# Approach 2: Execution time
print(timeit.timeit('remove_duplicates([1, 2, 3, 1, 7])', globals=globals(), number=10000))

比较这两种方法表明,使用集合来删除重复项更有效。虽然这看起来像是时间上的一个小差异,但是如果你有非常大的列表,它可以节省你很多时间。

设置操作方法

Python 中集合的一个常见用途是计算标准数学运算,如并、交、差和对称差。下图显示了两个集合 A 和 b 上的几个标准数学运算。每个维恩图的红色部分是给定集合运算的结果集合。

Python 集合提供了允许您执行这些数学运算的方法,以及提供等效结果的运算符。

在探索这些方法之前,让我们从初始化两组数据科学家和数据工程师开始。

dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'])
dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])

联盟

表示为 dataScientist ∪ dataEngineer 的并集是 dataScientist 和/或 dataEngineer 的所有值的集合。您可以使用union方法找出两个集合中的所有唯一值。

# set built-in function union
dataScientist.union(dataEngineer)# Equivalent Result 
dataScientist | dataEngineer

从并集返回的集合可以被可视化为下面维恩图的红色部分。

交集

两个集合 dataScientist 和 dataEngineer 的交集表示为 dataScientist ∩ dataEngineer,它是 dataScientist 和 dataEngineer 的所有值的集合。

# Intersection operation
dataScientist.intersection(dataEngineer)# Equivalent Result
dataScientist & dataEngineer

从交集返回的集合可以被可视化为下面维恩图的红色部分。

您可能会发现,在这种情况下,您希望确保两个集合没有公共值。换句话说,你希望两个集合的交集是空的。这两个集合称为不相交集合。您可以通过使用isdisjoint方法来测试不相交的集合。

# Initialize a set
graphicDesigner = {'Illustrator', 'InDesign', 'Photoshop'}# These sets have elements in common so it would return False
dataScientist.isdisjoint(dataEngineer)# These sets have no elements in common so it would return True
dataScientist.isdisjoint(graphicDesigner)

您可以注意到,在下面维恩图所示的交集中,不相交集 dataScientist 和 graphicDesigner 没有共同的值。

差异

两个集合 dataScientist 和 dataEngineer 的差,表示为 dataScientist \ dataEngineer,是 dataScientist 的所有值的集合,这些值不是 dataEngineer 的值。

# Difference Operation
dataScientist.difference(dataEngineer)# Equivalent Result
dataScientist - dataEngineer

从差异返回的集合可以被可视化为下面维恩图的红色部分。

对称 _ 差异

两个数据集 dataScientist 和 dataEngineer 的对称差表示为 dataScientist △ dataEngineer,它是恰好是两个集合中一个集合的值而不是两个集合的值的集合。

# Symmetric Difference Operation
dataScientist.symmetric_difference(dataEngineer)# Equivalent Result
dataScientist ^ dataEngineer

从对称差返回的集合可以被可视化为下面维恩图的红色部分。

集合理解

您可能之前已经了解了列表理解字典理解和生成器理解。还有一套理解。集合理解非常相似。Python 中的集合理解可以按如下方式构造:

{skill for skill in ['SQL', 'SQL', 'PYTHON', 'PYTHON']}

上面的输出是两个值的集合,因为集合不能有相同元素的多次出现。

使用集合理解背后的想法是让你用代码写和推理,就像你用手做数学一样。

{skill for skill in ['GIT', 'PYTHON', 'SQL'] if skill not in {'GIT', 'PYTHON', 'JAVA'}}

上面的代码类似于您之前了解到的集合差异。只是看起来有点不一样。

会员测试

成员资格测试检查特定元素是否包含在序列中,例如字符串、列表、元组或集合。在 Python 中使用集合的一个主要优点是它们为成员测试进行了高度优化。例如,集合比列表更有效地进行成员资格测试。如果你有计算机科学背景,这是因为对于列表,集合中成员测试的平均用例时间复杂度是 O(1)比 O(n)。

下面的代码显示了一个使用列表的成员测试。

# Initialize a list
possibleList = ['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala']# Membership test
'Python' in possibleList

对于器械包也可以做类似的事情。集合只是碰巧更有效率。

# Initialize a set
possibleSet = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala'}# Membership test
'Python' in possibleSet

由于possibleSet是一个集合,值'Python'possibleSet的值,这可以表示为'Python'possibleSet

如果你有一个不属于集合的值,比如'Fortran',它将被表示为'Fortran'possibleSet

子集

理解成员关系的一个实际应用是子集。

我们先初始化两组。

possibleSkills = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'} mySkills = {'Python', 'R'}

如果集合mySkills的每个值也是集合possibleSkills的值,那么mySkills被称为possibleSkills的子集,数学上写成mySkillspossibleSkills

您可以使用issubset方法查看一个集合是否是另一个集合的子集。

mySkills.issubset(possibleSkills)

因为该方法在这种情况下返回 True,所以它是一个子集。在下面的维恩图中,注意集合mySkills的每个值也是集合possibleSkills的值。

冰冻集

您遇到了嵌套列表和元组。

# Nested Lists and Tuples
nestedLists = [['the', 12], ['to', 11], ['of', 9], ['and', 7], ['that', 6]]
nestedTuples = (('the', 12), ('to', 11), ('of', 9), ('and', 7), ('that', 6))

嵌套集合的问题是你通常不能有嵌套集合,因为集合不能包含可变值。

在这种情况下,您可能希望使用冷冻箱。除了 frozenset 是不可变的之外,frozenset 与集合非常相似。

你可以用frozenset()制作一个冰冻人。

# Initialize a frozenset
immutableSet = frozenset()

如果您使用类似下面代码的 frozenset,您可以创建一个嵌套集。

nestedSets = set([frozenset()])

重要的是要记住,frozenset 的一个主要缺点是,由于它们是不可变的,这意味着您不能添加或删除值。

结论

Python 集合对于从列表等集合中有效移除重复值以及执行联合和交集等常见数学运算非常有用。人们经常遇到的一些挑战是何时使用各种数据类型。例如,如果你觉得不确定什么时候使用字典比使用字典更有利,我鼓励你去看看 DataCamp 的日常练习模式。如果您对本教程有任何问题或想法,请在下面的评论中或通过 Twitter 联系我们。

最初发表于www.datacamp.com