第 1 章 入门

第 1 章 入门

因为本书中有很多代码和样本数据,所以我首先要告诉你如何获取它们,然后再进行下一步。我们需要做一些准备工作。当务之急就是获取学习本书所需的代码和数据,这样你就可以“愉快地开始玩耍了”。获取代码和数据最简单的方法就是按照本章的指示去做。

在本章中,我们首先要安装并准备好Python工作环境:

  • 安装Enthought Canopy;
  • 安装Python库文件;
  • 使用IPython/Jupyter Notebook;
  • 使用、读取和运行本书中的代码文件。

然后,我们将通过一节速成课来学习如何理解Python代码:

  • Python基础——第一部分;
  • 理解Python代码;
  • 导入模块;
  • 使用列表;
  • 元组;
  • Python基础——第二部分;
  • 运行Python脚本。

通过这一章的学习,你可以搭建Python工作环境,熟悉Python语言,然后就可以使用Python开始数据科学的奇妙之旅了。

1.1 安装Enthought Canopy

本节介绍如何在你的计算机上安装Python环境,以开发数据科学所需的代码。我们将安装一个称为Enthought Canopy的软件包,其中既包括开发环境,也包括你需要预先安装的所有Python包,它可以使你的工作更加容易。但是,如果你之前使用过Python,那么你的计算机上可能已经存在Python环境了,如果你想继续使用这个环境,或许也可以。

最重要的是,你的Python环境应该是能够支持Jupyter Notebook的Python 3.5或更高版本 (因为本书使用的就是Jupyter Notebook),而且环境中安装了本书需要的关键软件包。我会通过几个简单的步骤,精确地介绍如何进行完整的安装,这种安装是非常简单的。

首先来看一下关键的软件包,Canopy会自动为我们安装其中的大部分。它将会安装Python 3.5以及我们需要的一些软件包:scikit_learnxlrdstatsmodels。我们还需要使用pip命令,手动安装一个名为pydot2plus的包。这就行了,使用Canopy就是这么简单!

如果完成了以下安装步骤,那么所需的准备工作就全部就绪,可以打开一个小示例文件,进行真正的数据科学工作了。下面,让我们尽快完成所需的准备工作。

(1) 首先,我们需要一个Python集成开发环境,又称IDE。本书中将使用Enthought Canopy。这是一种科学计算环境,非常适合本书。

(2) 若要安装Canopy,请访问www.enthought.com,点击DOWNLOADS:Canopy

(3) Enthought Canopy的Canopy Express版本是免费的,本书使用的就是这个版本。你必须选择适合自己操作系统的版本,对我来说是Windows 64位版。你应该点击对应你的操作系统和Python 3.5版的下载按钮。

(4) 这一步可以不填写任何个人信息。这是一个标准的Windows安装程序,开始下载吧。

(5) 下载完成之后,找到Canopy安装程序并启动,开始安装。在同意许可条款之前,你或许想仔细地读一下,这由你自己决定,然后只需静待安装完成即可。

(6) 安装过程结束后,点击Finish按钮,可以自动启动Canopy。然后你会看到Canopy可以自己搭建Python环境,这个功能非常好,不过要持续1~2分钟。

(7) 安装程序搭建好Python环境之后,你会看到类似下图的屏幕显示。这是一个Canopy欢迎页面,含有一些用户友好的大按钮。

(8) 最棒的是,本书所需的几乎所有软件包都和Enthought Canopy一起预先安装好了,这就是我推荐Enthought Canopy的原因。

(9) 我们的准备工作还有最后一项。点击Canopy欢迎页面的Editor按钮,你会看到跳出一个编辑器界面,点击编辑器界面下方的窗口,输入以下代码。

!pip install pydotplus

(10) 下图是在Canopy编辑器窗口中输入上面代码的屏幕显示。 别忘了按回车键。

(11) 按下回车键后,就会开始安装一个附加模块,在本书后面讲到决策树和生成决策树时,会用到这个模块。

(12) pydotplus安装完成后,程序会通知你。恭喜,你已经完成了所有的准备工作!程序安装完成之后,让我们再通过几个步骤确认程序可以顺畅地运行。

程序运行测试

(1) 对安装好的程序进行一下测试。首先,将Canopy窗口全部关掉!这是因为我们实际上不会使用Canopy编辑器来编写代码,相反,我们要使用的是IPython Notebook,现在它又称为Jupyter Notebook。

