Python技巧总结(持续更新)

在这篇文章中,我会列举一些平常会用到的Python技巧和Python工具包,持续更新,建议收藏!

1.整理字符串输入

整理用户输入的问题在编程过程中极为常见。通常情况下,将字符转换为小写或大写就够了,有时你可以使用正则表达式模块「Regex」完成这项工作。但是如果问题很复杂,可能有更好的方法来解决:

user_input = "This  
string has  some whitespaces...  
"  
character_map = {  
    ord(   
 ) :    ,  
    ord(     ) :    ,  
    ord(   
 ) : None  
}  
user_input.translate(character_map)  # This string has some whitespaces... 

在本例中,你可以看到空格符「 n」和「 t」都被替换成了单个空格,「 r」都被删掉了。这只是个很简单的例子,我们可以更进一步,使用「unicodedata」程序包生成大型重映射表,并使用其中的「combining()」进行生成和映射。

2.迭代器切片(Slice)

如果对迭代器进行切片操作,会返回一个「TypeError」,提示生成器对象没有下标,但是我们可以用一个简单的方案来解决这个问题:

import itertools  
s = itertools.islice(range(50), 10, 20)  # <itertools.islice object at 0x7f70fab88138>  
for val in s:  
    ... 

我们可以使用「itertools.islice」创建一个「islice」对象,该对象是一个迭代器,可以产生我们想要的项。但需要注意的是,该操作要使用切片之前的所有生成器项,以及「islice」对象中的所有项。

3.跳过可迭代对象的开头

有时你要处理一些以不需要的行(如注释)开头的文件。「itertools」再次提供了一种简单的解决方案:

string_from_file = """  
// Author: ...  
// License: ...  
//  
// Date: ...  
Actual content... 
 """ 
import itertools  
for line in itertools.dropwhile(lambda line: line.startswith("//"), string_from_file.split("  
")):  
    print(line) 

这段代码只打印初始注释部分之后的内容。如果我们只想舍弃可迭代对象的开头部分(本示例中为开头的注释行),而又不知道要这部分有多长时,这种方法就很有用了。

4.只包含关键字参数的函数 (kwargs)

当我们使用下面的函数时,创建仅仅需要关键字参数作为输入的函数来提供更清晰的函数定义,会很有帮助:

def test(*, a, b):  
    pass  
test("value for a", "value for b")  # TypeError: test() takes 0 positional arguments...  
test(a="value", b="value 2")  # Works... 

如你所见,在关键字参数之前加上一个「」就可以解决这个问题。如果我们将某些参数放在「」参数之前,它们显然是位置参数。

5.创建支持「with」语句的对象

举例而言,我们都知道如何使用「with」语句打开文件或获取锁,但是我们可以实现自己上下文表达式吗?是的,我们可以使用「enter」和「exit」来实现上下文管理协议:

class Connection:  
    def __init__(self):  
        ...  
    def __enter__(self):  
        # Initialize connection...  
    def __exit__(self, type, value, traceback):  
        # Close connection...  
with Connection() as c:  
    # __enter__() executes  
    ...  
    # conn.__exit__() executes 

这是在 Python 中最常见的实现上下文管理的方法,但是还有更简单的方法:

from contextlib import contextmanager  
@contextmanager  
def tag(name):  
    print(f"")  
    yield  
    print(f"{name}>")  
with tag("h1"):  
    print("This is Title.") 

上面这段代码使用 contextmanager 的 manager 装饰器实现了内容管理协议。在进入 with 块时 tag 函数的第一部分(在 yield 之前的部分)就已经执行了,然后 with 块才被执行,最后执行 tag 函数的其余部分。

6.用「slots」节省内存

如果你曾经编写过一个创建了某种类的大量实例的程序,那么你可能已经注意到,你的程序突然需要大量的内存。那是因为 Python 使用字典来表示类实例的属性,这使其速度很快,但内存使用效率却不是很高。通常情况下,这并不是一个严重的问题。但是,如果你的程序因此受到严重的影响,不妨试一下「slots」:

class Person:  
    __slots__ = ["first_name", "last_name", "phone"]  
    def __init__(self, first_name, last_name, phone):  
        self.first_name = first_name  
        self.last_name = last_name  
        self.phone = phone 

当我们定义了「slots」属性时,Python 没有使用字典来表示属性,而是使用小的固定大小的数组,这大大减少了每个实例所需的内存。使用「slots」也有一些缺点:我们不能声明任何新的属性,我们只能使用「slots」上现有的属性。而且,带有「slots」的类不能使用多重继承。

7.限制「CPU」和内存使用量

如果不是想优化程序对内存或 CPU 的使用率,而是想直接将其限制为某个确定的数字,Python 也有一个对应的库可以做到:

import signal  
import resource  
import os  
# To Limit CPU time  
def time_exceeded(signo, frame):  
    print("CPU exceeded...")  
    raise SystemExit(1)  
def set_max_runtime(seconds):  
    # Install the signal handler and set a resource limit  
    soft, hard = resource.getrlimit(resource.RLIMIT_CPU)  
    resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))  
    signal.signal(signal.SIGXCPU, time_exceeded)  
