Python for Data Analysis-2nd (Chapter 2)

引入惯例
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import statsmodels as sm

2.1 Python解释器

Python是解释性语言。Python解释器同一时间只能运行一个程序的一条语句。标准的交互Python解释器可以在命令行中通过键入python命令打开。

2.2 IPython基础

运行IPython Shell

使用ipython在命令行打开IPython Shell。
许多Python对象被格式化为更易读的形式,或称作pretty-printed ,与普通的print不同。

运行Jupyter Notebook

Python的Jupyter内核是使用IPython。要启动Jupyter,在命令行中输入jupyter notebook

Tab补全

IPython shell的进步之一是具备其它IDE和交互计算分析环境都有的tab补全功能。
在shell中输入表达式,按下Tab,会搜索已输入变量(对象、函数等等)的命名空间,也可以补全任何模块,以及对象的方法、属性等。

注意:默认情况下,IPython会隐藏下划线开头的方法和属性,比如魔术方法和内部的“私有”方法和属性,必须首先键入一个下划线才能看到它们。

?自省

在变量前后使用问号?,可以显示对象的信息。如果对象是一个函数或实例方法,定义过的文档字符串,也会显示出信息。
(使用??会显示函数的源码)

%run命令

可以用%run命令运行所有的Python程序。
在Jupyter notebook中,也可以使用%load,它将脚本导入到一个代码格中。

中断运行的代码

代码运行时按Ctrl-C,无论是%run或长时间运行命令,都会导致KeyboardInterrupt
这会导致几乎所有Python程序立即停止,除非一些特殊情况。

从剪贴板执行程序

可使用%paste%cpaste函数。
%paste可以直接运行剪贴板中的代码;
%cpaste功能类似,但会给出一条提示。使用%cpaste,你可以粘贴任意多的代码再运行。

键盘快捷键
图2-5 IPython shell中一些快捷键的说明
魔术命令

IPython中特殊的命令(Python中没有)被称作“魔术”命令,即在指令前添加百分号%前缀。
魔术函数默认可以不用百分号,只要没有变量和函数名相同。这个特点被称为“自动魔术”,可以用%automagic打开或关闭。

  • Python的文档可以在shell中打开,建议使用%quickref%magic学习下所有特殊命令
集成Matplotlib

%matplotlib魔术函数配置了IPython shell和Jupyter notebook中的matplotlib。

2.3 Python语法基础

Python的语言设计强调的是可读性、简洁和清晰

使用缩进,而不是括号

Python使用空白字符(tab和空格)来组织代码,冒号标志着缩进代码块的开始,冒号之后的所有代码的缩进量必须相同,直到代码块结束。

万物皆对象

Python重要特性之一即对象模型的一致性。
每个数字、字符串、数据结构、函数、类、模块等等,都是在Python解释器的自有“盒子”内,被认为是Python对象。每个对象都有类型(例如,字符串或函数)和内部数据。

注释

任何前面带有井号#的文本都会被Python解释器忽略,通常被用来添加注释。

函数和对象方法调用

使用圆括号调用函数,传递零个或几个参数,或者将返回值给一个变量。函数可以使用位置和关键词参数。
Python中的每个对象都有附加的函数,称作方法,可以用来访问对象的内容。

变量和参数传递

当在Python中创建变量(或名字),即在等号右边创建了一个对这个变量的引用。
当你将对象作为参数传递给函数时,新的局域变量创建了对原始对象的引用,而不是复制。如果在函数里绑定一个新对象到一个变量,这个变动不会反映到上一层。

动态引用,强类型

Python中的对象引用不包含附属的类型。变量是在特殊命名空间中的对象的名字,类型信息保存在对象自身中。
Python在某个方面被认为是强类型化语言,意味着每个对象都有明确的类型(或类),默许转换只会发生在特定的情况下。

可使用isinstance函数检查对象是某个类型的实例。isinstance可以用类型元组,检查对象的类型是否在元组中。

属性和方法