(2) 让我来告诉你该怎么做。如果你在操作系统中打开了一个窗口,来查看本书附带的文件(文件的下载方法见前言),那么就应该看到下图这个样子,窗口中有一组本书将要用到的.ipynb代码文件。

现在在列表中找到Outliers文件,也就是Outliers.ipynb文件。双击这个文件,将先启动Canopy,然后会启动你的Web浏览器。这是因为IPython/Jupyter Notebook实际上是在Web浏览器中运行的。开始时,会有一点小小的停顿,这在第一次使用时可能会有点困惑,但你很快就会习惯这种方式。

你很快就能看到,Canopy和默认Web浏览器(我的是Chrome)相继启动。因为双击了Outliers.ipynb文件,所以会看到以下Jupyter Notebook页面。

{%}

如果你看到了这个页面,就说明安装过程一切正常,你已经做好准备,可以开始学习本书后续的内容了!

如果在打开IPYNB文件时出现问题

我发现在双击.ipynb文件时偶尔会出现一点小问题。别紧张!Canopy只是偶尔会有一点古怪,有时会要求你输入密码或令牌,有时会显示无法连接。

当出现以上任意一种情况时,不要紧张,这只是偶然现象。有时候,仅仅是因为电脑上的某些程序没有按照正确顺序启动,或者没有及时启动,这都是很正常的。

你能做的就是再次打开文件,有时候需要试两次或三次才能正确加载它。你只要多试几次,Jupyter Notebook页面总归会出现的,就像前面的Dealing with Outliers页面一样。

1.2 使用并理解IPython/Jupyter Notebook

恭喜你安装完成!下面就开始使用Jupyter Notebook,也就是IPython Notebook。眼下,时髦的名称是Jupyter Noterbook,但很多人还是称其为IPython Notebook,其实很多开发者是交替使用这两个名称的。IPython Notebook可以帮助我记住notebook文件的后缀.ipynb,本书中会频繁使用这种文件。

下面开始学习如何使用IPython/Jupyter Notebook。找到本书下载资料中的DataScience文件夹,我的文件夹是E:DataScience。如果你在前面安装部分没有打开任何文件,那么现在请双击打开Outliers.ipynb文件。

双击文件后,先启动Canopy,然后启动Web浏览器。下面是Outliers文件在我的浏览器中的样子。

如你所见,notebook文件可以将文本、注释和代码组织在一起,而且你还可以在Web浏览器中运行代码。所以,这是一种非常方便的文件格式,你不仅可以将这种文件作为日后工作的参考,帮助自己回忆起算法是如何运行的,还可以使用这种文件来做实验。

IPython/Jupyter Notebook文件实际上是在浏览器中运行的,就像网页一样,但后台需要Python引擎的支持。所以,你会看到和前一个截图相似的页面。

当你在浏览器中向下滚动notebook时,会看到一个代码段。因为它里面包含着实际的代码,所以很容易看见。请在Outliers notebook中找到以下代码,就在上方附近:

%matplotlib inline
import numpy as np

incomes = np.random.normal(27000, 15000, 10000)
incomes = np.append(incomes, [1000000000])

import matplotlib.pyplot as plt
plt.hist(incomes, 50)
plt.show()

快速地看一下这段代码。这段代码首先建立了一个简单的正态分布,用来模拟某个人群的收入分布。然后模拟了将高收入者(比如比尔·盖茨)加入这个人群之后,对收入分布的均值所造成的破坏,以此来说明离群点对分布的影响。

可以通过点击鼠标在notebook中选择任意代码段。如果你点击了以上代码段,再点击上方的运行按钮,就可以运行这段代码了。下图就是页面上部的区域,你可以在这里找到运行按钮。

选择代码段并点击运行按钮后,会生成以下图形。

同样,可以点击下一个代码段,这个代码段只有一行代码:

incomes.mean()

如果你选择了这个代码段,并点击运行按钮,就会看到下面的输出结果。因为离群点的影响,这是一个非常大的值,如下所示:

127148.50796177129

下面来点有意思的。在后面的代码段中,你将看到以下代码,它找出离群点,并将其从数据集中移除:

def reject_outliers(data):
    u = np.median(data)
    s = np.std(data)
    filtered = [e for e in data if (u - 2 * s < e < u + 2 * s)]
    return filtered

filtered = reject_outliers(incomes)
plt.hist(filtered, 50)
plt.show()

在notebook中选择相应的代码段,再次点击运行按钮,你会看到以下图形。