# To limit memory usage  
def set_max_memory(size):  
    soft, hard = resource.getrlimit(resource.RLIMIT_AS)  
    resource.setrlimit(resource.RLIMIT_AS, (size, hard)) 

我们可以看到,在上面的代码片段中,同时包含设置最大 CPU 运行时间和最大内存使用限制的选项。在限制 CPU 的运行时间时,我们首先获得该特定资源(RLIMIT_CPU)的软限制和硬限制,然后使用通过参数指定的秒数和先前检索到的硬限制来进行设置。最后,如果 CPU 的运行时间超过了限制,我们将发出系统退出的信号。在内存使用方面,我们再次检索软限制和硬限制,并使用带「size」参数的「setrlimit」和先前检索到的硬限制来设置它。

8.控制可以/不可以导入什么

有些语言有非常明显的机制来导出成员(变量、方法、接口),例如在 Golang 中只有以大写字母开头的成员被导出。然而,在 Python 中,所有成员都会被导出(除非我们使用了「all」):

def foo():  
    pass  
def bar():  
    pass  
__all__ = ["bar"] 

在上面这段代码中,我们知道只有「bar」函数被导出了。同样,我们可以让「all」为空,这样就不会导出任何东西,当从这个模块导入的时候,会造成「AttributeError」。

9.实现比较运算符的简单方法

为一个类实现所有的比较运算符(如 lt , le , gt , ge)是很繁琐的。有更简单的方法可以做到这一点吗?这种时候,「functools.total_ordering」就是一个很好的帮手:

from functools import total_ordering  
@total_ordering  
class Number:  
    def __init__(self, value):  
        self.value = value  
    def __lt__(self, other):  
        return self.value  Number(3))  