Python的对象通常都有属性(其它存储在对象内部的Python对象)和方法(对象的附属函数可以访问对象的内部数据),可用obj.attribute_name访问属性和方法,也可以用getattr函数,通过名字访问属性和方法。

鸭子类型

通常可能不关心对象的类型,只关心对象是否有某些方法或用途,这被称为“鸭子类型”。

引入

在Python中,模块就是一个有.py扩展名、包含Python代码的文件。

  1. 如果想从同目录下的另一个文件访问some_module.py中定义的变量和函数:
import some_module
result = some_module.f(5)
pi = some_module.PI
  1. 或者:
from some_module import f, g, PI
result = g(5, PI)
  1. 使用as关键词,可以给引入起不同的变量名:
import some_module as sm
from some_module import PI as pi, g as gf

r1 = sm.f(pi)
r2 = gf(6, pi)
二元运算符和比较运算符
表2-3 二元运算符
  • 要判断两个引用是否指向同一个对象,可以使用is方法;is not可以判断两个对象不同。
  • is和is not常用来判断一个变量是否为None,因为只有一个None的实例。
可变与不可变对象

Python中的大多数对象,比如列表、字典、NumPy数组,和用户定义的类型(类),都是可变的,意味着这些对象或包含的值可以被修改。其它的,例如字符串和元组,则是不可变的。

可以修改一个对象并不意味就要修改它。这被称为副作用。例如,当写一个函数,任何副作用都要在文档或注释中写明。

标量类型

Python的标准库中有一些内建的类型,用于处理数值数据、字符串、布尔值,和日期时间。这些单值类型被称为标量类型,本书中称其为标量。
日期和时间处理会另外讨论,因为它们是标准库的datetime模块提供的。

表2-4 Python的标量

数值类型

Python的主要数值类型是intfloat:

  • int可以存储任意大的数;
  • 浮点数使用Python的float类型(不能得到整数的除法会得到浮点数)。每个数都是双精度(64位)的值,也可以用科学计数法表示;

要获得C-风格的整除(去掉小数部分),可以使用底除运算符//

字符串