这是一幅更加美观的直方图,代表了更加典型的美国人——已经将那些起破坏作用的离群点剔除了。

现在,你已经做好了学习本书的一切准备,包括所需的全部数据、脚本、Python开发环境和Python notebook。行动起来吧!下面我们将学习一堂关于Python语言本身的速成课,即使你对Python已经很熟悉了,也可以通过这门课程复习一下。所以,无论如何你都要学习一下,马上开始。

1.3 Python基础——第一部分

如果你使用过Python,那么可以跳过接下来这两节。但是,如果你需要复习,或者以前根本没有用过Python,那么就需要好好学习一下了。Python这门脚本语言有一些独特之处需要你了解,下面我们就通过编写一些实际的代码来学习Python。

我之前说过,学习本书需要一些编程经验。你应该使用某种语言编写过代码,即使是脚本语言也没问题,不管是JavaScript、C++、Java还是其他语言均可。如果你是个Python新手,那么我会提供一个快速教程。本节只是给出了几个例子。

与其他语言相比,Python有一些独特之处,这是你应该了解的。所以,我只会指出Python与你用过的其他脚本语言的区别,而通过实际例子展示是最佳方式。下面来看一些Python代码。

如果你打开前面下载过的DataScience文件夹,就会看到Python101.ipynb文件,双击打开它。如果所有程序都安装正确,那么这个文件会在Canopy中打开,如下所示。

 新版本的Canopy会在Web浏览器中打开这个文件,而不是在Canopy编辑器中打开。没关系的!

Python的一大优点就是可以用多种方式运行代码。你可以将代码作为脚本运行,就像普通编程语言一样。你还可以将代码写在IPython Notebook里,本书就是这样做的。通过这种方式,你可以使用Web浏览器查看文件,在文件中使用HTML标记加入一些文本和注释,并嵌入可以使用Python解释器运行的实际代码。

1.4 理解Python代码

下面就是Python代码的一个例子。这个代码段可以在notebook页面中运行,我们将其放大一下,看看其中的代码。

代码中有一个数值列表。Python中的列表与其他语言中的数组很相似,用中括号表示。

这个列表中包含从1到6的数值,如果要迭代其中的每个数值,可以使用for number in listOfNumbers:,这就是在列表中进行迭代的Python语法,后面要加上一个冒号。

 制表符与空白在Python中有实际意义,所以你不能使用它们来随意地格式化代码,这一点需要注意。

我要强调的是,在其他语言中,经常使用小括号或大括号来表示for循环、if代码块或其他代码块中的内容,但在Python中,这是使用空白来实现的。制表符确实非常重要,它可以使Python识别出每个代码块中的内容:

for number in listOfNumbers:
    print number,
    if (number % 2 == 0):
        print ("is even")
    else:
        print ("is odd")
print ("All done.")

在这个for代码块中,所有代码行的前面都有一个制表符,对于每个number in listOfNumbers,都会执行这些由一个制表符缩进的代码。先打印出这个数值,逗号表示随后的内容不会另起一行。在数值后面还要打印出一些东西。如果(number % 2 = 0),就打印出even,否则就打印出odd。所有数值都打印完成后,打印出All done

在代码后面,你可以看到输出结果。在将这段代码放到notebook文件中之前,我已经实测过了,如果你想亲自试一下,只需点击选中这段代码,然后按运行按钮,就可以将这段代码重新运行一遍。为了确认这段代码确实有效,把print语句修改一下,改为输出Hooray! We're all done. Let's party!。再运行一次,你可以看到输出的信息已经改变了。

再强调一下,空白是非常重要的。使用缩进或制表符产生的空白可以表示出代码块,比如for循环或if then语句,这一点请一定注意。还要注意一下,很多子句都是由冒号引导的。

1.5 导入模块

和所有语言一样,Python本身的功能是相当有限的。Python在机器学习、数据挖掘和数据科学领域的真正威力在于,它具有可以完成这些工作的大量外部程序库。例如,NumPy就是这样的程序库之一。这个程序库包括在Canopy中,这里可以将NumPy包导入为np

这意味着可以使用np来引用NumPy包。实际上可以使用任何名称来引用这个包,比如FredTim,但最好使用一个有实际意义的名称。既然已经将NumPy包导入为np,就可以使用np来引用它:

import numpy as np

这个例子将使用NumPy包中的random功能,调用其中的正态分布函数,使用所给参数生成一组符合正态分布的随机数值,并将这些数值打印出来。因为这些数值是随机的,所以每次生成的结果都不一样:

import numpy as np
A = np.random.normal(25.0, 5.0, 10)
print (A)

上述代码的输出如下。

我的结果肯定与你的不一样,这很正常。

1.5.1 数据结构

下面学习数据结构。对于这部分内容,如果你想多花一些时间仔细研究的话,完全没问题。学习数据结构的最佳方法就是马上开始并多做实际练习。我之所以提供了实用的IPython/Jupyter Notebook,就是想让你马上开始,随意地进行修改,进行各种各样的练习。

例如,我们已经有了一个25.0附近的分布,那么可以将其修改为55.0附近的分布:

import numpy as np
A = np.random.normal(55.0, 5.0, 10)
print (A)

所有的数值都改变了,它们都在55附近,不错吧?

对于数据结构,这里会多介绍一些。在第一个例子中,我们使用了一个列表,下面就介绍列表的用法。

1.5.2 使用列表

x = [1, 2, 3, 4, 5, 6]
print (len(x))

这个例子中创建了一个列表x,并为其赋予了从16的数值。中括号表示这里使用的是Python列表。列表是可变对象,我们可以向里面随意地添加元素或重新排列元素。Python中有一个可以确定列表长度的内置函数len。如果输入len(x),就会返回数值6,因为这个列表中有6个数值。

同样,为了确定这些代码确实可以运行,我们向列表中添加一个新的数值,比如4545。如果重新运行这段代码,那么结果就是7,因为现在列表中有7个数值:

x = [1, 2, 3, 4, 5, 6, 4545]
print (len(x))

上述代码的输出如下:

7

回到最初的例子,你还可以对列表进行切片操作。如果想对列表取子集,那么语法非常简单,如下所示:

x[:3]

上述代码的输出如下:

[1, 2, 3]
  1. 前冒号

    如果你想取出列表的前3个元素,即元素3前面的所有元素,可以使用:3,即取出123。为什么会这样呢?因为和大多数语言一样,Python中的索引是从0开始的,所以元素0是1,元素1是2,元素2是3。因为我们需要的是元素3前面的所有元素,所以结果是这样的。

     注意,在大多数语言中,计数是从0开始的,不是1。

    这有点令人迷惑,但在这个例子中,它的意义还是很直观的。你可以认为冒号的意义是所有元素,比如前3个元素。还可以将这个例子修改为取出前4个元素,以证明这段代码确实可以运行:

    x[:4]

    上述代码的输出如下:

    [1, 2, 3, 4]
  2. 后冒号

    如果将冒号放在3的后面,就能取出3后面的所有元素,即x[3:]可以返回456

    x[3:]

    上述代码的输出如下:

    [4, 5, 6]

    你可以保留这个IPython/Jupyter Notebook文件。这是个很好的参考,因为有时候会搞不清分片操作符是否包括某个元素。这时最好的方法就是做一些实际的测试。

  3. 反向语法

    你还可以使用反向语法:

    x[-2:]

    输出如下:

    [5, 6]

    x[-2:]表示取出列表中的后两个元素,这意味着从列表最后向前数两个元素,即56,因为它们就是列表中的最后两个元素。

  4. 向列表中加入列表

    你还可以修改列表。假设我们想向列表中加入另一个列表。可以使用extend函数来完成这个操作,如下所示:

    x.extend([7,8])
    x

    上述代码的输出如下:

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

    原列表中的元素是1, 2, 3, 4, 5, 6。假设我们用新列表[7, 8]来扩展这个列表,其中方括号表示这是一个新的列表。这里直接写出了列表,其实也可以隐式地使用一个变量来引用一个列表。你可以看到,一旦扩展完成,列表[7, 8]就被追加到原列表的最后。使用列表来扩展列表会得到一个新列表。

  5. append函数

    如果你只想向列表中加入一个元素,可以使用append函数。如果想向列表中加入数值9,可以这样做:

    x.append(9)
    x

    上述代码的输出如下:

    [1, 2, 3, 4, 5, 6, 7, 8, 9]
  6. 复杂的数据结构

    使用列表还可以实现比较复杂的数据结构。你不但可以在列表中包括数值,还可以在列表中包括字符串,甚至包括其他列表,都是没问题的。Python是一种弱类型语言,只要你愿意,可以在列表中包括任意类型的数据。以下代码完全没有问题:

    y = [10, 11, 12]
    listOfLists = [x, y]
    listOfLists

    上面例子创建了另一个列表y,其中包含10, 11, 12。我们又创建了一个包含两个列表的列表,惊不惊喜?意不意外?列表listofLists中包含列表x和列表y,这是完全可以的。你可以看到,一个中括号用来表示列表listofLists,其中还有另外两个中括号,表示作为列表元素的列表:

    [[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], [10, 11, 12]]

    有时候这种数据结构是非常方便的。

  7. 引用单个元素

    如果你想引用列表中的单个元素,可以这样使用中括号:

    y[1]

    上述代码的输出如下:

    11

    y[1]会返回元素1。请注意y中包含10, 11, 12。从上个例子可知,索引是从0开始的,所以元素1实际上是列表的第二个元素,即数值11,明白了吗?

  8. 排序函数

    最后来看一下内置的排序函数:

    z = [3, 2, 1]
    z.sort()
    z

    如果使用列表元素是3, 2, 1的列表z,那么对这个列表进行排序后,结果如下:

    [1, 2, 3]
  9. 反向排序

    z.sort(reverse=True)
    z

    上述代码的输出如下:

    [3, 2, 1]

    如果你要进行反向排序,可以在sort函数中设置参数reverse = True,这样就可以对3, 2, 1进行反向排序了。

    如果你想把这部分内容好好消化一下,可以花点时间进行复习。

