TowardsDataScience 博客中文翻译 2020(七百三十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

Python 股票分析—使用 Python 和 Plotly 的蜡烛图

原文:https://towardsdatascience.com/python-stock-analysis-candlestick-chart-with-python-and-plotly-e619143642bb?source=collection_archive---------9-----------------------

蜡烛图是一种非常常见和有用的股票价格表示法。通过查看蜡烛图,我们可以直观地看到任何给定股票的开盘价、收盘价、最低价和最高价。

在本文中,我将向您展示如何使用 Python、Pandas 和 Plotly 来构建您自己的蜡烛图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

M. B. M.Unsplash 上的照片

我们将从导入所有需要的包开始。我们将需要熊猫PlotlyJson请求。需要 Requests 和 Json 从免费的金融 API Ffinancialmodelingprep中检索股票信息。

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import requests
import jsonquote = 'AAPL'days = 300def candlestick(quote,days):
    r =     requests.get(f'[https://financialmodelingprep.com/api/v3/historical-  price-full/{quote}?timeseries={days}'](https://financialmodelingprep.com/api/v3/historical-price-full/{quote}?timeseries={days}')) r = r.json() return r

我们将 API 端点 url 作为 get 函数的一个参数进行传递,该 URL 存储在一个名为 r 的变量中。然后,我们把 API 响应转换成 Json,这样我们 Python 就可以很容易地用 Python 操纵它了。变量 r 将包含我们传递给函数烛台的任何股票的历史价格数据。在上面的例子中,我们传递了函数’ AAPL '(即苹果)和 300 天作为参数。因此,结果是,我们得到一个代表 300 个数据点的列表。列表中的每个元素都是一个字典,包含我们的蜡烛图所需要的信息,即的*开市、*的高、低和收市的。

“symbol” : “AAPL”, “historical” : [ { “date” : “2015–01–20”, “open” : 107.84, “high” : 108.97, “low” : 106.5, “close” : 108.72, “volume” : 4.98999E7, “unadjustedVolume” : 4.98999E7, “change” : -0.88, “changePercent” : -0.816,....

如果可能的话,我总是喜欢把我的数据转换成熊猫数据框架,因为它让我以一种非常容易和方便的方式处理、操作和清理我的数据。这就是我们用下面两行代码实现的。

首先,我们解析变量 r 来提取与历史键相关的值,并将其存储在名为 stockdata 的变量中。通过这种方式,我们保留了一个字典列表。每个字典包含一天的股票价格数据。然后,我们可以简单地将 stockdata 列表转换成 Pandas 数据帧。

stockdata = r[‘historical’]
stockdata_df = pd.DataFrame(stockdata)

如果我们打印出我们的 Pandas data frame*stock data _ df,*我们会得到类似下面的内容,其中每行代表一天,每列为我们提供股票价格信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到目前为止一切顺利。现在,让我们进入有趣的部分。我们可以开始用 Plotly 构建我们的图表。Plotly 是一个非常强大的图形库。非常容易使用 Python 和熊猫。

首先,我们需要创建一个包含数据点的 fig 对象。在我们的数字中,我们定义了我们的日期,开盘价、最高价、最低价和收盘价。每个数据点都将是我们的股票数据 _df 熊猫数据框架中的一列。例如,open 将包含我们的 Pandas 数据框架中包含的每个日期的开盘价。因为,我们在函数中传递了 300 天,open 将包含苹果最近 300 天的公开股票价格。

我们还可以使用 Plotly fig.update_layout 命令更新图表的布局,为图表添加一些漂亮的标题,更改字体,并确保文本位于图表区域的顶部中央。

最后,我们可以使用 fig.show() 来显示蜡烛图:

fig = go.Figure(data=[go.Candlestick(x=stockdata_df['date'],
                open=stockdata_df['open'],
                high=stockdata_df['high'],
                low=stockdata_df['low'],
                close=stockdata_df['close'])])fig.update_layout(
    title= {
        'text': quote,
      'y':0.9,
        'x':0.5,
        'xanchor': 'center',
        'yanchor': 'top'},
      font=dict(
        family="Courier New, monospace",
        size=20,
        color="#7f7f7f"
    )
    )fig.show()

现在神奇的是,或者说是因为我们的编码技能,一个令人印象深刻的烛台图表显示在我们面前,包括一个滑块来放大和缩小任何特定的时间段。自己尝试一下吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用 Python 和 Plotly 制作的烛台图

我已经包括了下面的整个脚本供您参考。只需替换报价天数变量来选择想要的股票和你想在图表中显示的天数。

注意:如果您在运行下面的代码时遇到任何问题,请确保您已经安装了所有必需的库。

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import requests
import jsonquote = ‘AAPL’
days = 300def candlestick(quote,days):
  r = requests.get(f’[https://financialmodelingprep.com/api/v3/historical-price-full/{quote}?timeseries={days}'](https://financialmodelingprep.com/api/v3/historical-price-full/{quote}?timeseries={days}'))
  r = r.json()

  stockdata = r[‘historical’]
  stockdata_df = pd.DataFrame(stockdata)

  fig = go.Figure(data=[go.Candlestick(x=stockdata_df[‘date’],
  open=stockdata_df[‘open’],
  high=stockdata_df[‘high’],
  low=stockdata_df[‘low’],
  close=stockdata_df[‘close’])]) fig.update_layout(
    title= {
     ‘text’: quote,
     ‘y’:0.9,
     ‘x’:0.5,
     ‘xanchor’: ‘center’,
     ‘yanchor’: ‘top’},
   font=dict(
    family=”Courier New, monospace”,
    size=20,
    color=”#7f7f7f”
 )) fig.show()

candlestick(quote,days)

Python 股票分析-损益表瀑布图

原文:https://towardsdatascience.com/python-stock-analysis-income-statement-waterfall-chart-ffb7f9a4687f?source=collection_archive---------13-----------------------

在这篇文章中,我展示了如何使用 Python、Pandas 和 Plotly 以瀑布图的形式显示损益表。

在这篇文章中,我将向你展示如何使用 Python、Pandas 和 Plotly 以瀑布图的形式显示损益表。

一个 瀑布图 是一种表示数据的方式,以便可视化不同项目的累积效果。在我们的例子中,我们将能够看到每一个收益表行从收入到净收入的影响。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Pixabay 来自 像素

我将文章分为两部分,在第一部分,我们将从免费的财务 APIFinancialmodelingprep中检索我们感兴趣的任何公司的损益表数据。然后,我们将使用 Pandas 来清理数据并执行一些基本操作。

在文章的第二部分,我们将使用 Plotly 将损益表转换成一个漂亮的瀑布图表示。

如果你跟随这篇文章并和我一起编码,你将能够为你感兴趣的任何上市公司建立瀑布图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

瀑布图形式的损益表— Python for Finance

好了,让我们开始编码第一部分。我们需要导入 json请求库,以便向 API 端点发出 GET 请求。我们还导入 Pandas 来将请求的数据转换成 Pandas DataFrame ,最后,我们将导入 Ploty ,这是我们将用来创建图表的库。

对于所有不熟悉 Plotly 的人来说,这是一个免费的 Python 图形库,它提供了创建非常有吸引力的交互式图表的可能性。

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import requests
import json

导入所需的包后,我们开始创建我们的函数 selectquote ,我们将在其中添加将我们的数据转换成 Pandas 数据帧的逻辑。我们发出一个 http 请求,并将数据转换成 Json ,这样我们就可以用 PythonPandas 轻松处理它。

然后,从通过 API 检索的信息中,我们将关键字 financials 的值存储到 stock 变量中。Financials 包含一个字典列表,其中每个字典代表一个季度的损益表。

接下来,我们从股票字典中创建一个 Pandas 数据框架,并对其进行转置,以便将损益表项目作为行,将日期作为标题。

def selectquote(quote): 
   r= requests.get(f"https://financialmodelingprep.com/api/v3/financials/income-statement/{quote}?period=quarter")    r = r.json() 
   stock = r['financials'] stock = pd.DataFrame.from_dict(stock) 
   stock = stock.T   
   stock.columns = stock.iloc[0]
   stock.reset_index(inplace=True) 
   return  stock selectquote('AAPL')

到目前为止,如果我们打印出我们的库存熊猫数据帧,我们会得到类似于下面的苹果的结果,因为我们已经将 AAPL 传递给了我们的选择报价函数。请注意,我们需要作为参数传递股票的代码,而不是全名

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们创建图表之前,还有一些东西需要清理。

首先,我们将熊猫数据框切片,只保留上一季度的损益表。然后,我们将列名重命名为股票名称,而不是日期。最后,我们将损益表信息(即列)转换成一个数字。

stock = stock.iloc[:,0:2]stock.rename(columns={ stock.columns[1]: quote }, inplace = True)cols = stock.columns.drop('index')stock[cols] = stock[cols].apply(pd.to_numeric, errors='coerce')stock = stock.iloc[1:,]

重新运行我们的代码后,我们可以看到苹果公司最新的季度收入报表:

incomeStatement = selectquote('AAPL')
print(incomeStatement)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python for Finance —损益表

我们还需要提取收入、销货成本等的价值。从我们的库存熊猫数据框架以便在瀑布图中使用。我们可以很容易地用 iloc 找到损益表项目的价值。我们将费用乘以 -1 ,使其符合负号约定:

Revenue = incomeStatement[incomeStatement['index'] == 'Revenue'].iloc[0][1]COGS = incomeStatement[incomeStatement['index'] == 'Cost of Revenue'].iloc[0][1]*-1grossProfit = incomeStatement[incomeStatement['index'] == 'Gross Profit'].iloc[0][1]RD = incomeStatement[incomeStatement['index'] == 'R&D Expenses'].iloc[0][1]**-1**GA =* incomeStatement*[*incomeStatement*['index'] == 'SG&A Expense'].iloc[0][1]**-1operatingExpenses = incomeStatement[incomeStatement['index'] == 'Operating Expenses'].iloc[0][1]**-1**interest =* incomeStatement*[*incomeStatement*['index'] == 'Interest Expense'].iloc[0][1]**-1EBT = incomeStatement[incomeStatement['index'] == 'Earnings before Tax'].iloc[0][1]incTax = incomeStatement[incomeStatement['index'] == 'Income Tax Expense'].iloc[0][1]*-1netIncome = incomeStatement[incomeStatement['index'] == 'Net Income'].iloc[0][1]

太好了,我们已经完成了代码的第一部分。现在,让我们进入有趣的部分,我们将创建一个瀑布图

首先,我们将创建一个 对象,它将包含构建图表所需的数据点。对于瀑布图,我们将需要一个度量列表,其中我们将指出每个变量是相对度量还是总度量。这将影响图表的构建方式。例如,毛利将是一个总的衡量标准,它将从图表的底部开始。**

然后,我们将有我们的 x 轴,它将包含损益表项目的名称,最后,我们的 y 将包含与每个 x 相关联的值。此外,我们将有一个文本列表,其中包含我们希望在图表中显示的每个项目的值。

我们将文本除以 100,000 来表示以百万计的数字。

fig = go.Figure(go.Waterfall(name = "20", orientation = "v",measure = ["relative", "relative", "total", "relative", "relative", "total","relative","total","relative","total"],x = ["Revenue", "COGS", "Gross Profit", "RD", "G&A", "Operating Expenses","Interest Expense", "Earn Before Tax","Income Tax","Net Income"],textposition = "outside",text = [Revenue/100000, COGS/100000, grossProfit/100000, RD/100000, GA/1000000, operatingExpenses/1000000,Interest/100000, EBT/100000,incTax/100000, NetIncome/100000],y = [Revenue, COGS, grossProfit, RD, GA, operatingExpenses, Interest,EBT, incTax, NetIncome], connector = {"line":{"color":"rgb(63, 63, 63)"}}, )) fig.update_layout( 
title = "Profit and loss statement",
showlegend = **True** ) fig.show()

现在,如果我们运行代码,我们可以看到苹果公司的收益表是一个瀑布图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

自己尝试使用不同的股票,只需将所需公司的股票代码作为参数传递给 selectquote 函数。

下面看到完整的代码供你参考。请注意,您需要安装教程中使用的所有库。否则,代码将不起作用。

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import requests
import json

def selectquote(quote):
     r= requests.get(f"https://financialmodelingprep.com/api/v3/financials/income-statement/{quote}?period=quarter")
     r = r.json()
    stock = r['financials']
    stock = pd.DataFrame.from_dict(stock)
    stock = stock.T
    stock.columns = stock.iloc[0]
    stock.reset_index(inplace=True)
    stock = stock.iloc[:,0:2]
    stock.rename(columns={ stock.columns[1]: quote }, inplace = True)
    cols = stock.columns.drop('index')
    stock[cols] = stock[cols].apply(pd.to_numeric, errors='coerce')
    stock = stock.iloc[1:,]
    return stock

incomeStatement = selectquote('AAPL')Revenue = incomeStatement[incomeStatement['index'] == 'Revenue'].iloc[0][1]COGS = incomeStatement[incomeStatement['index'] == 'Cost of Revenue'].iloc[0][1]*-1grossProfit = incomeStatement[incomeStatement['index'] == 'Gross Profit'].iloc[0][1] RD = incomeStatement[incomeStatement['index'] == 'R&D Expenses'].iloc[0][1]*-1 GA = incomeStatement[incomeStatement['index'] == 'SG&A Expense'].iloc[0][1]*-1operatingExpenses = incomeStatement[incomeStatement['index'] == 'Operating Expenses'].iloc[0][1]*-1 interest = incomeStatement[incomeStatement['index'] == 'Interest Expense'].iloc[0][1]*-1EBT = incomeStatement[incomeStatement['index'] == 'Earnings before Tax'].iloc[0][1]incTax = incomeStatement[incomeStatement['index'] == 'Income Tax Expense'].iloc[0][1]*-1netIncome = incomeStatement[incomeStatement['index'] == 'Net Income'].iloc[0][1] 

fig = go.Figure(go.Waterfall(
    name = "20", orientation = "v", measure = ["relative", "relative", "total", "relative", "relative", "total","relative","total","relative","total"],

    x = ["Revenue", "COGS", "Gross Profit", "RD", "G&A", "Operating Expenses","Interest Expense", "Earn Before Tax","Income Tax","Net Income"], textposition = "outside",

    text = [Revenue/100000, COGS/100000, grossProfit/100000, RD/100000, GA/1000000, operatingExpenses/1000000,Interest/100000, EBT/100000,incTax/100000, NetIncome/100000],

     y = [Revenue, COGS, grossProfit, RD, GA, operatingExpenses, Interest,EBT,incTax,NetIncome],

    connector = {"line":{"color":"rgb(63, 63, 63)"}},

fig.update_layout(
         title = "Profit and loss statement",
         showlegend = True
 )))

fig.show()

我创建了下面的 Youtube 视频,我一步一步地建立瀑布图。如果您在理解本文中的代码时遇到困难,这是值得一查的。

损益表的瀑布图— Python for Finance

原载于【https://codingandfun.com】

Python 字符串插值

原文:https://towardsdatascience.com/python-string-interpolation-829e14e1fc75?source=collection_archive---------19-----------------------

了解用 Python 实现字符串插值的方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

字符串插值是将值注入字符串文字中的占位符(占位符只是一个变量,您可以稍后将数据/值赋给它)的过程。它有助于以一种更好的方式动态格式化输出。Python 支持多种格式化字符串文字的方式。所有字符串插值方法总是返回新值,并且不处理原始字符串。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

使用%(模)运算符

除了其正常的计算用法, % 运算符在 str 类中被重载以执行字符串格式化,它将各种类类型插入到字符串文字中。下面是一些常用的格式说明符,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

使用 % 的一般格式为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

这里, % 表示使用 Python 的字符串格式化功能时字符串的转换类型。

使用%的字符串插值

Output:
-------
Result of calculation is 4.38

Hey! I'm Emma, 33 years old and I love Python Programing

Hey! I'm Emma and I'm 33 years old.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

在上面的例子中,我们使用了两个 %s 和一个 %d 格式说明符,它们只是元组 (‘Emma ‘,33,’ Python’) 值的占位符。 % 只接受一个参数,因此元组用于多值替换。请注意,元组的值是按照指定的顺序传递的。如果一个值的类型和对应的格式说明符的类型不匹配,Python 会抛出 类型错误 异常。

在下面的代码中, %d 是字符串的第一个值 ‘Emma’ 的格式说明符,因此引发了 TypeError 异常。

print("\nHey! I'm **%d**, %d years old and I love %s Programing"%('**Emma**',33,'Python')) **--------------------------------------------------------------------**
**TypeError**                                 Traceback (most recent call last)
<ipython-input-5-f2e9acc11cdb> in <module>
      1 
----> 2 print("\nHey! I'm **%d**, %d years old and I love %s Programing"%(**'Emma'**,33,'Python'))  

**TypeError**: %d format: a number is required, not str

尽管 % -formatting 在 Python 中从一开始就是可用的,但是当单个字符串中有多个替换时,它就显得笨拙了。

使用。format()方法

Str.format()用于位置格式化,这允许重新排列字符串中占位符的顺序,而不改变它们的排列顺序。格式()。{ }用作占位符,并且是方法传递的唯一值。format()将被替换为{ },其余的字符串文字将在输出中保持不变。

位置格式可以通过在占位符中使用索引或关键字来实现。如果它们都没有被指定,对象将按照它们在中被提到的顺序被注入。默认情况下,格式为()。

字符串插值使用。格式( )

Output:
-------
Hey! I'm Emma, 33 years old, and I love Python Programming.

33 years old Emma loves Python programming.

Emma loves Python programming and she is 33 years old.

使用索引/关键字或者保持黑色,你不能将它们混合在一起,因为 Python 会抛出 值错误 异常*。*在下面的代码中,两个占位符保持空白,一个具有索引“2”引用,因此引发了异常。

name="Emma"
age=33
lan="Python"print("**{}** years old **{2}** loves **{}** programming.".format(age,lan,name))**--------------------------------------------------------------------**
**ValueError**                                Traceback (most recent call last)
<ipython-input-15-b38087c9c415> in <module>
      5 lan="Python"
      6 
----> 7 print("**{}** years old **{2}** loves **{}** programming."**.**format**(**age**,**lan**,**name**))**
      8 

**ValueError**: cannot switch from automatic field numbering to manual field specification

。format()方法是通用的,可以很容易地用于所有的数据结构。

字符串插值使用。格式( )

Output:
-------
Hey! My name is Emma, I'm 33 years old, currently living in UK and love Python programming

Person info from List: Emma from UKPerson info from Tuple: Emma 33 UK

Person info Set: 33 Python Emma

如上面的代码所示,从 dictionary person_dict 接收的值将键值作为字符串中的占位符。 **(双星号)用于解包映射到键值的字典值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

对于列表和元组,在占位符中使用了索引。

使用 f 字符串格式

f-string 或格式化字符串文字提供了一种使用最小语法格式化字符串的方法。(在 Python 3.6 中引入)。代码可读性很高,因此它通常是格式化字符串的首选方式。“F”或“F”用作前缀,{}用作占位符。不像。format(),f-string 不允许空括号{}。f 字符串表达式在运行时计算。

string 比两种最常用的字符串格式化机制更快,%-formatting 和。格式( )

使用 f 弦的字符串插值

Output:
-------
Emma is 33 years old currently living in UK and loves Python programming.
33 years old  Emma lives in UK and loves Python programming
'Emma' is a python developer from UK

Date in default format: 2020-06-04 17:01:31.407452 
Date in custom format: 04/06/20

如上面的代码所示,我们只需在字符串的开头附加’ f ',并将变量名直接放入占位符{ }。f-string 格式可以无缝地用于类及其对象。

Output:
-------
Person Details: Emma is 33 years old Python developer.

[Name: Emma, Age: 33, Programming_language: Python]

这里,我们在 Person 类中定义了两个方法。开头附加“f ”,类/对象引用变量放在{ }中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

干净精准!

使用模板类

字符串模块的模板类有助于字符串插值的另一种方式。它允许您使用映射对象替换字符串。这里,前面带有符号’ $ '的有效 python 标识符被用作占位符。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

基本上,我们可以使用模板类对象定义一个字符串文字,然后通过 substitute()或 safe_substitute()方法映射占位符的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

$ '符号执行实际的替换,标识符用于映射方法 substitute()或 safe_substitute()中指定的替换关键字。

substitute( ) —如果没有提供相应占位符的值,则会引发错误。

safe_substitute( ) —当用户提供的数据可能不完整时,此选项更合适。(当数据丢失时,占位符保持不变。)

使用模板类的字符串插值

Output:
-------
Emma is 33 years old and loves Python programming!

$age years old Emma loves Python programming

$age years old Harry loves Java programming

在上面的例子中,我们已经创建了保存字符串的模板类的对象 person_info 。然后使用 substitute( ) 方法注入实际值,它将值映射到占位符名称。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

如果没有提供相应占位符的值,substitute( ) 将引发错误。这里, substitute( ) 中没有提供 $years 的值,因此它引发 KeyError 异常。

person_info=Template('\n$name is $years years old and loves $lan programming!')   
print(person_info.substitute(name='Emma',lan='Python'))**--------------------------------------------------------------------**
**KeyError**                                  Traceback (most recent call last)
<ipython-input-7-2b10997fef23> in <module>
      4 #creating object of Template class
      5 person_info=Template('\n$name is $years years old and loves $lan programming!')
----> 6 print(person_info.substitute(name='Emma',lan='Python'))  #substitute()
      7 
      8 

~\Anaconda3\lib\string.py in substitute(*args, **kws)
    130             raise ValueError('Unrecognized named group in pattern',
    131                              self.pattern)
--> 132         return self.pattern.sub(convert, self.template)
    133 
    134     def safe_substitute(*args, **kws):

~\Anaconda3\lib\string.py in convert(mo)
    123             named = mo.group('named') or mo.group('braced')
    124             if named is not None:
--> 125                 return str(mapping[named])
    126             if mo.group('escaped') is not None:
    127                 return self.delimiter

**KeyError**: 'years'

在同一个示例中,我们还使用了 safe_substitute(),其中我们没有为占位符 $age 分配任何值,因此它在输出中保持不变,不会引发任何异常。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

**$age** years old Emma loves Python programming

**$age** years old Harry loves Java programming

该方法被考虑用于复杂的定制字符串操作;但是,str 最大的局限性。模板类是,它只接受字符串参数。

结论

我个人大部分时间使用 f-string,因为它简洁,编写非常方便,同时代码可读性很高。该主题的一些重要资源是,

本文中使用的代码可以从我的 GitHub 库中获得。

Python 字符串方法

原文:https://towardsdatascience.com/python-string-methods-7ac76ed7590b?source=collection_archive---------40-----------------------

看看最常用的操作 Python 字符串的内置方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash 上由 Hitesh Choudhary 拍摄的照片

什么是字符串,什么是字符串方法?

在 Python 中,文本形式的数据被称为字符串。要将数据指定为字符串,文本必须用单引号(')或双引号(" ")括起来。名字,地点,物体,句子,甚至数字都可以是字符串,只要用引号括起来。一旦你有了一个字符串,你就可以使用所谓的“方法”来操作这个字符串。要使用一个方法,您只需编写字符串,后跟。【方法】()。例如,要对字符串“pizza”运行 upper() 方法,只需编写“pizza”即可。upper();如果将“pizza”设置为一个变量,您应该使用 variable.upper()。一些方法接受所谓的“参数”,这些参数放在括号中,进一步定义了该方法将做什么。Python 语言有很多内置的方法,比如 upper() ,允许你轻松地改变字符串。

upper()、lower()、title()和大写()

这些方法都在字符串上执行简单的操作,并且不带参数

upper() 方法将字符串中的每个字母转换成大写:

Syntax: *string*.upper()'pizza'.upper() --> 'PIZZA'

lower() 方法将字符串中的每个字母转换成小写:

Syntax: *string*.lower()'PIZZA'.lower() --> 'pizza'

title() 方法将字符串中每个单词的首字母大写,就像标题一样:

Syntax: *string*.title()'i love to eat pizza'.title() --> 'I Love To Eat Pizza'

**capital()**方法类似于 title()方法;但是,只有字符串中第一个单词的第一个字母大写,就像一个句子:

Syntax: *string*.capitalize()'i love to eat pizza'.capitalize() --> 'I love to eat pizza'

记住,所有这些例子也可以用变量来写:

food = 'pizza'
food.upper() --> 'PIZZA'

拆分()

方法将一个字符串转换成一个列表。该方法可以带两个可选参数。第一个参数是分隔符,它告诉代码如何拆分字符串。默认情况下,字符串在任何空格处被分割,但是如果您选择,您可以决定用任何字符来分割字符串。第二个参数指定要完成的最大拆分次数。默认情况下,该数字设置为-1,即所有事件。

Syntax: *string*.split(*separator, maxsplit*)'I like to eat pizza'.split() --> 
['I', 'like', 'to', 'eat', 'pizza']'I like to eat pizza'.split('e') -->
['I lik', ' to ', 'at pizza']'I like to eat pizza'.split('e', 1) -->
['I lik', ' to eat pizza']

分区()

与 split()类似, partition() 方法按照指定的字符分割字符串。但是,使用这种方法,字符串被分割成一个由三项组成的元组:匹配之前的所有内容、匹配本身和匹配之后的所有内容。通过使用 partition()而不是 split(),您可以保留用来拆分字符串的字符。这个方法使用了*一个必需的参数——*分隔符,它告诉代码你希望如何分割字符串。如果在字符串中没有找到分隔符,仍然返回一个包含三项的元组;但是,它由整个字符串、一个空字符串和另一个空字符串组成。

Syntax: *string*.partition(*value*)'I like to eat pizza'.partition(' to ') 
--> ('I like', ' to ', 'eat pizza')'I like to eat pizza'.partition(' drink ')
--> ('I like to eat pizza', '', '')

加入()

join() 方法用于将 iterable (列表、字典、元组、集合,甚至另一个字符串)中的所有项目连接到一个字符串。该方法使用一个必需的参数,即 iterable。在应用该方法之前使用的字符串被输入到 iterable 中的每一项之间。通常,仅由一个空格(’ “或” ")组成的字符串与 join()方法一起使用,在 iterable 中的单词之间创建空格。

Syntax: *string*.join(*iterable*)' '.join(['I', 'like', 'to', 'eat', 'pizza']) 
--> 'I like to eat pizza''x'.join(['I', 'like', 'to', 'eat', 'pizza'])
--> 'Ixlikextoxeatxpizza''yummy'.join({'food':'Pizza', 'topping': 'pepperoni'})
--> 'foodyummytopping'

替换()

replace() 方法允许你用另一个值替换一个字符串的指定值。这个方法有三个参数,其中前两个是必需的。第一个参数是您希望替换的字符串的值,第二个参数是将取代它的值。第三个参数是一个整数,指定要替换的值的出现次数,默认为所有出现次数。

Syntax: *string*.replace(*oldvalue, newvalue, count*)'I like to eat pizza'.replace('pizza', 'burgers')
--> 'I like to eat burgers''I really really like to eat pizza'.replace('really', 'kind of', 1)
--> 'I kind of really like to eat pizza'

条状()

方法从一个字符串的开头或结尾删除你选择的任何字符。该方法可以带一个可选参数。默认情况下,任何前导空格或尾随空格都将从字符串中删除,但是如果您将所选的任何字符作为参数包含在字符串中,您也可以选择删除这些字符。

Syntax: *string*.strip(*characters*)'   pizza   '.strip() --> 'pizza''..rjq,,pizza.rq,j.r'.strip('rjq.,') --> 'pizza'

startswith()和 endswith()

如果字符串以指定的值开始,则 startswith() 方法返回 True,否则返回 False。endswith() 方法以同样的方式工作,但是使用了字符串的结尾。这些方法有三个参数,第一个是必需的,后两个是可选的。第一个参数是您要查看字符串是否以此开头/结尾的值。第二个参数是一个整数值,指定要从哪个索引开始搜索,第三个参数是要结束搜索的索引的值。

Syntax: *string*.[starts/ends]with(*value, start, end*)'I like to eat pizza'.startswith('I like') --> True'I like to eat pizza'.endswith('drink pizza') --> False'I like to eat pizza'.startswith('to', 7, 18) --> True'I like to eat pizza'.endswith('eat', 7, 18) --> False

计数()

方法告诉你一个指定的值在一个字符串中出现了多少次。这个方法需要三个参数,其中第一个是必需的。第一个参数是要在字符串中搜索的值。第二个和第三个参数分别是希望开始和结束搜索的位置。默认情况下,第二个参数是 0,即字符串的开头,第三个参数是-1,即字符串的结尾。

Syntax: *string*.count(*value, start, end*)'I really really like to eat pizza'.count('really') --> 2'I really really like to eat pizza'.count('really', 8, 20) --> 1

查找()和索引()

find()index() 方法几乎完全相同,因为它们都返回指定值的第一个匹配项的索引(如果给定值是多个字符,则返回指定值的第一个字符的索引)。两者之间的唯一区别是,如果在字符串中没有找到该值,find()方法将返回-1,而如果该值没有出现,index()方法将导致错误。两种方法都有三个参数*,其中第一个是必需的。与 count()方法一样,第一个参数是要在字符串中搜索的值,第二个和第三个参数分别是要开始和结束搜索的位置。默认情况下,第二个参数是 0,即字符串的开头,第三个参数是-1,即字符串的结尾。*

Syntax: *string*.[find/index](*value, start, end*)'I really really like to eat pizza'.find('really') --> 2'I really really like to eat pizza'.index('really') --> 2'I really really like to eat pizza'.find('really', 8, 20) --> 9'I really really like to eat pizza'.index('really', 8, 20) --> 9'I really really like to eat pizza'.find('hamburger') --> -1'I really really like to eat pizza'.index('hamburger') --> ERROR

现在你知道了。使用上述这些方法,您应该能够执行 Python 字符串上的大多数操作。要查看所有可用的字符串方法,请确保查看 w3schools 列表

快乐编码,请务必查看我的博客,下面列出了 Python 方法!

[## Python 列表方法

Python 中最常用列表方法的总结

towardsdatascience.com](/python-list-methods-fa7c53010300)

参考资料:

[## Python 字符串方法

Python 有一组内置的方法,可以用在字符串上。注意:所有的字符串方法都返回新值。他们确实…

www.w3schools.com](https://www.w3schools.com/python/python_ref_string.asp)

Python 字符串

原文:https://towardsdatascience.com/python-strings-38c3d74c236a?source=collection_archive---------26-----------------------

他们比你想象的要多得多

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Aditya WardhanaUnsplash 上拍摄

在 Python 中,字符串似乎是简单的数据类型。但是你知道str.format_map是做什么的吗?还是str.expandtabs?没有吗?好的,str.isidentifier怎么样?

直到最近,我才听说过他们中的任何一个——如果你听说过,公平地说,我印象深刻。

Python 的字符串方法多种多样,有些非常有用,有些则不那么有用。但是它们都有自己独特的用例。我们将看看一些不太常见但仍然有用的特性。

所以,让我们来看看 Python 的字符串方法。

案件卷宗

更激进的版本lower。鉴于lower只适用于 ASCII 字符[A-Z] -> [a-z]casefold试图标准化非标准字符,例如拉丁语或希腊语。

这真的很好用——希腊神话中的奥林匹斯山神赫尔墨斯,在希腊语中被写成ἑρμῆς,在小写中,这是ἑρμῆς.

"Ἑρμῆς".casefold() == "ἑρμῆς".casefold()

**[Out]:** True

相比之下,lower在这点上就失败了。

"Ἑρμῆς".lower() == "ἑρμῆς".lower()

**[Out]:** False

中心

这里,我们在字符串的两边添加填充,使其居中对齐,如下所示:

"hello there".center(20, ".")

[Out]: "....hello there....."

第二个参数是可选的,默认为" "

ljust 和 rjust

center类似,这些函数向字符串添加填充,并分别对其进行左对齐或右对齐。同样,默认参数是" "

"hello there".ljust(20, ".")
"hello there".rjust(20, ".")[Out]: "hello there........."
       ".........hello there"

数数

这让我们可以计算一个模式在一个句子中重复的次数。

"Lets count how many spaces are in this string".count(" ")

**[Out]:** 8

"You cannot end a sentence with because because because is a conjunction.".count("because")

**[Out]:** 3

编码

允许我们指定或改变字符串的编码类型,默认为utf-8。如果字符串包含编码集之外的字符,我们将收到一个UnicodeEncodeError

"ἑρμῆσ".encode('ascii')

**[Out]:** UnicodeEncodeError

我们可以调整错误处理方案的行为——默认为'strict''ignore'会忽略错误,'replace'会替换它们。

"ἑρμῆσ".encode('ascii', 'ignore')

**[Out]:** b''

"ἑρμῆσ".encode('ascii', 'replace')

**[Out]:** b'??????'

扩展表

这将所有制表符替换为空格,默认为八个空格。

print("\tthis is tabbed".replace(" ", "-"))  # without expandtabs
print("\tthis is too"**.expandtabs()**.replace(" ", "-"))  # with**[Out]:** "        this-is-tabbed"
       "--------this-is-too"

格式 _ 地图

类似于format方法,但是允许我们使用字典。例如:

mappings = {'x': 'mapped', 'y': 'values', 'z': 'dictionary'}
print("We have {x} the {y} from the {z}".format_map(mappings))

**[Out]:** "We have mapped the values from the dictionary"

分区和 rpartition

partition类似于split,但是在给定模式的第一个实例上拆分字符串,并且也返回给定模式。rpartition做同样的事情,但是从字符串的右边开始。

"lets split this".split(" ")
"and this too".partition(" ")
"to the right".rpartition(" ")**[Out]:** ['lets', 'split', 'this']
       ('and', ' ', 'this too')
       ('to the', ' ', 'right')

rfind

其中find返回满足给定模式的字符串中第一个字符的索引,rfind做同样的事情,但是从字符串的右边开始。

"l**e**ts search this string".find("e")
"lets s**e**arch this string".rfind("e")**[Out]:** 1
       6

如果没有找到模式,findrfind返回-1

"this string does not contain the pattern".rfind("ABC")**[Out]:** -1

rindex

indexrindex几乎总是以与findrfind相同的方式工作:

"search me".rfind("e")
"search me".rindex("e")**[Out]:** 8
       8

除了模式是而不是的地方。indexrindex将返回一个ValueError:

"another string".rfind("X")
"another string".rindex("X")**[Out]:** -1
       *ValueError: substring not found*

rsplit

split相同,但从右侧开始。这仅在指定了最大分割数时才有所不同,如下所示:

"there are six spaces in this string".split(" ", 3)
"there are six spaces in this string".rsplit(" ", 3)**[Out]:** ['there', 'are', 'six', 'spaces in this string']
       ['there are six spaces', 'in', 'this', 'string']

分割线

也与split相同,但由换行符\n分开。

"""This is a
multi-line\nstring""".splitlines()

**[Out]:** ['This is a', 'multi-line', 'string']

交换情况

交换字符的大小写,也适用于非英语字母。

"CamelCase".swapcase()
"Ἑρμῆς".swapcase()[Out]: 'cAMELcASE'
       'ἑΡΜΗΣ'

翻译

允许我们使用用maketrans方法构建的翻译字典来交换模式。

translate = "".maketrans("e", "3")
"lets translate this string".translate(translate)**[Out]:** 'l3ts translat3 this string'

零填充

用零填充字符串的开头,直到达到给定的长度。如果给定的长度小于字符串的长度,则不进行填充。

"test one".zfill(5)
"two".zfill(5)**[Out]:** 'test one'
       '00two'

格式检查

我们也有许多格式检查方法,它们返回TrueFalse。大多数都是不言自明的,所以我们将保持简短。

伊萨勒姆

字符串是字母数字的,只包含字母和数字的混合字符。

"a1phanum3r1c".isalnum()  # contains no space character

**[Out]:** True

"a1pha num3r1c".isalnum()  # contains a space character

**[Out]:** False

伊萨法

字符串是按字母顺序排列的,只包含字母吗?

"ABC".isalpha()

**[Out]:** True

"A/B/C".isalpha()

**[Out]:** False

伊萨西

字符串是否只包含 128 字符 ASCII 编码标准中的字符?

"Pretty much anything on your English language keyboard! Punctuation included ~#!$%^&*()|\<>,.?/:;@'{}[]-=_+ and numbers too 1234567890".isascii()

**[Out]:** True

"We are not allowed Ἑρμῆς, nor £, €, and ¬".isascii()

**[Out]:** False

isdecimal

这一个在行为上更有趣,也更出乎意料。它识别只包含 Unicode 十进制数字字符的字符串。这并不意味着像3.142这样的十进制数。

在许多不同的脚本中,Unicode 十进制数字字符涵盖了数字本身。例如,它涵盖了0-9,它还涵盖了孟加拉数字三৩,以及藏语数字五༥.

"123".isdecimal()

[Out]: True

"3.142".isdecimal()

[Out]: False

"༥৩".isdecimal()

[Out]: True

Unicode 十进制数字的完整列表可在此处找到。

标识符

这告诉我们这个字符串是否是一个有效的 Python 标识符,这意味着我们可以将它指定为变量、函数、类等的名称。它包括字母、数字和下划线。但是,它不能以数字开头。

"valid_identifier".isidentifier()
"9_is_not_valid".isidentifier()
"CamelCaseIsOkay".isidentifier()
"no spaces".isidentifier()**[Out]:** True
       False
       True
       False

可打印

检查我们的字符串中是否有没有直接打印到控制台的字符,比如换行符\n或制表符\t

"line 1".isprintable()

**[Out]:** True

"line 1\nline 2".isprintable()

**[Out]:** False

isspace

检查字符串是否只包含空格字符(包括换行符\n和制表符\t)。

" \n \t".isspace()

**[Out]:** True

ist title

这个检查每个新单词是否以大写字母开头。它忽略数字和标点符号:

"A Typical Title Of Something".istitle()
"123 Still A Title".istitle()
"IT DOES NOT WORK IF WE SHOUT".istitle()
"But not if we don't capitalize everything".istitle()**[Out]:** True
       True
       False
       False

仅此而已!Python 中字符串方法的数量(至少对我来说)非常惊人。虽然我很难看到zfill的用例(如果你用过,请告诉我),但其余的看起来确实有用。

我希望这篇文章至少向您介绍了一些 Python 的字符串方法。

如果您有任何问题或建议,请随时通过 Twitter 或在下面的评论中联系我们。

感谢阅读!

其他方法

我已经排除了更多的字符串方法,因为它们要么是不言自明的,要么是常识。这些是:

capitalize
endswith
find
format
isdigit
islower
isnumeric
isupper
lower
lstrip
replace
rstrip
strip
startswith

如果您喜欢这篇文章,您可能会喜欢我写的另一篇文章,它讲述了 Python 的四个不太为人所知但却非常有用和有趣的特性:

[## 4 个非常有用的 Python 特性

四个不太知名但非常有用的 Python 功能

towardsdatascience.com](/4-super-useful-python-features-993ae484fbb8)

用 Schrutepy 包进行 Python 文本分析

原文:https://towardsdatascience.com/python-text-analysis-with-the-schrutepy-package-234bc70f3916?source=collection_archive---------13-----------------------

这个新的 python 包让文本分析变得有趣

By: 布拉德·林德布拉德
LinkedIn|Github|博客 | 推特

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

随着 {schrute} R 包的成功,许多请求都是针对移植到 Python 的同一个数据集。 schruteschrutepy 包只有一个目的:从Office加载整个脚本,这样你就可以用这个有趣的数据集执行自然语言处理、文本分析或其他什么。

快速启动

使用 pip 安装软件包:

pip install schrutepy

然后将数据集导入数据框架:

from schrutepy import schrutepy df = schrutepy.load_schrute()

就是这样。现在你准备好了。

长示例

现在,我们将快速学习一些常见的基本文本分析功能。

**from** schrutepy **import** schrutepy
**from** wordcloud **import** WordCloud, STOPWORDS, ImageColorGenerator
**import** matplotlib.pyplot **as** plt
**from** matplotlib.pyplot **import** figure
**import** nltk
**from** nltk.corpus **import** stopwords
**from** PIL **import** Image
**import** numpy **as** np
**import** collections
**import** pandas **as** pd

用 load_schrute 函数加载整个脚本

df = schrutepy.load_schrute()

有些唱片没有对白

df = df.dropna()

为整个系列中的所有文本创建一个单词云

text = " ".join(review for review in df.text)print ("There are {} words in the combination of all review.".format(len(text)))#There are 3001517 words in the combination of all review.# Create stopword list:
nltk.download(**'stopwords'**)
stopWords = **set**(stopwords.words(**'english'**))

# Generate a word cloud image
wordcloud = WordCloud(stopwords=stopWords, background_color=**"white"**).generate(text)

# Display the generated image:
# the matplotlib way:
plt.figure(figsize=[**30**,**15**])
plt.imshow(wordcloud, interpolation=**'bilinear'**)
plt.axis(**"off"**)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们对一些角色做同样的事情。函数会有所帮助。

**def** plotDunder(character, df):
    mydf = df[df.character == character]
    text1 = **" "**.join(review **for** review in mydf.text)
    # Generate a word cloud image
    wordcloud = WordCloud(stopwords=stopWords, background_color=**"white"**).generate(text1)

    # Display the generated image:
    # the matplotlib way:
    plt.figure(figsize=[**15**,**7**])
    plt.imshow(wordcloud, interpolation=**'bilinear'**)
    plt.title(character)
    plt.axis(**"off"**)
    plt.show()fav = [**"Michael"**, **"David Wallace"**, **"Dwight"**, **"Jim"**, **"Pam"**, **"Oscar"**, **"Phyllis"**, **"Creed"**, **"Ryan"**,]for i in fav: 
  plotDunder(i, df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们做一个德怀特大头的形状

dwight_mask = np.array(Image.open("schrutepy.png"))# Create a word cloud image
wc = WordCloud(background_color=**"white"**, max_words=**1000**, mask=dwight_mask,
               stopwords=stopWords, contour_width=**1**, contour_color=**'grey'**)

# Generate a wordcloud
wc.generate(text)

# show
plt.figure(figsize=[**30**,**15**])
plt.imshow(wc, interpolation=**'bilinear'**)
plt.axis(**"off"**)
plt.show()

wc.to_file(**"final_schrute.png"**)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在让我们找出并画出我最喜欢的角色最常用的单词

**def** commonWord(character, df):
    mydf = df[df.character == character]
    text = **" "**.join(review **for** review in mydf.text)
    wordcount = {}
    # To eliminate duplicates, remember to split by punctuation, and use case demiliters.
    **for** word in text.lower().split():
        word = word.replace(**"."**,**""**)
        word = word.replace(**","**,**""**)
        word = word.replace(**":"**,**""**)
        word = word.replace(**"\""**,**""**)
        word = word.replace(**"!"**,**""**)
        word = word.replace(**"“"**,**""**)
        word = word.replace(**"‘"**,**""**)
        word = word.replace(**"*"**,**""**)
        **if** word not in stopWords:
            **if** word not in wordcount:
                wordcount[word] = **1**
            **else**:
                wordcount[word] += **1**

    # Print most common word
    n_print = **int**(**10**)
#     print("\nOK. The {} most common words are as follows\n".format(n_print))
    word_counter = collections.Counter(wordcount)
    **for** word, count in word_counter.most_common(n_print):
        **pass**
    # Close the file
    # Draw a bar chart
    lst = word_counter.most_common(n_print)
    df = pd.DataFrame(lst, columns = [**'Word'**, **'Count'**])
    df.plot.bar(x=**'Word'**,y=**'Count'**, title=character)for i in fav: 
  commonWord(i, df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你喜欢这个包,就在 Github 上开始吧,这样更多的人可以从中得到乐趣。

想要更多这样的内容? 订阅此处

原载于 2020 年 1 月 18 日 https://technistema.com

Python:布尔混淆

原文:https://towardsdatascience.com/python-the-boolean-confusion-f7fc5288f0ce?source=collection_archive---------7-----------------------

if valif val is not None不一样!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Hitesh ChoudharyUnsplash 上拍摄

哇,什么???Python(不)疯狂。

当你做if val is None时,你调用操作员is,它检查x的身份。即if val is value在这里,运算符检查两个操作数是否指向同一个对象。

*None*在 Python 中是单例的,所有的*None*值也是完全相同的实例。

但是…

你说if val,python 的表现就不一样了。如果期望一个布尔值,并且假设val不是布尔值,Python 自动调用val__bool__方法。

if val实际上是作为if val.__bool__执行的

令人困惑的是,bool(None)返回False,所以如果val为 None。这按预期工作,但还有其他值被评估为False.

最重要的例子是空列表。bool([])同样返回False。通常情况下,空单和None有不同的含义;None 表示没有值,而空列表表示零值。语义上,他们是不同的。

例子

为了更好地理解,这里有一些例子。

我们将针对不同的值执行以下条件块:

**if** val:
    print(**'if val'**)**if not** val:
    print(**'if not val'**)**if** val **is not None**:
    print(**'if val is not None'**)**if** val **is None**:
    print(**'if val is None'**)

1。无

val = Noneif not val
if val is None

2。【(空单)

val = []if not val
if val is not None

3。[27,37] (非空列表)

val = [27, 37]if val
if val is not None

4。0 (数字—零)

val = 0if not val
if val is not None

5。1 (数字—1/非零)

val = 1if val
if val is not None

6。一个物体

val = object()if val
if val is not None

很有趣,对吧?试试看!

Python:面向(有抱负的)数据科学家的(非官方)OOP 速成班!

原文:https://towardsdatascience.com/python-the-unofficial-oop-crash-course-for-aspiring-data-scientists-ed2ed3789bcf?source=collection_archive---------7-----------------------

类、属性、方法、继承、封装和所有其他你不确定是否真的需要的晦涩难懂的东西(剧透:为了你的理智,你需要!)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

信用:Pixabay

背景

Python 正经历着市场需求和用户基础的巨大增长;无论您是开发人员、分析师、研究人员还是工程师,python 都有可能在您的领域中得到应用。这么多免费的教育资料(比如*自动化枯燥的东西)进入门槛不能再低了。)*奇怪的是,然而,我们看到了一个不寻常的结果:python 爱好者过早地停滞不前,终止了他们对 python 基础的研究,转而支持特定领域的库和框架学习。对于当今的数据科学文化来说尤其如此;在对字符串、列表和字典有了中等程度的熟悉之后,未来的 python 爱好者可以直接进入 Numpy、Pandas 和 Scikit-Learn(如果不是 Keras、TensorFlow 或 PyTorch 的话)。)

那么应该学习数据结构与算法(DS&A),从零开始实现二叉树或链表吗?开始特定领域的旅程,什么是合适的“我已经学了足够多的 python 基础知识”门槛?没有“一刀切”的答案;然而,我建议在进入回归、分类和聚类等主题之前,至少要熟悉 OOP。

什么是面向对象编程(OOP)?

为了理解 OOP,我们需要简单讨论一下函数式编程;无需深究这种范式,只需说,函数式编程将函数(动作)与数据(信息)分开,而 OOP 认为这是一种错误的二分法。你以前用过 python 的内置列表吗?()想必你已经注意到了append方法允许你在当前最后一个元素之后插入一个元素,自动增加列表的长度?(

恭喜恭喜!你喜欢 OOP。数据类型及其方法(附属于对象的函数)是一个内聚的整体,这是 OOP 的核心“本质”。

在下面的代码片段中,我将定义一两个类,并围绕一个已建立的机器学习任务演示一些基本的 OOP 概念,以便您可以看到 OOP 如何为数据科学家带来好处。我们将使用各种 ML 算法对 Yelp 评论进行分类。事实上,这个类将只接收两个强制参数,数据和您希望使用的模型。(当然还会有其他几种算法),但是,这个类架构将允许我们做以下事情:

(1)将数据分为训练集和测试集,(2)将数据预处理并向量化为 TF-IDF 令牌,(3)训练模型,(4)计算测试集性能的准确性和相关度量,以及(5)通过 pickle 保存模型。

这条管道将大大提高你的效率。和许多其他人一样,我在对基础知识有一个坚实的掌握之前就一头扎进了数据科学的材料中。我会上下滚动笔记本,寻找我之前定义的变量。如果我想比较 2 或 3 个模型的性能,这将成为一个噩梦,确保我引用了适当的变量名。您将会看到,使用下面的方法,比较模型性能将是一项微不足道的任务,并且(如果幸运的话)我将会把您变成一名 OOP 的传道者!

面向对象的情感分析

关于显示问题,见 GitHub 要诀。

GitHub Gist

正如你在上面注意到的,我定义了两个类:DataSplitterClassifier。首先,让我们看看 DataSplitter 稍后我们将访问分类器。

DataSplitter 接收一个 dataframe、文本列的名称和情感列的名称。然后,train_test_split 用于为类分配以下属性:x_train、x_test、y_train 和 y_test。请注意,random_state 和 test_percent 参数有默认值。这意味着——除非您特别更改这些参数中的任何一个,否则两个类实例将具有相同的 x_train、x_test、y_train 和 y_test 属性。这将是有用的,因为我们可以直接比较 ML 模型,而不用担心它们是在(稍微)不同的数据集上训练的。

当 DataSplitter 类对象被实例化时,您可以非常简单地访问这些值:

import pandas as pd
data = pd.read_csv('yelp_samples_500k.csv')
d = data.sample(n=1000)ds = DataSplitter(data=d,x_var='text',y_var='sentiment')
ds.x_test>>>
267157    This place always has a line so I expected to ...
197388    Would give them a zero stars if I could. They ...

如您所见,self关键字将这些属性绑定到对象上。使用点符号,检索这些属性很简单。

继续我们的下一个 OOP 概念:继承!对于这个例子,我们将进入第二个类,分类器。继承仅仅意味着一个类从以前定义的类继承功能。在我们的例子中,分类器将继承 DataSplitter 的所有功能;请注意两点:(1) DataSplitter 在其定义DataSplitter()中没有接收任何要继承的类,而Classifier(DataSplitter) 接收了一个要继承的类。(2)分类器的__init__方法中使用了super关键字。这样做的效果是执行 DataSplitter 的 init 方法,然后继续执行所有其他特定于分类器自己的 init 方法的指令。底线是,我们训练/测试/分割我们的数据,而不需要重新输入所有代码!

在 init 方法之后,你会看到__vectorize。注意定义前面的双下划线。这就是在 python 中实现封装的方式。封装意味着~对象拥有程序员不具备的访问属性和方法。换句话说,为了不分散程序员的注意力,它们被抽象(或封装)了。

from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
c = Classifier(data=d,model_instance=nb,
x_var='text',y_var='sentiment')c.__vectorize('some text')
>>>
AttributeError: 'Classifier' object has no attribute '__vectorize'

换句话说,对象可以访问这些方法,但是,我们不能!

说到方法,如果你没有猜到的话——方法只是内置于类对象中的函数。我们上面定义的方法包括 _ _ 矢量化、_ _ 拟合、_ _ 评估准确性、度量、预测和保存。从向量化开始,我们使用 NLTK 的 word_tokenize 函数将所有单词和标点符号标记为一元语法。接下来,我们使用 NLTK 的 ngrams 函数来创建二元模型和三元模型

'I like dogs' #text
['I', 'like', 'dogs'] #unigrams
['I like', 'like dogs'] #bigrams
['I like dogs'] #trigram 

这种方法大大改进了 unigrams,因为它允许 ML 模型学习“好”和“不好”之间的区别。请注意,我没有删除停用词或标点符号,也没有词干标记。如果你对扩展功能感兴趣,这可能是一个很好的家庭作业!__vectorize 方法被传递给由 __fit 方法创建的管道属性。同样,__fit 方法训练提供给 init 方法的 ML 模型,并创建预测(preds。)下面的方法 __evaluate_accuracy 确定模型的二进制精度,并赋值为一个类属性,以便以后访问(无需多次重新计算。)接下来,我们的度量方法将为我们检索二进制准确性,或者打印分类报告(精度、召回等)。)我们的预测方法简单地产生了这个代码。向方法调用提供文本,要么分配一个类,要么返回属于类 1 的概率。(如果你对多类分类感兴趣,一些调整将是必要的——我将把它作为家庭作业留给你!)最后,save 方法接收一个文件路径并挑选整个对象。这很简单——我们所要做的就是打开 pickled 文件来访问所有的类方法和属性,包括完全训练好的模型!

from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
nb_model = Classifier(data=data,model_instance=nb
,x_var='text',y_var='sentiment')nb_model.metrics()
>>>
'92.77733333333333 percent accurate'

让我们将它与随机森林分类器进行比较!

from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier()
rf_model = Classifier(data=data,model_instance=rf,
x_var='text',y_var='sentiment')rf_model.metrics()
>>>
'86.29666666666667 percent accurate'

似乎我们的朴素贝叶斯模型优于我们的随机森林分类器。保存我们的对象(并再次打开它以备后用)非常简单:

## saving
nb_model.save('nb_model') #will append .pkl to end of input## opening for later use
with open('nb_model.pkl','rb') as f:
    loaded_model = pickle.load(f)loaded_model.predict("This tutorial was super awesome!",prob=True)
>>>
0.943261472480177 # 94% certain of positive sentiment

我希望你喜欢这个教程;我的目标是——简洁、信息丰富、实用。为了满足所有这三个目标,一些 OOP 主题没有入选(例如,多态性)。)如果您觉得这有帮助,请发表评论。同样,如果你想让我探索类似的概念,请发表评论,我会看看是否能在未来的文章中有所体现。

感谢您的阅读——如果您认为我的内容没问题,请订阅!😃

给初学者的 10 个有用的 Python 技巧和窍门

原文:https://towardsdatascience.com/python-tips-and-tricks-for-beginners-62473d569d0a?source=collection_archive---------24-----------------------

有了实际例子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:像素

在这篇文章中,我们想和你分享 10 个对初学者有用的 Python 技巧和窍门。

Python 是数据科学家最需要的技能之一。除了为初学者提供免费的 Python 课程之外,我们还总结了这 10 个提示和技巧,应该可以帮助你完成日常的数据科学任务。

通过本初学者教程,您将学会如何:

  • 格式化字符串
  • 使用枚举、排序函数
  • 从函数中返回多个值
  • 使用 lambda 表达式,列出理解
  • 更多!

如果你想让你的 Python 编码更高效,不要错过这些技巧/窍门!

我们开始吧。

提示#1:显示方法/功能

Python 如此强大,有许多不同的方法和函数。对于初学者来说,要记住所有内容尤其困难。

我们如何找出 Python 对象的可用方法/函数?

针对初学者的第一个 Python 技巧是关于两种快速实现这一点的方法。

方法 1:代码完成特性

许多 ide(集成开发环境)或 Python 的代码编辑应用程序可以在您键入时自动完成代码。这个特性有助于加速编程。

例如,在 Jupyter Notebook 中,你可以输入一个函数/文件的前几个字符,等等。,然后按下标签的键填写剩余的项目。下面的屏幕截图显示了以字母“p”开头的可用自动完成选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

方法 2: dir 函数

dir 函数在其参数中返回对象的有效属性列表,这意味着我们可以用它来返回对象的方法。

例如,让我们运行下面的 Python 代码,将 dir 应用于 string 对象。

这将返回一长串名字。

忽略列表开头带’ __ '的那些特殊方法,可以找到一些有趣的方法,比如大写、查找、lower。

['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

注意 : [dir](https://docs.python.org/3/library/functions.html#dir)只提供了一组有趣的名字,而不是完整的名单。但是当你不能回忆起一个你意识到的方法时,使用起来很方便。
除了 dir,还可以试试帮助功能。例如,help(str)将打印出关于 string 对象的帮助页面,其中包含了比 dir 更多的方法细节。

技巧#2:格式化字符串

打印字符串是数据科学项目中的一项常见任务。str 的 format 方法可以把多个变量和字符串拼凑在一起,用特定的方式格式化。

让我们看一个例子。

我们将定义三个变量价格已付变更(=已付—价格)。如果我们想打印出一个包含这些变量的完整句子,格式为美元呢?

我们可以使用下面的格式方法。

The item cost $11.29\. I paid $20.00\. I received $8.71 in change

技巧 3:枚举函数

当迭代一个对象,比如一个列表、字典或文件时, enumerate 是一个有用的函数。该函数返回一个元组,其中包含通过迭代对象获得的值和循环计数器(从 0 的起始位置开始)。当您想根据索引编写代码时,循环计数器尤其方便。

让我们看一个例子,我们可以为第一个和最后一个元素做一些特殊的事情。

我们用 enumerate 方便地打印了指示第一个和最后一个元素的字符串。

0: J
The first element!
1: u
2: s
3: t
4:  
5: I
6: n
7: t
8: o
9:  
10: D
11: a
12: t
13: a
The last element!

枚举功能也可以用于文件。

在下面的例子中,我们可以在跳出循环之前打印出 csv 文件的前 10 行。由于结果太长,我们就不在这里复制了。但是你可以在你所有的文件上试试。

技巧 4:在一个函数中返回多个值

在定义函数时,我们经常希望返回多个值。在这个 Python 技巧/窍门中,我们将在下面介绍三种常见的方法。

方法 1:返回一个元组

首先,我们来看看最方便的方法:返回一个元组。我们通常只在有 2 或 3 个值要返回时使用这种方法。当值的数量更多时,很容易忘记元组中值的顺序。

下面是一个示例函数 get_employee,它根据雇员的 ID 号,以元组的形式返回雇员的名和姓。

如果我们调用值为 0 的函数,您可以看到该函数返回具有两个值的元组:“Jane”和“Doe”。

first_name: Jane, last_name: Doe

这很好,但是当有更多的值要返回时,我们该怎么办呢?

让我们继续下一个方法。

方法 2:返回一个字典

第二种方法是返回字典。字典可以被认为是键:值对,所以我们可以命名返回的值,这比元组更清楚。

下面的例子与上一个相似。但是我们要求函数返回一个字典。

我们可以调用 id_num = 0 的函数。有了作为字典的结果,用它的键调用特定的值就更容易了。

first_name: Jane,
last_name: Doe,
title: Data Scientist,
department: A,
date_joined: 20190808

方法 3:返回一个命名的元组

我们讨论的最后一种方法是返回一个命名的元组。命名元组是具有命名字段的元组。它们像元组一样是不可变的,但也像字典一样提供命名。

命名元组为元组中的每个位置赋予意义,并允许更具可读性、自文档化的代码。它们可以在使用正则元组的任何地方使用,并且它们增加了通过名称而不是位置索引来访问字段的能力。

Python 文档

与字典相比,命名元组的主要优势是字段保证在对象中。对于字典,我们不确定是否所有的键:值对都在那里。

让我们看一个命名元组的例子。

我们必须在使用 namedtuple 对象之前定义它。在下面的代码中,我们创建了一个名为雇员的 namedtuple 对象,然后用它来保存值。

我们可以再次调用 id_num = 0 的函数来返回命名元组。

first_name: Jane,
last_name: Doe,
title: Data Scientist,
department: A,
date_joined: 20190808

我们还可以仔细检查返回对象的变量类型,即前面定义的 Employee namedtuple。

__main__.Employee

技巧 5: Lambda 表达式

λ表达式用于创建匿名函数,通常是单行的。

下面的例子展示了 lambda 如何缩短创建简单函数的代码。

下面两种方法返回相同的结果。

0     first
1    second
2     third
3     first
4     third
5     first
Name: address, dtype: object

技巧 6:排序函数

在这篇 Python 技巧文章中,我们将介绍有用的排序函数,以及列表和字典的例子。这是一项常见的任务,因为我们经常希望看到数据集中的顶部/底部值。

排序列表

让我们看一个使用 sorted 函数的列表的简单例子。

[1, 3, 5, 5, 8, 9]

注意:还有 list.sort()方法,但是我们更喜欢 sorted,因为它更通用并且创建一个新的列表。参见 Python 文档中更详细的比较。

分类词典

对于字典,排序稍微复杂一些,因为有键和值。

我们可以将 sorted 函数直接应用于字典,它将对字典的键进行排序。

['A', 'B', 'G', 'Q', 'T']

或者将字典的值排序如下。

[0, 3, 7, 8, 9]

或者按照下面 Python 代码中的键或值对整个字典进行排序。

{'A': 9, 'B': 8, 'G': 0, 'Q': 7, 'T': 3}
{'G': 0, 'T': 3, 'Q': 7, 'B': 8, 'A': 9}

技巧 7:条件表达式

如果你学过 Python 的基础知识,你应该熟悉 if-else 语句。当逻辑简单时,我们也可以在一行中使用条件表达式(或者三元运算符)。

让我们看一个基于下面布尔变量 is_raining 的例子。

下面的 Python 代码展示了这样做的传统方式。

Stay at home

然而,我们也可以使用下面的表达式。短多了!

表达式*x if C else y*首先计算条件,C 而不是 x,如果 C 为真,则计算 x 并返回其值;否则,计算 y 并返回其值。

Python 文档

技巧 8:列出理解

我们可以使用列表理解来创建列表,这比传统的方法要简洁得多。当新列表中的每个元素都是对另一个 iterable 对象的元素的一些操作的结果时,通常会使用它。

列表理解由括号组成,括号包含一个表达式,后跟一个*for*子句,然后是零个或多个*for**if*子句。结果将是一个新的列表,该列表是通过在表达式后面的*for**if*子句的上下文中评估该表达式而得到的。

Python 文档

这个例子展示了如何使用它来计算字符串中单词的长度,并将结果作为一个列表。

下面两种方法返回相同的结果,而列表理解代码要短得多。

[3, 3, 3, 3, 6, 2, 3, 3, 3, 2, 5, 2, 2, 3, 2, 3, 5, 3, 4, 5, 5, 3, 4, 1, 3, 5, 4, 6, 2, 3, 6, 2, 4, 3, 1, 5, 4, 1, 4, 2, 3, 9, 2, 4, 3, 3, 2, 2, 3, 3, 3, 4, 2, 4, 5, 2, 2, 3, 2, 3, 6, 2, 3, 7, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 4, 4, 4, 3, 2, 3, 3, 4, 3, 3, 3, 6, 4]

技巧 9:所有/任何功能

我们还想涵盖 Python 中的所有任何函数。在进行多重比较时,它们很方便。

如果 iterable 对象的任何元素为 true,则 any 函数返回 True。下面的例子显示了它如何使编码更简单。

Toronto, Ontario

同样,如果 iterable 对象的所有元素都为 true(或者 iterable 为空),all 函数返回 True。下面是一个比较 all 函数和常用方法的例子。

Just Into Data

技巧#10:使用虚拟环境

如果您同时从事多个数据科学项目,学习和使用虚拟环境至关重要。

Python 的虚拟环境有哪些?

虚拟环境是一种 Python 环境,其中安装的 Python 解释器、库和脚本与其他虚拟环境中安装的解释器、库和脚本以及(默认情况下)安装在“系统”Python(即作为操作系统的一部分安装的系统)中的任何库相隔离。

Python 文档

可以使用 Anaconda(康达环境)virtualenvpipenv 等工具创建和管理虚拟环境。

虚拟环境允许每个项目使用不同的 Python 环境,因此我们可以使用不同版本的 Python 和/或不同的库。

例如,假设我们使用 plotly 版本 3 在项目中创建图表。几个月后,plotly 版本 4 推出了新功能。由于该项目的代码在生产中运行良好,我们可以继续使用 Plotly 版本 3。但是对于任何新项目,我们希望使用 Plotly 版本 4 中的新功能。

在这种情况下,我们可以分别使用 plotly v3 和 v4 创建两个虚拟环境,并将它们用于旧项目和新项目。

问题解决了!

就是这样!希望这些 Python 提示和技巧对初学者有用。

你想先试试这篇文章中的哪个技巧?

请留下您的任何问题或任何其他问题的评论。

相关资源:

对于 Python 初学者,请查看我们的 pandas 和 numpy 教程继续学习:

[## 学习 Python 熊猫数据科学:快速教程-数据入门

这是一本帮助你快速学习和使用 Python 熊猫进行数据科学、机器学习的指南。熊猫是最…

www.justintodata.com](https://www.justintodata.com/learn-python-pandas-for-data-science-tutorial/) [## Python NumPy 教程:数据科学实用基础——深入数据

在本 Python 教程中,我们将向您展示数据科学和机器学习的 NumPy 基础知识。NumPy 是…

www.justintodata.com](https://www.justintodata.com/python-numpy-tutorial-basics-for-data-science/)

或者查看我们最近为初学者撰写的其他数据科学文章:

[## 成功的数据科学管道的 7 个步骤——直接进入数据

在本指南中,我们将讨论在实践中构建数据科学管道的步骤。数据科学有助于…

www.justintodata.com](https://www.justintodata.com/data-science-pipeline-steps/) [## 初学者的机器学习:算法类型概述——数据

在这个初学者教程中,我们将解释机器学习算法的类型和一些流行的算法。机器…

www.justintodata.com](https://www.justintodata.com/machine-learning-algorithm-types-for-beginners-overview/)

要获得更多有用的数据科学文章,注册我们的简讯

从 Excel 过渡到 Python 的技巧

原文:https://towardsdatascience.com/python-tips-for-someone-transiting-from-excel-ce16c5f9cbac?source=collection_archive---------40-----------------------

关于提高生产率的最佳做法的讨论

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

米卡·鲍梅斯特在 Unsplash 上的照片

Excel 是最常用的数据分析应用程序之一。然而,由于其明显的局限性(即性能、行和列的限制),它可能不足以应付现代的需求。Python 狂热者经常推荐使用 pandas 库作为 Excel 的替代品来自动化/加速数据分析。然而,如果不熟悉这个库和一些最佳实践,它不一定能节省时间。本文旨在强调使用 Excel 进行数据分析的一些挑战,以及使用 python(和 pandas 库,以及一些附加库)和采用最佳实践如何有助于提高整体效率。假设有一些 python 和熊猫的基础知识。

典型的数据分析师可能夹在业务职能部门和应用程序所有者之间。这种职责分离的结果是,可能没有一个人会理解数据的所有用例。热心的数据分析师有责任对数据进行切片和切块,形成基于输入的假设,并寻找反例来反驳假设。这种递归过程需要数据分析师手动重复过滤、排序、分组、连接、透视、vlookup、拆分 Excel 上的数据。这些步骤可能会导致人工错误,特别是当操作没有往返时(即结果取决于操作的顺序)。解决这个问题的关键是从根本上改变方法:不要机械地操纵数据来准备输出,而应该进行战略性的思考,并准备一个生成输出的程序/脚本。对我来说,这是使用 python 的最大动机,因为重复一系列动作的纯手工和令人麻木的任务不适合我,基于 Excel 的宏太慢了。

这篇文档/文章涵盖了一些有用的想法,通过使用 python,特别是 pandas 库,人们也许可以利用这些想法来节省一些时间并潜在地避免重复工作。

一些警告

在以下情况下,使用 pandas 几乎没有什么价值:
(a)数据量相当小(少于 50000 行),
(b)涉及的文件非常少(少于 10 个),
©为将来使用而准备的输出数据不太可能频繁重复或手动重复。

在这些情况下,Excel 将是首选工具,这取决于您对 python 和 pandas 的熟悉程度。

Python 和 pandas 的图形用户界面非常有限,因此大多数人可能会发现,与 Excel 相比,它的使用不够直观。例如,重新排序列和查找值是否存在这样的琐碎操作在 Excel 中是微不足道的,但是这些操作需要 python 上的几行代码,并且对于第一次接触 python 和 pandas 的初学者来说不那么直观。

在 ide 上,文本编辑器…

虽然有一些不错的工具(PyCharm 和 Jupyter 笔记本)可用,但是在我参与的项目中,这些工具是不可用的或者不可行的(工具是可用的,但是没有足够的 RAM 来使用它)。因此,我经常只使用命令提示符或 Powershell 来运行代码。任何带语法高亮的文本编辑器都可以,我用的是 Notepad++。

1.一次读文件,泡菜,以后读泡菜。

虽然这听起来微不足道,但数据分析师的首要任务是打开并读取数据文件。pandas 将 Excel 文件作为数据帧读取所花费的时间比 Excel 打开相同的 Excel 文件所花费的时间要长。当文件很大(尤其是 Excel 文件)时,将数据文件作为数据帧读取可能需要几分钟时间。如果每次执行脚本时都需要读取数据集,那么执行和编辑脚本的重复过程将大大降低效率。克服瓶颈的方法是读取数据并将其作为 pickle 写入(即.pkl)。读泡菜快 100 倍左右。通过获取数据样本(例如大约 10,000 行)并将其作为 pickle 写入,可以进一步提高效率。还应注意,读取平面文件(.csv和带分隔符的文本文件)比读取 excel 文件快得多,因此,如果可能,应检索/请求此类平面文件格式的文件,假设这些数据文件不打算由用户在 Excel 中打开。

2.规划好功能和代码结构

每个开发人员在开始一个全新的项目时都会说:“这一次,我会把事情做好。”。

在每个项目的开始,自然倾向于编写硬编码脚本来快速生成必要的报告。在这个阶段,可能会有一个单独的.py文件,它有一个巨大的功能,可以创建一个单独的报告。抵制匆忙生成输出报告的冲动,因为长函数很难维护,而且技术债务积累得非常快。

因为可读性很重要,所以每个函数在逻辑上应该代表一个预期的操作。下面的示例显示了读取、清理、修改数据以及将两列相乘以在另一列中给出结果的推荐方法。

示例 1.1(推荐):

def read_trade_data():
   return pd.read_excel('data.xlsx')def clean_trade_data(df):
    # PRICE turns out to be text with comma as decimals point.
    df['PRICE'] = df['PRICE'].str.replace({",", "."})
                             .astype('float64')
    return dfdef add_col_total(df):
    df['TOTAL'] = df['QTY']*df['PRICE']
    return dfdef df_output():
    df = read_trade_data()
    df1 = clean_trade_data(df)
    df2 = add_col_total(df1)
    return df2

示例 1.2

def df_output():
    df = pd.read_excel('data.xlsx')
    df['PRICE'] = df['PRICE'].str.replace({",","."})
                             .astype('float64')
    df['TOTAL'] = df['QTY']*df['PRICE']
    return df

虽然示例 1.1 看起来更冗长,但有几个好处。由于这种分离,df_output在 1.1 中可读性更好,因为在读取修改数据的代码之前,不必通读所有代码来清理数据。此外,如果期望其他数据帧具有类似的十进制格式,可以重用 1.1 中的clean_trade_data函数。另一方面,在 1.2 中,人们可能会求助于复制和粘贴代码。此外,如果在df_output上发生错误,在 python shell 中调试 1.1 的小函数会更容易。

应使用可选参数和关键字参数为数据分析师提供灵活性;应该避免执行类似操作的小函数。

如果预期只有一个版本的data.xlsx,这就足够了:

def read_trade_data():
    return pd.read_excel('data.xlsx')

然而,如果有多个版本的data.xlsx可能需要单独分析,那么编写一个函数来从命令行快速读取这些文件而不是重新编译代码是有意义的。

例 2.1(反例):

def read_trade_data1():
    return pd.read_excel('data1.xlsx')

将会有许多这样的函数,每个映射到不同的文件(例如data2.xlsxdata3.xlsx、…),随着时间的推移,它会变得非常混乱。

示例 2.2(推荐):

def read_trade_data(file=None):
    d_file = {1: 'data.xlsx',
              2: 'data1.xlsx'}
    file = file if file else d_file[max(d_files.keys())]
    return pd.read_excel(file)

例 2.2 有几个优点:
(a)所有文件都在同一个字典里(可读性很重要!),
(b)如果没有任何东西作为文件参数传递,它读取最新的dataN.xlsx
©如果文件没有被添加到files字典,它允许用户显式地传递文件的路径。

许多编码教程都包含类似于示例 2.1 的代码,因为教程的上下文可能不支持使用推荐的最佳实践。

这些功能中的一些可以被做得足够通用,以至于它可以被应用于其他项目。例如,输出数据摘要(即每列唯一值的数量)并打印一小份数据样本通常非常有用。这样的函数应该作为 dataframe 类的方法编写(这样它就可以作为方法 df.summarize()而不是 mymodule.summarize(df)被调用)。此外,如果这样的函数一般适用于任何数据集,那么应该将它重构到一个单独的 python 文件中,并导入到主项目文件的名称空间中。

下面是我的工具箱中的一个函数(pypo.py)。

有时在 Excel 中查看和执行分析会更快。但是导航到文件然后双击它会很麻烦。该功能通过在 Excel 文件被写入后打开该文件来升级to_excel()方法。

#pypo.pyfrom pandas.core.base import PandasObjectdef to_excelp(df, *arg, **kw):

    def xlopen(path):
        import win32com.client as w32
        from pywintypes import com_error
        import os #Opens the file (.csv, .xls, .xlsx) in Excel
        xl = w32.Dispatch('Excel.Application') try:
            wb = xl.Workbooks.Open(path)
        except com_error:
            print('Check if file exists in current working directory…', end='')
            if path in os.listdir():
                print('found!')
                path = '{}\{}'.format(os.getcwd(), path)
                wb = xl.Workbooks.Open(path)
            else:
                print('not found! Please check file path!')
        else:
            pass
        finally:
            xl.Visible = True
        return path, xl, wb

    df.to_excel(*arg, **kw)
    path, xl, wb = xlopen(arg[0])
    return path, xl, wbPandasObject.to_excelp = to_excelp

将它添加到主工作文件的名称空间中:

#main.pysys.path.insert(1, 'C:/Documents/pyprojects/pypo.py')
import pypo

在命令行界面中编写脚本时,可以简单地键入df.to_excelp('test.xlsx')来将数据帧写成 Excel 文件,该文件将在编写后打开。该函数还返回 Excel 应用程序xl和工作簿wb对象,可以在以后使用(也许是为了在 MsExcel 中自动格式化和创建表格?).

评估器可用于扩展 python,虽然这些可以简化pypo.py中的代码,但会导致主文件中的语法稍微冗长一些(例如df.myfunc.to_excel())。回想一下“平的比嵌套的好”。

3.过滤和选择数据

直观的方法是编写在过滤和/或选择相关行或列后返回数据帧的函数。然而,追加或连接这些数据帧是缓慢的。目前发现的最佳实践是编写返回布尔掩码的函数。组合其他掩码可以使用二进制操作完成,获得行数将成为 simpler⁴,尽管不太直观。

示例 3.1:返回数据帧

# Returns a dataframe
def apples(df):
    return df[df['Fruits']=='Apples']df_apples = apples(df)

如果不需要进一步的转换(如合并、排序、过滤),直观的方法会更快。

示例 3.2:返回布尔掩码

def select_apples(df)
    return df['Fruits']=='Apples'mask_apples = select_apples(df)

获取苹果的行数:sum(mask_apples)
获取包含苹果的数据帧:df[mask_apples]

这种方法避免了数据帧的设置成本,直到它真正需要时。使用布尔掩码的操作比数据帧上的操作快得多。

4.使最佳化

尽可能避免在数据帧的行或列中显式循环;这就是熊猫的全部意义。在大多数情况下,np.wherenp.selectnp.cutnp.vectorizedf.apply应该可以做到。其中一些方法本质上仍然是循环,但通常比显式循环快。

5.避免在 Excel 中使用 vlookups,而是合并表格

Excel 的 vlookup 函数从来不是用来合并两个表格的。Quoting docs.microsoftvlookup “在第一列中搜索,并从表数组中的另一列返回同一行中的值”。当表数组的第一列包含多个查找值时,将使用找到的第一个值的行号。与查找值匹配的后续值将被忽略。因此,使用pandas.merge来代替,并处理重复条目(如果有的话)。如果首选 vlookup ,确保查找值是唯一的。

Vlookup 看表的右边;“向左看”需要结合使用 choose() 和数组公式,如果不熟悉数组公式的行为,这很容易出错。有些人可能会通过插入一个辅助(重复)列来避免“向左看”,这会引入某种形式的冗余。

这篇文章的动机是整合作者在各种项目中的学习,以便读者在工作中处理大量数据时不必经历类似的痛苦。在撰写本文时,互联网上有大量关于数据科学、大数据等方面的信息。然而,在实现用于数据分析的开源框架时,几乎没有关于最佳项目实践的指导。

[1]在某种程度上,这不是一个公平的比较,因为 Excel 文件被设计为在 MsExcel 中打开,pandas 在幕后做了很多神奇的事情,将数据准备为 dataframe。

[2]从 12 个 excel 文件中读取 1 张需要 30 分钟。总共 170 万行。读取泡菜当量需要 15 秒。

[3]如果你对此一笑置之,是因为你理解或看到了这样的恐怖,那很好。如果你想知道这有什么问题,请继续阅读。

[4] sum(mask),因为True值在 python 中被求值为 1。

Python 交易工具箱:回溯测试的温和介绍

原文:https://towardsdatascience.com/python-trading-toolbox-05-backtesting-84266edb1d59?source=collection_archive---------8-----------------------

交易工具箱

从头开始测试交易策略

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由米卡·鲍梅斯特Unsplash 上拍摄

我们通过引入一些基于价格的指标开始了这个系列。我们的目标是使用指标、价格和交易量来做出投资决策:选择何时买入或卖出金融资产。在我们的投资决策过程中,我们可以用不同的方法来整合价格、交易量和指标。第一种,也是最传统的一种,是以任意的方式解释他们的模式,就像技术分析的追随者所做的那样。指标也可以在一个更量化的方法中使用,作为交易系统的组成部分,消除投资过程中的人为判断。算法交易尤其是一种基于交易策略的方法,这种方法在没有人工干预的情况下自行建立金融工具的头寸。我们还可以使用价格、交易量和指标作为更复杂的机器学习模型的一部分来进行投资决策。

一个明显的免责声明:这个帖子的内容仅用于教育目的。这里的所有例子都是作为学习练习提出的,它们绝不应该作为投资建议。

无论我们选择以何种方式使用我们的指标,我们都需要回答一个重要的问题:我们的指标或指标组合对我们的投资决策有多好?换句话说,使用任何指标会比根本不使用它们产生更好的结果吗?

可以帮助我们回答这个问题的过程被称为 回溯测试 。通过回溯测试,我们将交易或投资策略应用于历史数据,以生成假设的结果。然后,我们可以分析这些结果,以评估我们战略的盈利能力和风险。

这个过程有其自身的缺陷:不能保证在历史数据上表现良好的策略在现实交易中也会表现良好。真实的交易涉及很多因素,这些因素无法用历史数据来模拟或测试。此外,由于金融市场持续快速发展,未来可能会出现历史数据中没有的模式。然而,如果一个策略不能在回溯测试中证明自己是有效的,它很可能永远不会在真实交易中发挥作用。回溯测试至少可以帮助我们剔除那些没有价值的策略。

几个框架使得使用 Python 回溯测试交易策略变得很容易。两个流行的例子是Backtrader 。像 ZiplineBacktrader 这样的框架包含了设计、测试和实现算法交易策略所需的所有工具。他们甚至可以自动将真实订单提交给执行经纪人。

**在这篇文章中,我们采用了一种不同的方法:我们想研究如何使用 Python、 pandas、和 NumPy 作为我们仅有的工具,从头开始构建和测试一个交易系统。我们为什么要这么做?首先,从头开始构建回溯测试是一个很好的练习,有助于详细理解策略是如何工作的。此外,我们可能会发现自己需要实现现有框架中没有的解决方案。或者,您可能想要开始创建自己的回溯测试框架的旅程!

回溯测试我们的第一个系统

我们可以使用 Python 和 NumPy 以及 pandas 创建一个基本的回溯测试。举个例子,我们将使用在纽约证券交易所交易的金宝汤公司股票的价格。我从雅虎下载了五年的交易历史。财务:文件在这里有。

我们首先设置我们的环境,并将价格系列加载到数据框中:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pd.plotting.register_matplotlib_converters()# This is needed if you're using Jupyter to visualize charts:
%matplotlib inlinedatafile = 'data/CPB.csv'
data = pd.read_csv(datafile, index_col = 'Date')
# Converting the dates from string to datetime format:
data.index = pd.to_datetime(data.index)data

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原始数据帧

基本策略

在我们的例子中,我们将测试一个基本的移动平均线交叉系统**,该系统基于每日收盘价的 20 天指数移动平均线(EMA)和 200 天简单移动平均线(SMA)(在本例中使用调整收盘价)。只要 20 日均线从下方穿过 200 日均线,我们就会买入该股(持有多头仓位)。**

我们将带有移动平均线的列添加到数据框中:

df = data.copy()sma_span = 200
ema_span = 20df['sma200'] = df['Adj Close'].rolling(sma_span).mean()
df['ema20'] = df['Adj Close'].ewm(span=ema_span).mean()df.round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

增加了 sma200 和 ema20

正如我们所看到的,通过使用 200 天的 SMA,我们在相应列的前 199 行中获得了 NaN 值。这只是一个练习,我们可以删除这些行来执行回溯测试。在实际操作中,我们可以考虑使用不同的指标来避免丢失大量数据。清除 NaN 值:

df.dropna(inplace=True)df.round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

移除了 NaN 行

让我们看看图表中的数据:

plot_system1(df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

移动平均价格

为了跟踪我们在数据框中的头寸,我们添加了一列,每一行都包含有多头头寸时的数字 1 和没有头寸时的数字 0 :

# Our trading condition:
long_positions = np.where(df['ema20'] > df['sma200'], 1, 0)
df['Position'] = long_positionsdf.round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加了位置列

无论我们试图实现什么规则,检查我们的信号是一个好主意以确保一切按预期工作。讨厌的错误喜欢隐藏在这种计算中:开始测试一个系统,然后发现我们没有正确地实现我们的规则,这太容易了。特别是,我们需要警惕引入任何形式的前瞻偏差**:当我们在交易规则中包含在规则评估时实际不可用的数据时,就会出现这种情况。如果系统回溯测试产生的结果好得令人难以置信,那么前瞻偏差是最有可能的罪魁祸首。**

我们可以通过检查数据框中的数字变量并在图表上绘制信号来检查信号。

要选择触发交易信号的日期:

buy_signals = (df['Position'] == 1) & (df['Position'].shift(1) == 0)df.loc[buy_signals].round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

信号被触发时的行

在这种情况下,我们只有三个信号。为了确保我们正确应用交叉交易规则,我们可以在选择中包括信号之前的日子:

buy_signals_prev = (df['Position'].shift(-1) == 1) & (df['Position'] == 0)df.loc[buy_signals | buy_signals_prev].round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

包括信号触发前的几天

到目前为止,一切看起来都很好:在信号出现之前的日子里,ema20sma200下方,在信号出现的日子里,它在上方交叉。我们可以对退出我们头寸的信号进行类似的检查:我把这个练习留给你。

我们可以在图表上标出信号的标记:

plot_system1_sig(df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带信号标记的图表

从图表中,我们可以看到,买和卖的信号是不匹配的。第一个信号是卖出(没有买入),因为我们从系列开始时的多头头寸开始。最后一个信号是买入(没有卖出),因为我们在系列结束时保持多头头寸。

战略回报

我们现在可以用初始投资的百分比来计算我们策略的回报,并将其与买入并持有策略的回报进行比较,后者只是在期初买入我们的股票,并一直持有到期末。

我们将用来计算回报的价格序列是调整收盘价格**:通过使用调整后的价格,我们可以确保在我们的计算中考虑到股息、股票分割和其他公司行为对回报的影响。**

# The returns of the Buy and Hold strategy:
df['Hold'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1))# The returns of the Moving Average strategy:
df['Strategy'] = df['Position'].shift(1) * df['Hold']# We need to get rid of the NaN generated in the first row:
df.dropna(inplace=True)df

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加了返回列

整个周期的回报只是每日对数回报的总和(我将在后面解释数学原理):

returns = np.exp(df[['Hold', 'Strategy']].sum()) - 1print(f"Buy and hold return: {round(returns['Hold']*100,2)}%")
print(f"Strategy return: {round(returns['Strategy']*100,2)}%")

输出:

Buy and hold return: -5.83%
Strategy return: 10.3%

这些回报涉及 1060 天的时间。如果我们想将它们与其他时期的回报进行比较,我们需要将它们按年计算**😗*

n_days = len(df)# Assuming 252 trading days in a year:
ann_returns = 252 / n_days * returnsprint(f"Buy and hold annualized return: {round(ann_returns['Hold']*100,2)}%")print(f"Strategy annualized return:{round(ann_returns['Strategy']*100,2)}%")

输出:

Buy and hold annualized return: -1.39%
Strategy annualized return: 2.45%

除非你熟悉对数回报,否则你可能想知道为什么以及如何在回报计算中使用对数**。这里有一点数学来解释这一点,如果你听起来很陌生的话。否则,请随意跳到下一部分。**

在定量金融学中,使用对数来计算回报是很常见的:它们使得一些计算更容易处理。如果日收益率 R_t 定义为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 P_t 是𝑡日的价格,对数收益𝑟_𝑡定义为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过应用一些基本代数,可以将每日日志回报计算为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为什么对数回归如此方便?如果我们有一系列的日收益,我们需要计算整个周期的收益,用对数收益我们可以把它们加起来。相比之下,对于定期回报,我们需要一个乘法:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 T 是我们考虑的时间段的天数。计算年化回报率也变得更加容易。

更复杂的策略

我们刚刚测试的策略只有两种可能的头寸:我们要么多头(持有股票)要么空头(仅持有现金)。尝试和测试一种增加空头头寸可能性的策略(卖出借入的股票,并在退出头寸时买回)会很有趣。为了建立这个策略的例子,我们包括两个简单的移动平均线,一个是日高点,一个是日低点。我们还添加了 15 天指数移动平均线。我们根据以下规则建立头寸:

  • 当均线高于较高的均线时(加上 2%的偏移),我们做多(买入)
  • 当均线低于较低的均线时(减去 2%的偏移),我们做空(卖空)
  • 在所有其他情况下(均线和均线之间),我们不参与市场

我将失调添加到 SMAs 中,以减少错误信号的数量。让我们准备一个新的数据框:

df2 = data.copy()sma_span = 40
ema_span = 15df2['H_sma'] = df2['High'].rolling(sma_span).mean()
df2['L_sma'] = df2['Low'].rolling(sma_span).mean()
df2['C_ema'] = df2['Close'].ewm(span=ema_span).mean()df2.dropna(inplace=True)df2.round(3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加移动平均线

在这里,除了收盘价之外,我们还利用了最高价和最低价。为了在图表上绘制这些值,使用烛台**** 是个好主意。为此,我们将使用 mplfinance 库。如果您还没有这样做,您可以使用以下命令轻松安装 mplfinance :

pip install --upgrade mplfinance

为了将烛台图表与我们现有的样式相结合,我将应用 外部轴方法mplfinance :

**plot_system2(df2)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带移动平均线的蜡烛图

我们可以更详细地检查任何特定的日期范围:

**plot_system2(df2['2019-07-01':'2019-12-31'])**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

日期范围详细信息

然后,我们应用我们的交易规则并添加头寸列:

**offset = 0.02
long_positions = np.where(df2['C_ema'] > df2['H_sma']*(1+offset), 1, 0)
short_positions = np.where(df2['C_ema'] < df2['L_sma']*(1-offset), -1, 0)
df2['Position'] = long_positions + short_positionsdf2.round(3)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加了位置列

我们可以在图表上标出我们的信号:

**plot_system2_sig(df2)**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带信号标记的图表

这个系统比前一个系统有更多的信号,图表看起来很拥挤。我们可以详细查看任何日期范围:

**plot_system2_sig(df2['2018-12-01':'2019-05-30'])**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

日期范围详细信息

我们应用与之前相同的计算来获得策略的回报:

**# The returns of the Buy and Hold strategy:
df2['Hold'] = np.log(df2['Adj Close'] / df2['Adj Close'].shift(1))# The returns of the Moving Average strategy:
df2['Strategy'] = df2['Position'].shift(1) * df2['Hold']# We need to get rid again of the NaN generated in the first row:
df2.dropna(inplace=True)returns2 = np.exp(df2[['Hold', 'Strategy']].sum()) -1print(f"Buy and hold return: {round(returns2['Hold']*100,2)}%")
print(f"Strategy return: {round(returns2['Strategy']*100,2)}%")**

输出:

**Buy and hold return: 17.04%
Strategy return: -5.25%**

和以前一样,我们可以按年计算回报率:

**n_days2 = len(df2)# Assuming 252 trading days in a year:
ann_returns2 = 252 / n_days2 * returns2print(f"Buy and hold annualized return: {round(ann_returns2['Hold']*100,2)}%")
print(f"Strategy annualized return: {round(ann_returns2['Strategy']*100,2)}%")**

输出:

**Buy and hold annualized return: 3.52%
Strategy annualized return: -1.09%**

在这种情况下,我们的策略实际上不如买入并持有策略。**

你可能已经注意到,我使用未调整的价格序列来评估信号,而我一直使用调整后的价格来计算回报。每当股息、拆分或其他公司行为造成价格缺口时,使用未经调整的价格评估信号有引入错误触发的风险。在这里,我只是用了一个价格系列,这个价格系列很常见,每个人都可以免费下载。如果我们只有未调整的价格,我们应该使用所有关于公司行为的信息来修正我们的回溯测试。

结论

这就是我们执行回溯测试和选择可以依赖的策略所需要的吗?肯定不是:在我们的回溯测试中,我们做了(尽管是隐含的)一些假设和简化,这些假设和简化会极大地影响我们的结果。首先,我们假设一只股票可以在信号触发当天的收盘价买入。实际上,这是不能保证的:实际价格将在信号发生后一天的范围内。那么,交易成本就不得不包括在内了。例如:

  • 支付经纪费是为了执行和清算我们的订单。
  • 买价和卖价之间的价差是成本的一部分。
  • 如果我们利用杠杆买入,我们需要支付利息。同样,如果我们借入股票卖空,我们需要支付贷款利息。

其中一些因素比其他因素更容易理解并包含在模型中。

当我们想要评估一个系统的性能并将其与其他系统的性能进行比较时,给定期间的回报只是我们想要考虑的众多性能和风险指标中的一个。一些例子是:

  • 成功交易与失败交易的百分比
  • 最大提款:我们累积利润的最高点和最低点之间的差额。
  • 收益的标准差夏普比率。****
  • 风险/回报比,这是我们每投资一美元,从一笔交易中可以获得的预期回报。

我们刚刚介绍的准系统回溯测试为计算所有这些指标和构建更现实的系统提供了起点。

出于所有这些原因,除非我们想从零开始建立一个完整的系统,如果我们需要实际地回溯测试一个策略,最好的选择很可能是使用一个完整的解决方案,比如 ZiplineBacktrader 。然而,当我从头开始编写回溯测试时,我仍然不断地学习很多关于指标和策略的知识,这是我绝对推荐的练习。

跟踪数据的 Python 技巧

原文:https://towardsdatascience.com/python-tricks-for-keeping-track-of-your-data-aef3dc817a4e?source=collection_archive---------11-----------------------

如何用列表、字典计数器和命名元组来跟踪信息

动机

在您的数据科学项目中,有时您希望跟踪数据中的信息,或者灵活地快速轻松地更新新输入的数据。了解如何使用 Python 的一些数据对象将使您在数据科学职业生涯中处理大量数据时保持条理并避免错误。

在本文中,您将学习如何:

  • 循环时跟踪索引
  • 更新新词典项目
  • 用可重复使用的对象记录新信息

我将从这些问题开始,然后详细介绍如何用 Python 工具解决它们。我希望这种方法能帮助你想象这些工具在你的代码中的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由埃德加·恰帕罗Unsplash 上拍摄

循环时保持跟踪

假设你有一个朋友的名单。您希望在跟踪计数的同时遍历列表。你怎么能这样做?这可以通过enumerate轻松完成

>>> friends = ['Ben', 'Kate', 'Thinh']
>>> for i, item in enumerate(friends):
>>>     print(f'{i}: {item}')
0: Ben
1: Kate
2: Thinh

或者简单地用字典理解

>>> {i: friends[i] for i in range(len(friends))}
{0: 'Ben', 1: 'Kate', 2: 'Thinh'}

更新新词典项目:

你在用字典记录第一句话中的单词及其数量。

sent1 = {'love': 1, 'hate': 3}

但是当你读到第二个句子时,你想用新的句子更新你的旧字典。

sent2 = {'love': 2, 'flower': 1}

所以你新更新的单词包会变成这样:

{'love': 3, 'hate': 3, 'flower': 1}

这怎么可能呢?如果有一些工具可以让你轻松做到这一点,那不是很好吗?如果这就是你想要的,collections.Counter会支持你。collections.Counter该类允许集合中的元素出现不止一次

from collections import Counter
bag_words = Counter()sent1 = {'love': 1, 'hate': 3}bag_words.update(sent1)sent2 = {'love': 2, 'flower': 1}bag_words.update(sent2)bag_words

结果:

Counter({'love': 3, 'hate': 3, 'flower': 1})

不错!现在,随着你从其他句子中收集更多的信息,你可以很容易地更新你的单词包。要找出句子中有多少个独特的单词,你可以使用len

>>> len(bag_words)
3

或者想知道句子中的单词总数,你可以用sum

>>> sum(bag_words.values())
7

用命名元组定义可重用对象

你想记录朋友的信息列表,为他们的生日做准备。因为您现在还没有可用的信息,所以您想先创建一个占位符,以便以后输入信息。如果你想记录凯特的生日,喜欢的食物,颜色,以及她是否内向,你可以这样做:

>>> Kate = Friend('Feb', 'cake', 'pink', True)

当你不记得她的生日时,你可以打电话

>>> Kate.birthday
'Feb'

Python 中的 class 对象将使您能够实例化 Kate,但是您发现创建一个Friend类来保存简单信息需要时间。如果是这样的话,namedtuple就是你的 to-go 函数。nametuples允许您为您的记录定义一个可重用的对象,以确保使用正确的文件名

from collections import namedtupleFriend = namedtuple('Friend' , 'birthday food color introvert')Kate = Friend('Feb', 'cake', 'pink', True)Ben = Friend('Jan', 'fish', 'red', False)

显示关于 Kate 的信息:

>>> Kate
Friend(birthday='Feb', food='cake', color='pink', introvert=True)

如果你想知道本是内向还是外向,你可以打电话

>>> Ben.introvert
False

使用nametuples,您可以轻松地重用同一个对象来实例化新信息。

结论

厉害!你已经学会了如何使用enumerate、集合理解、Counternamedtuple来跟踪信息。我希望本教程能够为您提供额外的有用知识,将它们添加到您的数据科学工具包中。

这个 Github repo 中,您可以随意派生和使用本文的代码。

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

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

[## 高效 Python 代码的计时

如何比较列表、集合和其他方法的性能

towardsdatascience.com](/timing-the-performance-to-choose-the-right-python-object-for-your-data-science-project-670db6f11b8e) [## 如何使用 Lambda 获得高效的 Python 代码

lambda 对元组进行排序并为您创造性的数据科学想法创建复杂函数的技巧

towardsdatascience.com](/how-to-use-lambda-for-efficient-python-code-ff950dc8d259) [## 使用 Python 最大化您的生产力

你创建了一个待办事项清单来提高效率,但最终却把时间浪费在了不重要的任务上。如果你能创造…

towardsdatascience.com](/maximize-your-productivity-with-python-6110004b45f7) [## cy thon——Python 函数的加速工具

当调整你的算法得到小的改进时,你可能想用 Cython 获得额外的速度,一个…

towardsdatascience.com](/cython-a-speed-up-tool-for-your-python-function-9bab64364bfd) [## 如何从头开始构建矩阵模块

如果您一直在为矩阵运算导入 Numpy,但不知道该模块是如何构建的,本文将展示…

towardsdatascience.com](/how-to-build-a-matrix-module-from-scratch-a4f35ec28b56)

您应该开始在 Python 中使用类型注释

原文:https://towardsdatascience.com/python-type-annotations-and-why-you-should-use-them-6f647c6b4e9c?source=collection_archive---------5-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由拉杜·弗罗林Unsplash 拍摄

因为动态类型化,你花了多少时间调试?

我刚开始学 Python 的时候,是 C 背景。我当时没有丰富的软件开发经验,动态打字提供的自由的滋味是如此甜蜜。利用多态和鸭类型的函数允许我用很少的资源做很多事情。

后来,随着我的经验增长,我开始参与大型项目,我逐渐明白这种自由是福是祸。随着贡献者的增加,代码越来越接近产品级,没有静态类型或类型检查会导致令人讨厌的意外。

这是 Python 生态系统中许多人的共同感受。然而,保持动态类型所允许的自由,但减轻其负面影响是困难的。

输入类型注释

如果 Python 中有一个特性可以最大限度地增加对代码的积极影响,同时只需要最少的努力,那就是类型注释。它允许开发人员与解释器(以及其他开发人员)有效地交流预期的参数类型和返回值,同时保持动态类型的优势。

Python 中的动态类型

那么,什么是动态类型呢?为了看到这一点,让我们来玩一玩。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在幕后,Python 中类似上面a的变量是指针,指向某一类型的对象。然而,指针并不局限于表示给定名称的固定类型的对象。这给了我们很大的自由。例如,函数可以接受任何类型作为参数,因为在后台会传递一个指针。

不幸的是,如果没有适当的照顾,这可能会很快出错。

动态类型是一把双刃剑

想想下面的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个简单的统计函数也适用于列表和 NumPy 数组!多牛逼啊!

嗯,不完全是。有很多方法可以烧伤你自己。例如,您可能会无意中传递一些东西,导致函数崩溃。如果我们用一个字符串调用函数,就会发生这种情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

没有在字符串和整数之间定义除法运算符,因此错误。因为 Python 是一种解释型语言,所以这个问题不会出现,直到函数被错误的参数调用。这可能需要几周的运行时间。像 C 这样的语言可以在编译时间捕捉这些错误,以免出错。

事情可能会变得更糟。例如,让我们用字典调用函数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行成功,但是结果错误。当一个字典被传递时,minmax函数计算的最小值和最大值,而不是我们想要的值。这种错误可能会在很长一段时间内不被发现,同时,你会觉得一切都很好。

让我们看看我们能做些什么来避免这样的问题!

输入函数注释和类型提示

2006 年, PEP 3107 引入了函数注释,在 PEP 484 中扩展了类型提示。(PEP 是 Python Enhancement Proposal 的简称,是 Python 建议和讨论新语言特性的方式。)

函数注释就是*“一种向 Python 函数添加任意元数据注释的语法”*,如 PEP 3107 所述。实际情况如何?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

类型可以用argument: type = default_value提示,返回值可以用def function(...) -> type提示。

这些根本不会被强制执行,并且会被解释器忽略。然而,这并不意味着它们没有惊人的用处!来说服你,看看我们能有什么收获!

通过代码完成加快开发速度

你有没有尝试过在记事本这样的准系统文本编辑器中开发?你必须输入所有的东西,并且时刻记住什么是什么。如果 IDE 不知道您正在使用的对象,它也帮不了您。

看看下面的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PyCharm 中的自动完成

通过函数注释,IDE 知道data对象的类型,它是preprocess_data函数的返回值。因此,您得到了自动完成,这节省了大量的时间。

这也有助于使用函数。大多数情况下,定义是在一个完全不同的模块中,远离你调用它的地方。通过告诉 IDE 参数的类型,它将能够帮助您以正确的格式传递参数,而不必手动检查文档或实现。

代码作为文档

开发人员花在阅读代码上的时间比写代码多得多。我坚信伟大的代码是自文档化的。通过适当的结构和变量命名,很少需要注释。函数注释对此有很大贡献。只要浏览一下定义,就会发现很多关于如何使用它的信息。

类型检查

注释可以从函数外部访问。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这不仅对程序员有用,对程序本身也有用!在调用函数之前,如果需要,可以在运行时检查其参数的有效性。

基于 PEP 484,类型检查被带到了下一个级别。它包括typing模块,“为类型注释提供标准语法,开放 Python 代码以更容易进行静态分析和重构,潜在的运行时类型检查,以及(也许,在某些上下文中)利用类型信息的代码生成”,如 PEP 中所述。

举一个更具体的例子,typing模块包含List,所以通过使用注释List[int],您可以知道该函数期望(或返回)一个整数列表。

更进一步:用 pydantic 进行数据验证

类型检查带来了很多机会。但是,一直手动做就没那么方便了。

如果你想要一个稳定的解决方案,你应该试试 pydantic ,一个数据验证库。使用它的BaseModel类,您可以在运行时验证数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您甚至可以超越这个例子,例如为 pydantic 模型提供定制的验证器

pydantic 是 FastAPI 的支柱之一,是 Python 中 web 开发框架的后起之秀。在那里, pydantic 可以轻松地为端点定义 JSON 模式。

如果您感兴趣,可以在下面找到这些框架的文档。(它们是很好的读物,所以我强烈推荐它们。)

[## pydantic

版本文档:1.6.1 使用 python 类型注释的数据验证和设置管理。pydantic…

pydantic-docs.helpmanual.io](https://pydantic-docs.helpmanual.io/) [## FastAPI

FastAPI 框架,高性能,简单易学,快速编码,准备生产文档…

fastapi.tiangolo.com](https://fastapi.tiangolo.com/)

结论

所以,我希望我已经说服你了。类型注释需要最小的努力,但是它们对你的代码有巨大的积极影响。它

  • 让您和您的团队更容易阅读代码,
  • 鼓励你心中有类型,
  • 帮助识别与类型相关的问题,
  • 启用正确的类型检查。

如果你还没有使用它,你应该现在就开始使用它!这是你只用少量工作就能做的最大的代码改进之一。

如果你喜欢把机器学习概念拆开,理解是什么让它们运转,我们有很多共同点。看看我的博客,我经常在那里发表这样的技术文章!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值