可以用单引号或双引号来写字符串,对于有换行符的字符串,可以使用三引号,'''或"""都行。许多Python对象使用str函数可以被转化为字符串。

Python的字符串是不可变的,不能修改字符串。

字符串是一个序列的Unicode字符,因此可以像其它序列,比如列表和元组一样处理。

In [64]: s = 'python'

In [65]: list(s)
Out[65]: ['p', 'y', 't', 'h', 'o', 'n']

In [66]: s[:3]
Out[66]: 'pyt'

语法s[:3]被称作切片,适用于许多Python序列。
反斜杠是转义字符,意思是它备用来表示特殊字符,比如换行符\n或Unicode字符。要写一个包含反斜杠的字符串,需要进行转义:

In [67]: s = '12\\34'

In [68]: print(s)
12\34

如果字符串中包含许多反斜杠,但没有特殊字符,可以在字符串前面加一个r(r表示raw),表明字符就是它自身:

In [69]: s = r'this\has\no\special\characters'

In [70]: s
Out[70]: 'this\\has\\no\\special\\characters'

将两个字符串合并,会产生一个新的字符串:

In [71]: a = 'this is the first half '

In [72]: b = 'and this is the second half'

In [73]: a + b
Out[73]: 'this is the first half and this is the second half'

字符串的模板化或格式化,是另一个重要的主题,Python 3拓展了此类的方法。
字符串对象有format方法,可以替换格式化的参数为字符串,产生一个新的字符串:

In [74]: template = '{0:.2f} {1:s} are worth US${2:d}'

在这个字符串中,

  • {0:.2f}表示格式化第一个参数为带有两位小数的浮点数。
  • {1:s}表示格式化第二个参数为字符串。
  • {2:d}表示格式化第三个参数为一个整数。

要替换参数为这些格式化的参数,我们传递format方法一个序列:

In [75]: template.format(4.5560, 'Argentine Pesos', 1)
Out[75]: '4.56 Argentine Pesos are worth US$1'
字节和Unicode

在Python 3及以上版本中,Unicode是一级的字符串类型,这样可以更一致的处理ASCII和Non-ASCII文本。在老的Python版本中,字符串都是字节,不使用Unicode编码。假如知道字符编码,可以将其转化为Unicode。看一个例子:

In [76]: val = "español"

In [77]: val
Out[77]: 'español'

可以用encode将这个Unicode字符串编码为UTF-8:

In [78]: val_utf8 = val.encode('utf-8')

In [79]: val_utf8
Out[79]: b'espa\xc3\xb1ol'

In [80]: type(val_utf8)
Out[80]: bytes

如果你知道一个字节对象的Unicode编码,用decode方法可以解码:

In [81]: val_utf8.decode('utf-8')
Out[81]: 'español'

工作中碰到的文件很多都是字节对象,盲目地将所有数据编码为Unicode是不可取的。

虽然用的不多,你可以在字节文本的前面加上一个b:

In [85]: bytes_val = b'this is bytes'

In [86]: bytes_val
Out[86]: b'this is bytes'

In [87]: decoded = bytes_val.decode('utf8')

In [88]: decoded  # this is str (Unicode) now
Out[88]: 'this is bytes'
布尔值

Python中的布尔值有两个,True和False。比较和其它条件表达式可以用True和False判断。布尔值可以与and和or结合使用:

In [89]: True and True
Out[89]: True

In [90]: False or True
Out[90]: True
类型转换

str、bool、int和float也是函数,可以用来转换类型:

In [91]: s = '3.14159'

In [92]: fval = float(s)

In [93]: type(fval)
Out[93]: float

In [94]: int(fval)
Out[94]: 3

In [95]: bool(fval)
Out[95]: True

In [96]: bool(0)
Out[96]: False
None

None是Python的空值类型。如果一个函数没有明确的返回值,就会默认返回None:

In [97]: a = None

In [98]: a is None
Out[98]: True

In [99]: b = 5

In [100]: b is not None
Out[100]: True

None也常常作为函数的默认参数:

def add_and_maybe_multiply(a, b, c=None):
    result = a + b

    if c is not None:
        result = result * c

    return result

另外,None不仅是一个保留字,还是唯一的NoneType的实例:

In [101]: type(None)
Out[101]: NoneType
日期和时间

Python内建的datetime模块提供了datetimedatetime类型。datetime类型结合了datetime,是最常使用的:

In [102]: from datetime import datetime, date, time

In [103]: dt = datetime(2011, 10, 29, 20, 30, 21)

In [104]: dt.day
Out[104]: 29

In [105]: dt.minute
Out[105]: 30

根据datetime实例,你可以用datetime提取出各自的对象:

In [106]: dt.date()
Out[106]: datetime.date(2011, 10, 29)

In [107]: dt.time()
Out[107]: datetime.time(20, 30, 21)

strftime方法可以将datetime格式化为字符串:

In [108]: dt.strftime('%m/%d/%Y %H:%M')
Out[108]: '10/29/2011 20:30'

strptime可以将字符串转换成datetime对象:

In [109]: datetime.strptime('20091031', '%Y%m%d')
Out[109]: datetime.datetime(2009, 10, 31, 0, 0)

表2-5 Datetime格式化指令(与ISO C89兼容)

当你聚类或对时间序列进行分组,替换datetimetime字段有时会很有用。例如,用0替换分和秒:

In [110]: dt.replace(minute=0, second=0)
Out[110]: datetime.datetime(2011, 10, 29, 20, 0)

因为datetime.datetime是不可变类型,上面的方法会产生新的对象。

两个datetime对象的差会产生一个datetime.timedelta类型:

In [111]: dt2 = datetime(2011, 11, 15, 22, 30)

In [112]: delta = dt2 - dt

In [113]: delta
Out[113]: datetime.timedelta(17, 7179)

In [114]: type(delta)
Out[114]: datetime.timedelta

结果timedelta(17, 7179)指明了timedelta将17天、7179秒的编码方式。
timedelta添加到datetime,会产生一个新的偏移datetime

In [115]: dt
Out[115]: datetime.datetime(2011, 10, 29, 20, 30, 21)

In [116]: dt + delta
Out[116]: datetime.datetime(2011, 11, 15, 22, 30)
控制流

Python有若干内建的关键字进行条件逻辑、循环和其它控制流操作。

if、elif和else

if是最广为人知的控制流语句。它检查一个条件,如果为True,就执行后面的语句:

if x < 0:
    print('It's negative')

if后面可以跟一个或多个elif,所有条件都是False时,还可以添加一个else

if x < 0:
    print('It's negative')
elif x == 0:
    print('Equal to zero')
elif 0 < x < 5:
    print('Positive but smaller than 5')
else:
    print('Positive and larger than or equal to 5')

如果某个条件为True,后面的elif就不会被执行。当使用andor时,复合条件语句是从左到右执行:

In [117]: a = 5; b = 7

In [118]: c = 8; d = 4

In [119]: if a < b or c > d:
   .....:     print('Made it')
Made it

在这个例子中,c > d不会被执行,因为第一个比较是True。
也可以把比较式串在一起:

In [120]: 4 > 3 > 2 > 1
Out[120]: True
for循环

for循环是在一个集合(列表或元组)中进行迭代,或者就是一个迭代器。for循环的标准语法是:

for value in collection:
    # do something with value

可以用continue使for循环提前,跳过剩下的部分。看下面这个例子,将一个列表中的整数相加,跳过None

sequence = [1, 2, None, 4, None, 5]
total = 0
for value in sequence:
    if value is None:
        continue
    total += value

可以用break跳出for循环。下面的代码将各元素相加,直到遇到5:

sequence = [1, 2, 0, 4, 6, 5, 2, 1]
total_until_5 = 0
for value in sequence:
    if value == 5:
        break
    total_until_5 += value

break只中断for循环的最内层,其余的for循环仍会运行:

In [121]: for i in range(4):
   .....:     for j in range(4):
   .....:         if j > i:
   .....:             break
   .....:         print((i, j))
   .....:
(0, 0)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
(2, 2)
(3, 0)
(3, 1)
(3, 2)
(3, 3)

如果集合或迭代器中的元素序列(元组或列表),可以用for循环将其方便地拆分成变量:

for a, b, c in iterator:
    # do something
While循环

while循环指定了条件和代码,当条件为False或用break退出循环,代码才会退出:

x = 256
total = 0
while x > 0:
    if total > 500:
        break
    total += x
    x = x // 2
pass

pass是Python中的非操作语句。代码块不需要任何动作时可以使用(作为未执行代码的占位符);因为Python需要使用空白字符划定代码块,所以需要pass

if x < 0:
    print('negative!')
elif x == 0:
    # TODO: put something smart here
    pass
else:
    print('positive!')
range

range函数返回一个迭代器,它产生一个均匀分布的整数序列:

In [122]: range(10)
Out[122]: range(0, 10)

In [123]: list(range(10))
Out[123]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range的三个参数是(起点,终点,步进):

In [124]: list(range(0, 20, 2))
Out[124]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

In [125]: list(range(5, 0, -1))
Out[125]: [5, 4, 3, 2, 1]

可以看到,range产生的整数不包括终点。range的常见用法是用序号迭代序列:

seq = [1, 2, 3, 4]
for i in range(len(seq)):
    val = seq[i]

可以使用list来存储range在其他数据结构中生成的所有整数,默认的迭代器形式通常是你想要的。
虽然range可以产生任意大的数,但任意时刻耗用的内存却很小。

三元表达式

Python中的三元表达式可以将if-else语句放到一行里。语法如下:

value = true-expr if condition else false-expr

true-exprfalse-expr可以是任何Python代码。它和下面的代码效果相同:

if condition:
    value = true-expr
else:
    value = false-expr

三元表达式中的ifelse可以包含大量的计算,但只有True的分支会被执行。

虽然使用三元表达式可以压缩代码,但会降低代码可读性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容