1.5.3 元组

元组与列表很相似,但它是不可变的,所以你不能对元组进行扩展、追加和排序。除了不能修改之外,元组和列表的工作方式非常相似。与列表的另一个不同是,元组使用小括号来表示,而不是中括号。除了以上两点,元组操作基本上和列表一样:

#元组就是不可变的列表,它使用()来表示,而不是[]
x = (1, 2, 3)
len(x)

上述代码的输出如下:

3

如果x = (1, 2, 3),那么还是可以使用len函数来说明这个元组中有3个元素。如果你对tuple(元组)这个单词不太熟悉,那么只要知道元组中可以包含任意多的元素就行了。尽管这个单词的发音与拉丁语中的3很相似,但并不是说其中只有3个元素。通常,元组中只有两个元素,但实际上,其中可以有任意多的元素。

  1. 引用元素

    同样,我们可以引用元组中的元素。因为从0开始计数,所以元素2还是第三个元素。以下代码会返回数值6

    y = (4, 5, 6)
    y[2]

    上述代码的输出如下:

    6
  2. 元组列表

    和列表一样,元组也可以作为列表的元素。

    listOfTuples = [x, y]
    listOfTuples

    上述代码的输出如下:

    [(1, 2, 3), (4, 5, 6)]

    我们可以创建一个包含两个元组的列表。前面的示例已经创建了值为(1, 2, 3)的元组x和值为(4, 5, 6)的元组y。接下来可以使用这两个元组创建一个列表,并看一下这个列表的值。可以看到,中括号表示这是一个列表,其中有两个元素,分别是由小括号表示的元组。当进行数据科学或者进行某种数据管理或数据处理时,常常使用元组来将输入值赋给变量。对于下面的例子,我会介绍得详细一些:

    (age, income) = "32,120000".split(',')
    print (age)
    print (income)

    上述代码的输出如下:

    32
    120000

    假设有一行来自于逗号分隔值文件的输入数据,其中包含年龄,比如是32,以及由逗号分隔开的对应年龄的收入,比如是120000。我们要做的是对于每行输入都调用split函数,将其拆分为由逗号分隔的一对数值,然后定义一个由年龄和收入组成的元组,并让这个由ageincome组成的元组等于拆分后的结果元组,这样就可以一次性地为两个变量赋值了。

    当需要将多个域一次性地赋给多个变量时,这是一种非常常见的快捷操作。如果运行上面的代码,就会看到由于这个小技巧,age变量确实被赋给了32,而income变量确实被赋给了120000。在进行这种操作时,你需要非常仔细,因为如果没有相应数量的域,或者结果元组中没有相应数量的元素,代码就会引发异常。

1.5.4 字典

最后一种在Python中常用的数据结构是字典,你可以将字典看作其他语言中的映射或散列表。字典是Python内置的一种建立微型数据库或某种键/值对数据的方法。例如,我们可以建立一个《星际迷航》中战舰与舰长的小型字典:

首先,使用大括号可以创建一个空字典captains = { }。然后,可以使用上图中的语法向字典中添加条目。对于字典captainsEnterprise号战舰的舰长是KirkEnterprise D号战舰的舰长是PicardDeep Space Nine号战舰的舰长是SiskoVoyager号战舰的舰长是Janeway。这样就建立了一个战舰和舰长的对应表,如果使用代码print captains["Voyager"],就可以得到Janeway