print(Number(1) = Number(15))  
print(Number(10) 

这里的工作原理究竟是怎样的呢?我们用「total_ordering」装饰器简化实现对类实例排序的过程。我们只需要定义「lt」和「eq」就可以了,它们是实现其余操作所需要的最小的操作集合(这里也体现了装饰器的作用——为我们填补空白)。

数据分析 篇

1. Pandas Profiling

该工具效果明显。下图展示了调用 df.profile_report() 这一简单方法的结果:


Python技巧总结(持续更新)

使用该工具只需安装和导入 Pandas Profiling 包。

2. 使用 Cufflinks 和 Plotly 绘制 Pandas 数据

「经验丰富的」数据科学家或数据分析师大多对 matplotlib 和 pandas 很熟悉。也就是说,你只需调用 .plot() 方法,即可快速绘制简单的 pd.DataFrame 或 pd.Series:


Python技巧总结(持续更新)

有点无聊?

这已经很好了,不过是否可以绘制一个交互式、可缩放、可扩展的全景图呢?是时候让 Cufflinks* *出马了!(Cufflinks 基于 Plotly 做了进一步的包装。)

在环境中安装 Cufflinks,只需在终端中运行! pip install cufflinks –upgrade 即可。查看下图:


Python技巧总结(持续更新)

效果好多了!

注意,上图唯一改变的是 Cufflinks cf.go_offline() 的导入和设置,它将 .plot() 方法变为 .iplot()。

其他方法如 .scatter_matrix() 也可以提供非常棒的可视化结果:


Python技巧总结(持续更新)

需要做大量数据可视化工作的朋友,可以阅读 Cufflinks 和 Plotly 的文档,发现更多方法。

  • Cufflinks 文档:plot.ly/ipython-noteboo
  • Plotly 文档:plot.ly/

3. IPython 魔术命令

IPython 的「魔术」是 IPython 基于 Python 标准语法的一系列提升。魔术命令包括两种方法:行魔术命令(line magics):以 % 为前缀,在单个输入行上运行;单元格魔术命令(cell magics):以 %% 为前缀,在多个输入行上运行。下面列举了 IPython 魔术命令提供的一些有用功能:

%lsmagic:找出全部命令

如果你只记得一个魔术命令,那必须得是这一个。执行 %lsmagic 命令将提供所有可用魔术命令的列表:


Python技巧总结(持续更新)

%debug:交互式 debug

这可能是我最常使用的魔术命令了。

大部分数据科学家都遇到过这种情况:执行的代码块一直 break,你绝望地写了 20 个 print() 语句,想输出每个变量的内容。然后,当你最终修复问题后,你还得返回并再次删除所有 print() 语句。

不过以后再也不用这样了。遇到问题后只需执行 %debug 命令,即可执行想要运行的任意代码部分:


Python技巧总结(持续更新)

上图中发生了什么?

  1. 我们有一个函数,它以列表为输入,并对所有的偶数取平方值。
  2. 我们运行函数,但是出了些问题。但是我们并不知道怎么回事!
  3. 对该函数使用%debug 命令。
  4. 让调试器告诉我们 x 和 type(x) 的值。
  5. 问题显而易见:我们把 6 作为字符串输入到函数中了!

这对于更复杂的函数非常有用。

%store:在 notebook 之间传递变量

这个命令也很酷。假设你花了一些时间清洗 notebook 中的数据,现在你想在另一个 notebook 中测试一些功能,那么你是在同一个 notebook 中实现该功能,还是保存数据并在另一个 notebook 中加载数据呢?使用%store 命令后,这些操作都不需要!该命令将存储变量,你可以在其他任意 notebook 中检索该变量:


Python技巧总结(持续更新)
  • %store [variable] 存储变量。
  • %store -r [variable] 读取/检索存储变量。

%who:列出所有全局变量。

你是否遇到过,为变量赋值后却忘记变量名的情况?或者不小心删掉了负责为变量赋值的单元格?使用%who 命令,你可以得到所有全局变量的列表:


Python技巧总结(持续更新)

%%time:计时魔法命令

使用该命令可以获取所有计时信息。只需对任意可执行代码应用%%time 命令,你就可以得到如下输出:


Python技巧总结(持续更新)

%%writefile:向文件写入单元格内容

在 notebook 中写复杂函数或类,且想将其保存到专属文件中时,该魔法命令非常有用。只需为函数或类的单元格添加 %%writefile 前缀和想要保存到的文件名即可:


Python技巧总结(持续更新)

如上所示,我们可以将创建的函数保存到 utils.py 文件中,然后就可以随意导入了。在其他 notebook 中也可以这样,只要与 utils.py 文件属于同一个目录即可。

4. Jupyter 中的格式编排

这个工具很酷!Jupyter 考虑到 markdown 中存在 HTML / CSS 格式。以下是我最经常使用的功能:

蓝色、时尚:

This is fancy!

红色、轻微慌张:

This is baaaaad!

绿色、平静:

This is gooood!

下图展示了它们的运行过程:


Python技巧总结(持续更新)

当你想以 Notebook 格式呈现一些发现时,这非常有用!

5. Jupyter 快捷键

想了解和学习键盘快捷键,你可以使用命令面板:Ctrl + Shift + P,获取 notebook 所有功能的列表。下面选取了几个最基础的命令:

  • Esc:进入命令模式。在命令模式内,你可以使用方向键在 notebook 内进行导航。

在命令模式内:

  • A 和 B:在当前单元格上方(Above)或下方(Below)插入新的单元格。
  • M:当前单元格转入 Markdown 状态。
  • Y:当前单元格转入 code 状态。
  • D,D:删除当前单元格。
  • Enter:当前单元格回到编辑模式。

在编辑模式内:

  • Shift + Tab:为你在当前单元格中键入的对象提供文档字符串(文档),持续使用该快捷键,可循环使用文档模式。
  • Ctrl + Shift + -:在光标所在处分割当前单元格。
  • Esc + F:查找并替换代码(不包括输出)。
  • Esc + O:切换单元格输出。

选择多个单元格:

  • Shift + Down 和 Shift + Up:选中下方或上方的单元格。
  • Shift + M:合并选中单元格。

注意,选中多个单元格后,你可以批量执行删除/复制/剪切/粘贴/运行操作。

6. 在 Jupyter(或 IPython)中使一个单元同时有多个输出

想展示 pandas DataFrame 的 .head() 和 .tail(),但由于创建运行 .tail() 方法的额外代码单元过于麻烦而不得不中途放弃,你是否有过这样的经历?现在不用怕了,你可以使用以下代码行展示你想展示的输出:

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

下图展现了多个输出的结果:


Python技巧总结(持续更新)

7. 为 Jupyter Notebook 即时创建幻灯片

使用 RISE,你可以仅通过一次按键将 Jupyter Notebook 即时转变为幻灯片。而且 notebook 仍然处于活跃状态,你可以在展示幻灯片的同时执行实时编码!

要想使用该工具,你只需通过 conda 或 pip 安装 RISE 即可。

conda install -c conda-forge rise

或者:

pip install RISE

现在,你可以点击新按钮,为 notebook 创建不错的幻灯片了:


Python技巧总结(持续更新)

8个流行的 Python 可视化工具包

Matplotlib、Seaborn 和 Pandas

把这三个包放在一起有几个原因:首先 Seaborn 和 Pandas 是建立在 Matplotlib 之上的,当你在用 Seaborn 或 Pandas 中的 df.plot() 时,用的其实是别人用 Matplotlib 写的代码。因此,这些图在美化方面是相似的,自定义图时用的语法也都非常相似。

当提到这些可视化工具时,我想到三个词:探索(Exploratory)、数据(Data)、分析(Analysis)。这些包都很适合第一次探索数据,但要做演示时用这些包就不够了。

Matplotlib 是比较低级的库,但它所支持的自定义程度令人难以置信(所以不要简单地将其排除在演示所用的包之外!),但还有其它更适合做展示的工具。

Matplotlib 还可以选择样式(style selection),它模拟了像 ggplot2 和 xkcd 等很流行的美化工具。下面是我用 Matplotlib 及相关工具所做的示例图:

在处理篮球队薪资数据时,我想找出薪资中位数最高的团队。为了展示结果,我将每个球队的工资用颜色标成条形图,来说明球员加入哪一支球队才能获得更好的待遇。

import seaborn as sns
import matplotlib.pyplot as plt

color_order = ['xkcd:cerulean', 'xkcd:ocean',
                'xkcd:black','xkcd:royal purple',
                'xkcd:royal purple', 'xkcd:navy blue',
                'xkcd:powder blue', 'xkcd:light maroon', 
                'xkcd:lightish blue','xkcd:navy']

sns.barplot(x=top10.Team,
            y=top10.Salary,
            palette=color_order).set_title('Teams with Highest Median Salary')

plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

Python技巧总结(持续更新)

第二个图是回归实验残差的 Q-Q 图。这张图的主要目的是展示如何用尽量少的线条做出一张有用的图,当然也许它可能不那么美观。

import matplotlib.pyplot as plt
import scipy.stats as stats

#model2 is a regression model
log_resid = model2.predict(X_test)-y_test
stats.probplot(log_resid, dist="norm", plot=plt)
plt.title("Normal Q-Q plot")
plt.show()

最终证明,Matplotlib 及其相关工具的效率很高,但就演示而言它们并不是最好的工具。


Python技巧总结(持续更新)

ggplot(2)

你可能会问,「Aaron,ggplot 是 R 中最常用的可视化包,但你不是要写 Python 的包吗?」。人们已经在 Python 中实现了 ggplot2,复制了这个包从美化到语法的一切内容。

在我看过的所有材料中,它的一切都和 ggplot2 很像,但这个包的好处是它依赖于 Pandas Python 包。不过 Pandas Python 包最近弃用了一些方法,导致 Python 版本不兼容。

如果你想在 R 中用真正的 ggplot(除了依赖关系外,它们的外观、感觉以及语法都是一样的),我在另外一篇文章中对此进行过讨论。

也就是说,如果你一定要在 Python 中用 ggplot,那你就必须要安装 0.19.2 版的 Pandas,但我建议你最好不要为了使用较低级的绘图包而降低 Pandas 的版本。

ggplot2(我觉得也包括 Python 的 ggplot)举足轻重的原因是它们用「图形语法」来构建图片。基本前提是你可以实例化图,然后分别添加不同的特征;也就是说,你可以分别对标题、坐标轴、数据点以及趋势线等进行美化。

下面是 ggplot 代码的简单示例。我们先用 ggplot 实例化图,设置美化属性和数据,然后添加点、主题以及坐标轴和标题标签。

#All Salaries
ggplot(data=df, aes(x=season_start, y=salary, colour=team)) +
  geom_point() +
  theme(legend.position="none") +
  labs(title = 'Salary Over Time', x='Year', y='Salary ($)')

Python技巧总结(持续更新)

Bokeh

Bokeh 很美。从概念上讲,Bokeh 类似于 ggplot,它们都是用图形语法来构建图片,但 Bokeh 具备可以做出专业图形和商业报表且便于使用的界面。为了说明这一点,我根据 538 Masculinity Survey 数据集写了制作直方图的代码:

import pandas as pd
from bokeh.plotting import figure
from bokeh.io import show

# is_masc is a one-hot encoded dataframe of responses to the question:
# "Do you identify as masculine?"

#Dataframe Prep
counts = is_masc.sum()
resps = is_masc.columns

#Bokeh
p2 = figure(title='Do You View Yourself As Masculine?',
          x_axis_label='Response',
          y_axis_label='Count',
          x_range=list(resps))
p2.vbar(x=resps, top=counts, width=0.6, fill_color='red', line_color='black')
show(p2)

#Pandas
counts.plot(kind='bar')

Python技巧总结(持续更新)

红色的条形图表示 538 个人关于「你认为自己有男子汉气概吗?」这一问题的答案。9~14 行的 Bokeh 代码构建了优雅且专业的响应计数直方图——字体大小、y 轴刻度和格式等都很合理。

我写的代码大部分都用于标记坐标轴和标题,以及为条形图添加颜色和边框。在制作美观且表现力强的图片时,我更倾向于使用 Bokeh——它已经帮我们完成了大量美化工作。


Python技巧总结(持续更新)

蓝色的图是上面的第 17 行代码。这两个直方图的值是一样的,但目的不同。在探索性设置中,用 Pandas 写一行代码查看数据很方便,但 Bokeh 的美化功能非常强大。

Bokeh 提供的所有便利都要在 matplotlib 中自定义,包括 x 轴标签的角度、背景线、y 轴刻度以及字体(大小、斜体、粗体)等。下图展示了一些随机趋势,其自定义程度更高:使用了图例和不同的颜色和线条。


Python技巧总结(持续更新)

Bokeh 还是制作交互式商业报表的绝佳工具。

Plotly

Plotly 非常强大,但用它设置和创建图形都要花费大量时间,而且都不直观。在用 Plotly 忙活了大半个上午后,我几乎什么都没做出来,干脆直接去吃饭了。我只创建了不带坐标标签的条形图,以及无法删掉线条的「散点图」。Ploty 入门时有一些要注意的点:

  • 安装时要有 API 秘钥,还要注册,不是只用 pip 安装就可以;
  • Plotly 所绘制的数据和布局对象是独一无二的,但并不直观;
  • 图片布局对我来说没有用(40 行代码毫无意义!)

但它也有优点,而且设置中的所有缺点都有相应的解决方法:

  • 你可以在 Plotly 网站和 Python 环境中编辑图片;
  • 支持交互式图片和商业报表;
  • Plotly 与 Mapbox 合作,可以自定义地图;
  • 很有潜力绘制优秀图形。

以下是我针对这个包编写的代码:

#plot 1 - barplot
# **note** - the layout lines do nothing and trip no errors
data = [go.Bar(x=team_ave_df.team,
              y=team_ave_df.turnovers_per_mp)]

layout = go.Layout(

    title=go.layout.Title(
        text='Turnovers per Minute by Team',
        xref='paper',
        x=0
    ),

    xaxis=go.layout.XAxis(
        title = go.layout.xaxis.Title(
            text='Team',
            font=dict(
                    family='Courier New, monospace',
                    size=18,
                    color='#7f7f7f'
                )
        )
    ),

    yaxis=go.layout.YAxis(
        title = go.layout.yaxis.Title(
            text='Average Turnovers/Minute',
            font=dict(
                    family='Courier New, monospace',
                    size=18,
                    color='#7f7f7f'
                )
        )
    ),

    autosize=True,
    hovermode='closest')

py.iplot(figure_or_data=data, layout=layout, filename='jupyter-plot', sharing='public', fileopt='overwrite')



#plot 2 - attempt at a scatterplot
data = [go.Scatter(x=player_year.minutes_played,
                  y=player_year.salary,
                  marker=go.scatter.Marker(color='red',
                                          size=3))]

layout = go.Layout(title="test",
                xaxis=dict(title='why'),
                yaxis=dict(title='plotly'))

py.iplot(figure_or_data=data, layout=layout, filename='jupyter-plot2', sharing='public')

[Image: image.png]

Python技巧总结(持续更新)
表示不同 NBA 球队每分钟平均失误数的条形图


Python技巧总结(持续更新)

总体来说,开箱即用的美化工具看起来很好,但我多次尝试逐字复制文档和修改坐标轴标签时却失败了。但下面的图展示了 Plotly 的潜力,以及我为什么要在它身上花好几个小时:


Python技巧总结(持续更新)

Pygal

Pygal 的名气就不那么大了,和其它常用的绘图包一样,它也是用图形框架语法来构建图像的。由于绘图目标比较简单,因此这是一个相对简单的绘图包。使用 Pygal 非常简单:

  • 实例化图片;
  • 用图片目标属性格式化;
  • 用 figure.add() 将数据添加到图片中。

我在使用 Pygal 的过程中遇到的主要问题在于图片渲染。必须要用 render_to_file 选项,然后在 web 浏览器中打开文件,才能看见我刚刚构建的东西。

最终看来这是值得的,因为图片是交互式的,有令人满意而且便于自定义的美化功能。总而言之,这个包看起来不错,但在文件的创建和渲染部分比较麻烦。


Python技巧总结(持续更新)

Networkx

虽然 Networkx 是基于 matplotlib 的,但它仍是图形分析和可视化的绝佳解决方案。图形和网络不是我的专业领域,但 Networkx 可以快速简便地用图形表示网络之间的连接。以下是我针对一个简单图形构建的不同的表示,以及一些从斯坦福 SNAP 下载的代码(关于绘制小型 Facebook 网络)。


Python技巧总结(持续更新)

我按编号(1~10)用颜色编码了每个节点,代码如下:

options = {
    'node_color' : range(len(G)),
    'node_size' : 300,
    'width' : 1,
    'with_labels' : False,
    'cmap' : plt.cm.coolwarm
}
nx.draw(G, **options)

Python技巧总结(持续更新)

用于可视化上面提到的稀疏 Facebook 图形的代码如下:

import itertools
import networkx as nx
import matplotlib.pyplot as plt

f = open('data/facebook/1684.circles', 'r')
circles = [line.split() for line in f]
f.close()

network = []
for circ in circles:
    cleaned = [int(val) for val in circ[1:]]
    network.append(cleaned)

G = nx.Graph()
for v in network:
    G.add_nodes_from(v)

edges = [itertools.combinations(net,2) for net in network]

for edge_group in edges:
    G.add_edges_from(edge_group)

options = {
    'node_color' : 'lime',
    'node_size' : 3,
    'width' : 1,
    'with_labels' : False,
}
nx.draw(G, **options)

文章来源于互联网

原创文章,作者:27149,如若转载,请注明出处:http://wpbbw.com/4490.html

发表评论

登录后才能评论