字典就是建立这种对应关系的一种非常有用的工具。如果在数据集中有某种标识符可以映射为某种有实际意义的名称,你就可以使用字典来实现这种映射,并输出有意义的名称。

从上图中也可以看到,如果想访问不存在的字典条目会发生什么情况。使用字典的get方法,可以安全地返回一个条目。在我们的字典中,确实存在Enterprise这个条目,所以代码返回了Kirk。对于NX-01,字典中则没有这个条目,因为我们没有定义这艘战舰的舰长,所以会返回None。返回None比抛出一个异常更好,但是你确实需要意识到这是一种可能性。

print (captains.get("NX-01"))

上述代码的输出如下:

None

舰长是Jonathan Archer,但你知道,我现在有点太古怪了。

在条目中迭代

for ship in captains:
    print (ship + ": " + captains[ship])

上述代码的输出如下。

下面来看一个在字典条目中迭代的小例子。如果想在字典中的所有战舰之间迭代,并输出舰长的名字,那么可以使用for ship in captains,它可以在字典的所有键之间迭代。然后可以输出与每个键对应的舰长名字,这就是上面的输出。

好了,以上就是我们将在Python中见到的基本数据结构。还有一些其他的数据结构,比如集合,但本书中不会使用。所以,这些就足够我们开始学习了。本书后面的章节中将会介绍Python语言的更多内容。

1.6 Python基础——第二部分

本节将详细介绍更多的Python概念。

1.6.1 Python中的函数

下面介绍Python中的函数。和其他语言一样,你可以使用带有不同参数的函数来多次重复一组操作。在Python中,函数的语法如下:

def SquareIt(x):
    return x * x
print (SquareIt(2))

上述代码的输出如下:

4

你可以使用关键字def来声明一个函数,它表示一个函数定义,函数的名称是SquareIt,后面的括号中是参数列表,这个函数只有一个参数x。再次强调,在Python中空白是非常重要的。函数体不是用大括号或其他符号括起来的,而是通过空白来表示的。我们使用冒号表示函数声明行结束,一个或多个制表符的缩进则告诉解释器,缩进的代码就是SquareIt函数的内容。

所以,这个函数会返回x的平方。我们可以测试一下。我们称这个函数为print SquareIt(2)。和其他语言一样,这行代码会返回4。运行这行代码,结果也确实如此。这就是函数,非常简单。显然,如果我们愿意,可以使用任意多的参数。

下面来使用Python中的函数做一些很酷的事情。你可以将函数名作为参数,如下所示:

#你可以将函数作为参数传递
def DoSomething(f, x):
    return f(x)
print (DoSomething(SquareIt, 3))

上述代码的输出如下:

9

函数的名称为DoSomething,它有两个参数,分别为fx。可以将函数作为其中一个参数的值。请理智地看看这个例子。DoSomething(f, x)会返回f(x),即以x作为参数的函数f的值。因为Python中没有强类型检查,所以可以为第一个参数传递一个函数名称。

如果我们调用DoSomething,并将函数名SquareIt传递给第一个参数,将3传递给第二个参数,这样实际上就是使用参数3来调用函数SquareIt,即SquareIt(3),最后会返回9

把函数作为参数来传递对你来说可能是一个新概念,有些难以理解,所以好好思考一下。

  1. lambda函数——函数式编程

    相比于其他语言,Python中特有的一个概念是lambda函数,这是一种函数式编程。你可以在函数中再包括一个简单的函数。来看一个例子:

    #lambda函数可以让你直接在代码中定义简单的函数
    print (DoSomething(lambda x: x * x * x, 3))

    上述代码的输出如下:

    27

    下面再次调用DoSomething函数,它的第一个参数是个函数,所以除了传递给它一个函数名称外,我们还可以使用lambda关键字在代码行内定义这个函数。lambda的含义就是定义一个临时的未命名函数,这个函数有一个参数x。这里的语法是,lambda定义了一个行内函数,后面是其参数列表。这个函数有一个参数x,冒号后面是函数的具体内容,它将参数x自身相乘3次,返回x的三次方。

    在这个例子中,DoSomething将lambda函数传递给第一个参数,它计算x的三次方,并将3传递给第二个参数。那么这次函数调用的功能是什么呢?lambda函数被传递给DoSomething的第一个参数f3被传递给x,所以会返回参数为3的lambda函数值。lambda函数会将3相乘3次,返回27

    当开始使用MapReduce或Spark时,要经常进行这种操作。所以如果我们以后要使用Hadoop,就要搞清楚这个重要的概念。我再次建议你们花些时间,深刻理解这种操作。

  2. 理解布尔表达式

    布尔表达式的语法有点奇怪,至少在Python中是这样的:

    print (1 == 3)

    上述代码的输出如下:

    False

    通常,我们使用两个等号来测试两个值是否相等。因为1不等于3,所以结果为FalseFalse表示测试结果为假。请记住,当进行布尔测试时,True表示结果为真,False表示结果为假。这和我们使用过的其他语言不太一样,所以要注意一下。

    print (True or False)

    上述代码的输出如下:

    True

    True or False的结果是True,因为其中有一个True。你可以运行一下这行代码,结果肯定是True

    • if语句

      print (1 is 3)

      上述代码的输出如下:

      False

      我们还可以使用is,它和等号的作用是一样的,却是一种更加Python化的表示。1 == 31 is 3是等价的,只是后者更具Python风格。因为1不等于3,所以1 is 3的值是False

    • if-else循环

      if 1 is 3:
          print "How did that happen?"
      elif 1 > 3:
          print ("Yikes")
      else:
          print ("All is well with the world")

      上述代码的输出如下:

      All is well with the world

      上面例子中使用了if-elseelse-if代码块,这样可以使程序更复杂一些。如果1 is 3,就打印出How did that happen?。当然,1不是3,所以我们将进入else-if代码块,继续测试是否1 > 3。同样,这个条件也为假。如果这个条件为真,就打印出Yikes。最后进入else子句,打印出All is well with the world

      实际上,1不是31也不大于3,所以肯定会打印出All is well with the world。其他语言也有类似的语法,但是Python中的语法更强大。请保存好这个notebook,它以后会是很好的参考。

1.6.2 循环

最后要介绍的一项Python基础知识是循环。前面我们已经见过了几种循环,下面是另一个例子:

for x in range(10):
print (x),

上述代码的输出如下:

0 1 2 3 4 5 6 7 8 9

例如,可以使用range操作符来自动定义一个位于某个范围之内的数值列表,比如range(10)会生成一个从0到9的列表。使用for x in range(10),可以在这个列表的所有元素之间迭代,并打印出每个元素。同样,print语句后面的逗号表示不用另起一行,而是继续输出。所以,列表中的每个元素都打印在了一行上。

为了让代码更复杂一些,下面来看一下continuebreak的作用。和其他语言一样,在循环迭代中,你可以选择跳过某些操作,也可以完全结束循环:

for x in range(10):
    if (x is 1):
continue
if (x > 5):
    break
print (x),

上述代码的输出如下:

0 2 3 4 5

上面的例子中对从0到9的数值进行了处理。如果遇到1,就不进行处理,而是继续下一次迭代,所以1将被跳过。如果数值大于5,就跳出循环,完全结束操作。我们预期的结果是输出从0到5的数值,除了1之外。如果是1,就跳过去。结果也正是如此。

while循环

还有一种循环是while循环,很多语言中都将while循环作为标准的语法:

x = 0
while (x < 10):
    print (x),
    x += 1

上述代码的输出如下:

0 1 2 3 4 5 6 7 8 9

我们从x = 0开始,只要x < 10,就打印出x,并将x增加1。这个过程不断重复,不断增加x,直到x不再小于10,就结束循环。这个例子和前面的第一个例子功能相同,只是实现的方式不同,它使用while循环打印出了0~9的数值。这些例子都非常简单,如果你之前有过一些编程或脚本经验,那么理解它们轻而易举。

要想真正理解这些例子,最好的方式就是动手去做,实际运行这些代码。下面就来实际练习一下吧。

1.6.3 探索活动

下面是一个稍微有些难度的练习。

这是一个很好的小代码段,你可以在里面编写Python代码并运行测试。你的任务是编写代码来创建一个整数列表,在列表元素之间迭代,并打印出其中的偶数。

这个练习并不难,在notebook文件中能找到示例,你需要做的只是将示例代码组织在一起并让它们运行起来。我们的目的不是给你一个难题,而是让你建立起信心,去编写、调试和运行自己的Python代码。我强烈建议你动手练习。所以,祝你好运,也欢迎你来到Python世界。

我们的Python速成课到此为止,很显然,它只包含了一些最基础的内容。在后续章节中,我们还会介绍更多的例子,也会介绍更多的概念。如果你觉得现在学习起来有点困难,那么也许是因为你在编程或脚本方面的经验太少了。在继续学习之前,最好再复习一下Python基础知识。如果你没有问题,那么我们继续。

1.7 运行Python脚本

本书从头至尾都使用IPython/Jupyter Notebook格式的文件(即.ipynb文件),这种文件非常适合本书,因为我们既可以在文件中写代码,又可以写一些文字来解释这些代码,读者还可以使用这种文件来进行实际的练习。

当然,这种文件只是一个很好的起点。在实际工作中,你可能不会使用IPython/Jupyter Notebook来运行Python代码,所以本书也会简单地介绍一下运行Python代码的其他方式,以及交互地运行Python代码的其他方式。Python是非常灵活的。来看一下吧。

1.7.1 运行Python代码的其他方式

你应该清楚,有多种方式可以运行Python代码,本书中会采用IPython/Jupyter Notebook这种格式。但在实际工作中,你不会通过notebook来运行代码,而是会使用独立的脚本来运行。下面将介绍如何运行Python代码。

{%}

回到本书的第一个例子,说明一下空白的重要性。在notebook文件中选中并复制代码,然后粘贴到一个新文件中。

点击最左边的New按钮,创建一个新文件,粘贴代码,并将文件保存为test.py,这里的py是Python脚本的常用扩展名。现在可以使用多种方式来运行这个脚本。

1.7.2 在命令行中运行Python脚本

可以在命令行中运行Python脚本。在Tools菜单中选择Canopy Command Prompt,就可以打开一个命令行窗口,并且所有运行Python代码需要的环境变量已经设置好了。我们只需要输入python test.py就可以运行脚本,得到需要的结果。

在实际工作中,你可能需要像上面这样运行脚本,也许是在Crontab中,也许是在其他什么地方。运行实际的脚本就是这么简单。现在你可以关闭命令行窗口了。

1.7.3 使用Canopy IDE

还可以使用IDE来运行脚本。在Canopy中,可以使用Run菜单中的Run File菜单项,或者点击播放图标来运行脚本。运行结果会显示在底部的输出窗口中,如下面的屏幕截图所示。

{%}

最后,还有另外一种方式。你也可以在底部窗口中以交互的方式来运行脚本。可以每次输入一条Python命令,然后在下图所示的环境中运行。

例如,可以先创建一个列表stuff,其中的元素为1, 2, 3, 4,然后输入len(stuff),就可以得到4

输入for x in stuff: print x,可以得到1 2 3 4

所以,在交互式命令行中,你可以每次输入一条命令,并依次运行。在这个例子中,stuff是一个新创建的变量,是驻留在内存中的一个列表,有点像其他语言中的全局变量。

如果想重启这个环境,去掉变量stuff并重新开始,那么可以使用Run菜单中的Restart Kernel功能,这会给我们一个完全整洁的环境。

现在我们有了一个整洁且全新的Python环境。如果再次输入stuff,就会发现它根本不存在,因为这是一个全新的环境。但是可以重新定义stuff,将它的值修改为[4, 5, 6]

这样,我们就有了3种运行Python代码的方式:IPython/Jupyter Notebook(本书所采用的方式,因为它是一种非常好的学习工具);以独立的脚本文件方式来运行;在交互式的命令行环境中运行。

你应该记住这3种方式。本书后面内容中使用的都是IPython/Jupyter Notebook。但再次强调,在实际工作中,还有其他两种方式可以选择。

1.8 小结

本章先介绍了学习本书的基础——安装Enthought Canopy。然后安装了一些程序库和扩展包。此外还通过一些Python代码介绍了Python基础知识,包括模块、列表和元组,以及Python中的函数和循环。最后运行了几个简单的Python脚本。

下一章将开始学习统计和概率的相关知识。

目录

  • 版权声明
  • 前言
  • 第 1 章 入门
  • 第 2 章 统计与概率复习以及Python实现
  • 第 3 章 Matplotlib与概率高级概念
  • 第 4 章 预测模型
  • 第 5 章 使用Python进行机器学习
  • 第 6 章 推荐系统
  • 第 7 章 更多数据挖掘和机器学习技术
  • 第 8 章 处理真实数据
  • 第 9 章 Apache Spark——大数据上的机器学习
  • 第 10 章 测试与实验设计