利用python进行数据分析(1)

第一章 准备工作

本书内容

什么类型的数据

  • 表格型的数据
  • 多维数组(矩阵)
  • 由键位列关联的多张表数据(对于SQL用户来说就是主键或外键)
  • 均匀或非均匀的时间序列。

为何利用Python进行数据分析

Python作为胶水

  • Python在科学计算方面的成功部分是因为它很容易整合C、C++和FORTRAN等语言的代码。大部分现代计算环境都拥有相似的存量程序集,这些程序集使用FORTRAN和C的库进行线性代数、调优、积分、快速傅里叶变换等算法运算

解决“双语言”难题

为何不使用Python

重要的Python库

NumPy

  • NumPy(http://numpy.org)是Numerical Python的简写,是Python数值计算的基石。它提供多种数据结构、算法以及大部分涉及Python数值计算所需的接口。NumPy还包括其他内容:
  • 快速、高效的多维数组对象ndarray
  • 基于元素的数组计算或数组间数学操作函数
  • 用于读写硬盘中基于数组的数据集的工具
  • 线性代数操作、傅里叶变换以及随机数生成

pandas

  • pandas(http://pandas.pyda ta.org)提供了高级数据结构和函数,这些数据结构和函数的设计使得利用结构化、表格化数据的工作快速、简单、有表现力。

matplotlib

  • matplotlib(http://matplotlib.org)是最流行的用于制图及其他二维数据可视化的Python库。

IPython与Jupyter

SciPy

  • SciPy(http://scipy.org)是科学计算领域针对不同标准问题域的包集合。以下是SciPy中包含的一些包:
  • scipy.integrate数值积分例程和微分方程求解器
  • scipy.linalg线性代数例程和基于numpy.linalg的矩阵分解
  • scipy.optimize函数优化器(最小化器)和求根算法
  • scipy.signal信号处理工具
  • scipy.sparse稀疏矩阵与稀疏线性系统求解器

scikit-learn

  • scikit-learn项目(http://scikit-learn.org)诞生于2010年,目前已成为Python编程者首选的机器学习工具包。仅仅七年,scikit-learn就拥有了全世界1500位代码贡献者。其中包含以下子模块。
  • 分类:SVM、最近邻、随机森林、逻辑回归等
  • 回归:Lasso、岭回归等
  • 聚类:k-means、谱聚类等
  • 降维:PCA、特征选择、矩阵分解等
  • 模型选择:网格搜索、交叉验证、指标矩阵
  • 预处理:特征提取、正态化

statsmodels

  • statsmodels(http://statsmodels.org)是一个统计分析包
  • 与scikit-learn相比,statsmodels包含经典的(高频词汇)统计学、经济学算法。它所包含的模型如下。
  • 回归模型:线性回归、通用线性模型、鲁棒线性模型、线性混合效应模型等
  • 方差分析(ANOVA)
  • 时间序列分析:AR、ARMA、ARIMA、VAR等模型
  • 非参数方法:核密度估计、核回归· 统计模型结果可视化

安装与设置

社区和会议

快速浏览本书

术语

  • 处理/处置/规整(munge/munging/wrangling):描述的是将非结构化或者同时又很凌乱的数据整理成结构化、清晰形式的整个过程
  • 伪代码:用一种类似代码的形式描述算法或者过程,而事实上又不是实际有效的源代码。
  • 语法糖:并不增加新特性,但便利于代码编写的编程语法。

第二章Python语言基础、IPython及Jupyter notebook

2.1 Python解释器

  • Python是一种解释型语言。Python解释器通过一次执行一条语句来运行程序。

2.2 IPython基础

2.2.1 运行IPython命令行

import numpy as np
data = {i : np.random.randn()  for i in range(7)}
data
{0: -1.2991373778220445,
 1: -0.32334379274285147,
 2: -1.5074083105244436,
 3: 1.4752955371102277,
 4: 0.20873618343396627,
 5: -1.2957335373240664,
 6: -1.4404604846243687}
  • 与常见的print打印语句不同,IPython中大多数Python对象被格式化为更可读、更美观的形式。如果使用print方法在标准Python解释器中打印data变量,可读性会差一些
print(data)
{0: -1.2991373778220445, 1: -0.32334379274285147, 2: -1.5074083105244436, 3: 1.4752955371102277, 4: 0.20873618343396627, 5: -1.2957335373240664, 6: -1.4404604846243687}

2.2.2 运行Jupyter notebook

  • Jupyter项目中的主要组件就是notebook,这是一种交互式的文档类型,可以用于编写代码、文本(可以带标记)、数据可视化以及其他输出
  • Jupyter会自动打开你的默认网络浏览器(除非你使用了–no-browser命令)。你可以通过http地址来浏览notebook,地址是http://localhost:8888/
#如果这是你第一次使用,请尝试点击空的代码“单元”,输入一行Python代码,然后按下Shift-Enter来执行。
print("hello world")
hello world

2.2.3 Tab补全

  • 当在命令行输入表达式时,按下Tab键即可为任意变量(对象、函数等)搜索命名空间,与你目前已输入的字符进行匹配
an_apple = 27
an_example = 42
an
#还可以在输入英文的句号之后,按下tab,对方法、属性的名称进行补全:
b = [1,2,3]
b.
  File "<ipython-input-16-4bf084b07581>", line 3
    b.<Tab>
      ^
SyntaxError: invalid syntax
#模块也可以通过相同的方式补全
import datetime
datetime.
#在Jupyter notebook和新版的IPython(5.0及以上)中,自动补全是在下拉选项中展现,而不是文本输出
  File "<ipython-input-17-29ca93baded5>", line 3
    datetime.
             ^
SyntaxError: invalid syntax
  • 请注意IPython默认情况下隐藏了以下划线开始的方法和属性,诸如魔术方法、内部“私有”方法和属性,以避免杂乱的显示(使新手混淆)。

  • 这些你当然也是可以使用tab补全的,但是必须先输入下划线才能看到它们。

  • 如果你总是想在tab补全时直接看到它们,则需要修改IPython配置。

  • tab补全除了在搜索交互命名空间和补全对象或模块属性时有用,在很多其他上下文场景中也有用

  • tab补全的另一个应用场景是在函数的关键字参数(包含=号)中节约时间

def func_with_keyworlds(abra=1,abbra=2,abbbra=3):
    return abra,abbra,abbbra
func_with_keyworlds(abbbra=1)
(1, 2, 1)

2.2.4 内省

  • 在一个变量名的前后使用问号(?)可以显示一些关于该对象的概要信息
b = [1,2,3]
?b
def add_numbers(a,b):
    """两个数值相加"""  
    return a+b

add_numbers?
#使用双问号??可以显示函数的源代码
add_numbers??
#?有一个终极用途,可以像标准Unix或Windows命令行一样搜索IPython命名空间。
#把一些字符和通配符(星号*)结合在一起,会显示所有匹配通配符表达式的命名。
np.*load*?

2.2.5 %run命令

  • 文件中定义的所有变量(导入的、函数中的、全局定义的)在运行后,可以在IPython命令行中使用(除非出现某种异常)
  • 如果你想让待运行的脚本使用交互式IPython命名空间中已有的变量,请使用%run -i替代普通的%run命令
  • 在Jupyter notebook中,如果你想将脚本导入一个代码单元,可以使用%load魔术函数
2.2.5.1 中断运行中的代码
  • 在任意代码运行时按下Ctrl-C,无论脚本是通过%run或是其他长命令运行的,都将引起KeyboardInterrupt。除了某些特殊情况,这将导致所有的Python程序立即停止运行

2.2.6 执行剪贴板中的程序

  • %paste会获得剪贴板中的所有文本,并在命令行中作为一个代码块去执行
  • %cpaste与之类似,只不过它会给出一个特殊的提示符,让你粘贴代码
x = 7
y = 5
if x > 5:
    x+=1
    y=8
%paste
UsageError: Line magic function `%paste` not found.
%cpaste
UsageError: Line magic function `%cpaste` not found.

2.2.7 终端快捷键

  • Ctrl-P或向上箭头以当前输入内容开始,向后搜索历史命令
  • Ctrl-N或向下箭头以当前输入内容开始,向前搜索历史命令
  • Ctrl-R按行读取的反向历史搜索(部分匹配)
  • Ctrl-Shift-V从剪贴板粘贴文本
  • Ctrl-C中断当前正在执行的代码
  • Ctrl-A将光标移动到本行起始位置
  • CtrI-E将光标移动到本行结束位置
  • Ctrl-K删除光标后本行的所有内容
  • Ctrl-U删除当前行
  • Ctrl-F将光标向前移动一个字符
  • Ctrl-B将光标向后移动一个字符
  • Ctrl-L清除本屏内容

2.2.8 关于魔术命令

  • IPython的特殊命令(没有内建到Python自身中去)被称为“魔术”命令。这些命令被设计用于简化常见任务,确保用户更容易控制IPython系统的行为。- - 魔术命令的前缀符号是百分号%
  • 魔术命令可以看作是IPython系统内部的命令行程序。
  • 大多数魔术命令都可以使用?查看额外的“命令行”选项
  • 魔术函数也可以不加百分号%就使用,只要没有变量被定义为与魔术函数相同的名字即可。这种特性被称为自动魔术,通过%automagic进行启用/禁用关。
#可以使用%timeit来检查一段Python语句的执行时间,比如一个矩阵操作(后续将会详细讨论%timeit)
a = np.random.randn(100,100)
%timeit np.dot(a,a)
20.5 µs ± 803 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%debug?
%pwd
'D:\\PythonFlie\\python\\利用python进行数据分析(书籍笔记)'
#建议使用%quickref或者%magic探索所有的特殊命令
%quickref
%magic
  • %quickref显示IPython快速参考卡
  • %magic显示所有可用魔术命令的详细文档
  • %debug从最后发生报错的底部进入交互式调试器
  • %hist打印命令输入(也可以打印输出)历史
  • %pdb出现任意报错后自动进入调试器
  • %paste从剪贴板中执行已经预先格式化的Python代码
  • %cpaste打开一个特殊提示符,手动粘贴待执行的Python代码
  • %reset删除交互式命名空间中所有的变量/名称
  • %page OBJECT通过分页器更美观地打印显示一个对象
  • %run script.py在IPython中运行一个Python脚本
  • %prun statement使用CProfile执行语句,并报告输出
  • %time statement报告单个语句的执行时间
  • %timeit statement多次运行单个语句计算平均执行时间;在估算代码最短执行时间时有用
  • %who,%who_ls, %whos根据不同级别的信息/详细程度,展示交互命名空间中定义的变量
  • %xdel variable在IPython内部删除-一个变量,清除相关的引用

2.2.9 matplotlib集成

  • %matplotlib魔术函数可以设置matplotlib与IPython命令行或Jupyter notebook的集成
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(np.random.randn(50).cumsum())
plt.show()


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ll6PSUbg-1640752034422)(output_35_0.png)]

2.3 Python语言基础

2.3.1 语言语义

  • Python语言的设计非常独特,它侧重于可读性、易用性及清晰性。一部分人则认为它是“可执行的伪代码”
2.3.1.1 缩进,而不是大括号
  • Python使用缩进(tab或者空格)来组织代码,而不是像其他语言比如R、C++、Java和Perl那样用大括号
  • 一个冒号代表一个缩进代码块的开始,单个代码块中所有的代码必须保持相同的缩进,直到代码块结束。
  • 我强烈推荐使用四个空格作为你的默认缩进,而不是用tab。
2.3.1.2 一切皆为对象
  • Python语言的一个重要特征就是对象模型的一致性。每一个数值、字符串、数据结构、函数、类、模块以及所有存在于Python解释器中的事物,都是Python对象。
2.3.1.3 注释
  • 所有写在#号之后的文本会自动被Python解释器忽略。因此通常使用#在代码中添加注释。
  • 有时候你会想排除部分代码但又不想删除,一个简单的解决办法就是把代码注释掉
  • 注释也可以写在一行被执行代码的后面。部分编程者更习惯把注释写在特定的一行后面,这在很多时候有用
2.3.1.4 函数和对象方法的调用
  • 几乎所有的Python对象都有内部函数,称为方法,可以访问到对象内部的内容。
  • 函数传参既可以是位置参数也可以是关键字参数
2.3.1.5 变量和参数传递
  • 在Python中对一个变量(或者变量名)赋值时,你就创建了一个指向等号右边对象的引用。
  • 赋值也被称为绑定,这是因为我们将一个变量名绑定到了一个对象上。已被赋值的变量名有时也会被称为被绑定变量
a = [1,2,3]
b = a 
a.append(4)
b
[1, 2, 3, 4]
2.3.1.6 动态引用、强类型
  • 与Java、C++等大多数编译型语言不同,Python中的对象引用并不涉及类型
  • 变量对于对象来说只是特定命名空间中的名称;类型信息是存储在对象自身之中的。
a = 5
type(a)
int
a = "foo"
type(a)
str
  • 了解对象的类型是非常重要的,写出可以处理多种不同输入的函数是非常有用的。你可以使用isinstance函数来检查一个对象是否是特定类型的实例
a = 5
isinstance(a,int)
True
#isinstance接受一个包含类型的元组,你可以检查对象的类型是否在元组中的类型中
a = 5
b = 4.5
isinstance(a,(int,float))
True
isinstance(b,(int,float))
True
2.3.1.7 属性和方法
  • Python中的对象通常都会有属性(Python对象“内部”存储的其他对象)和方法(与对象内部对象有关的函数,相关的对象可以连接到对象内部数据)。
  • 属性和方法都可以通过形如obj.attribute_name的语法进行调用
#属性和方法也可以通过getattr函数获得
a = "foo"
getattr(a,'split')
<function str.split(sep=None, maxsplit=-1)>
2.3.1.8 鸭子类型
  • 常见的案例就是写接受任意序列类型(列表、元组、n维数组),甚至是一个迭代器的函数时使用这项功能。你可以先检查对象是否是一个列表(或者一个NumPy数组),如果不是就把它转换为列表:
def isiterable(obj):
    try:
        iter(obj)
        return True
    except TypeError:#不可遍历
        return False
x = 2.34
if not isinstance(x,list) and isiterable(x):
    x = list(x)
x
2.34
2.3.1.9 导入
  • 通过使用as关键字,你可以对导入内容给予不同的变量名
2.3.1.10 二元运算符和比较运算
  • 检查两个引用是否指向同一个对象,可以使用is关键字。is not在你想检查两个对象不是相同对象时也是有效的。
a = [1,2,3]
b = [1,2,3]
a is b
False
b = a
a is b
True
#因为list函数总是创建一个新的Python列表(即一份拷贝),我们可以确定c与a是不同的
c = list(a)
c is not a
True
#is和==是不同的
a == c
True
2.3.1.11 可变对象和不可变对象
  • Python中的大部分对象,例如列表、字典、NumPy数组都是可变对象,大多数用户定义的类型(类)也是可变的。可变对象中包含的对象和值是可以被修改的
  • 还有其他一些对象是不可变的,比如字符串、元组

2.3.2 标量类型

2.3.2.1 数值类型
  • 基础的Python数字类型就是int和float。
#int可以存储任意大小数字
ival = 457854
ival**6
9212172810807855033141451548434496
#浮点数在Python中用float表示,每一个浮点数都是双精度64位数值。它们可以用科学计数法表示

fval = 7.24
fval
7.24
fval = 7.24e-5
fval
7.24e-05
#整数除法会把结果自动转型为浮点数
3/2
1.5
#如果需要C风格的整数除法(去除了非整数结果的小数部分),可以使用整除操作符//
3//2
1
#### 2.3.2.2 字符串
- 
a = '这是一个字符串'
b = "这是一个字符串"
c = '''
这是一个字符串
这是一个字符串
这是一个字符串
'''
c.count('\n')
4
#Python的字符串是不可变的,你无法修改一个字符串
a = "这是一个字符串"
a[1] = "f"
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-36-64e270e702cb> in <module>
      1 a = "这是一个字符串"
----> 2 a[1] = "f"


TypeError: 'str' object does not support item assignment
#Python对象可以通过str函数转成字符串
a = 5.6
b = str(a)
b
'5.6'
s = "python"
list(s)
['p', 'y', 't', 'h', 'o', 'n']
#s[:3]这种语法被称为切片,在多种Python序列中都有实现
s[:3]
'pyt'
#反斜杠符号\是一种转义符号,它用来指明特殊符号
a = "12\\45"
print(a)
a
#这里print(a)与a是有差距的
12\45





'12\\45'
#你可以在字符串前面加一个前缀符号r,表明这些字符是原生字符
#这个通常在路径里面会使用
#r是raw的简写,表示原生的。
s = r"c\数据分析\python"
print(s)
c\数据分析\python
#使用加号将两个字符串连接在一起
a = "这是一个"
b = "小可爱"
a+b
'这是一个小可爱'
#字符串格式化。字符串对象拥有一个format方法,可以用来代替字符串中的格式化参数,并产生一个新的字符串
template = "{0:.4f}"
template.format(34.34232423)
'34.3423'
2.3.2.3 字节与Unicode
  • 使用enocde方法将这个Unicode字符串转换为UTF-8字节
  • 一个字节对象的Unicode编码,你可以再使用decode方法进行解码
  • 字符串前加前缀b来定义字符文本
2.3.2.4 布尔值
  • Python中的布尔值写作True和False。
  • 比较运算和其他条件表达式的结果为True或False。布尔值可以与and和or关键字合用
2.3.2.5 类型转换
  • str、bool、int和float既是数据类型,同时也是可以将其他数据转换为这些类型的函数
2.3.2.6 None
  • None是Python的null值类型。如果一个函数没有显式地返回值,则它会隐式地返回None
  • 从技术角度来说,None不仅是一个关键字,它还是NoneType类型的唯一实例
2.3.2.7 日期和时间
  • Python中内建的datetime模块,提供了datetime、data和time类型
from datetime import datetime,date,time
dt = datetime(2021,12,6,23,33,6)
dt
datetime.datetime(2021, 12, 6, 23, 33, 6)
dt.day
6
dt.time()
datetime.time(23, 33, 6)
dt.minute
33
#对于datetime实例,你可以分别使用date和time方法获取它的date和time对象
dt.date()
datetime.date(2021, 12, 6)
dt.time()
datetime.time(23, 33, 6)
#strftime方法将datetime转换为字符串
dt.strftime("%Y%m%d %H:%M:%S")
'20211206 23:33:06'
#字符串可以通过strptime函数转换为datetime对象
datetime.strptime("20211206","%Y%m%d")
datetime.datetime(2021, 12, 6, 0, 0)
#聚合或分组时间序列数据时,会常常用到替代datetime时间序列中的一些值,比如将分钟、秒替换为0
dt.replace(year = 2020,month = 1,day = 8)
datetime.datetime(2020, 1, 8, 23, 33, 6)
#两个不同的datetime对象会产生一个datatime.timedelta类型的对象
#两者相减,前者日期大于后者,输出为正数,否则为负数
dt1 = datetime(2021,11,6,22,7,0)
dt2 = datetime(2020,11,6,22,0,0)
dt1 - dt2
datetime.timedelta(days=365, seconds=420)
type(dt1-dt2)
datetime.timedelta

2.3.3 控制流

  • 其他语言中的标准控制流概念在Python中也是通过一些条件逻辑、循环等内建关键字的方式实现的。
2.3.3.1 if、elif和else
  • 一个if语句可以接多个elif代码块和一个else代码块,如果所有的elif条件均为False,则执行else代码块
2.3.3.2 for循环
  • for循环用于遍历一个集合(例如列表或元组)或一个迭代器
  • 使用continue关键字可以跳过conitnue后面的代码进入下一次循环
  • break关键字可以结束一个for循环
  • break关键字只结束最内层的for循环;外层的for循环会继续运行
4 > 3 > 2 >1
True
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)
2.3.3.3 while循环
  • while循环会在条件符合时一直执行代码块,直到条件判断为False或显式地以break结尾时才结束
2.3.3.4 pass
  • pass就是Python中的“什么都不做”的语句
2.3.3.5 range
  • range函数返回一个迭代器
  • 起始、结尾、步进(可以是负的)可以传参给range函数
  • range产生的整数包含起始但不包含结尾
range(10)
range(0, 10)
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(5,0,-1)
range(5, 0, -1)
list(range(5,0,-1))
[5, 4, 3, 2, 1]
#range常用于根据序列的索引遍历序列
seq = [1,2,3,4]
for i in range(len(seq)):
    print(i)
0
1
2
3
sum = 0
for i in range(20):
    if i%3 ==0 or i%5 ==0:
        print(i)
0
3
5
6
9
10
12
15
18
2.3.3.6 三元表达式
  • Python中的三元表达式允许你将一个if-else代码块联合起来,在一行代码或一个语句中生成数据
  • 可以使用三元表达式来压缩代码量,但请注意如果条件以及真假表达式非常复杂,可能会牺牲可读性

第da章 内建数据结构、函数及文件

  • Python的常用数据结构:元组、列表、字典和集合

3.1 数据结构和序列

3.1.1 元组

  • 元组是一种固定长度、不可变的Python对象序列。创建元组最简单的办法就是用逗号分隔序列值。
tup = 4,5,6
tup
(4, 5, 6)
#当你通过更复杂的表达式来定义元组时,通常需要用括号将值包起来
nested_tup = (4,5,6),(7,8)
nested_tup
((4, 5, 6), (7, 8))
#你可以使用tuple函数将任意序列或迭代器转换为元组
tuple([1,2,3])
(1, 2, 3)
tup = tuple("string")
tup
('s', 't', 'r', 'i', 'n', 'g')
#Python中的序列索引是从0开始
tup[2]
'r'
#虽然对象元组中存储的对象其自身是可变的,但是元组一旦创建,各个位置上的对象是无法被修改的
tup = tuple(["foo",[1,2,3],True])
tup
('foo', [1, 2, 3], True)
tup[2] = False
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-31-b89d0c4ae599> in <module>
----> 1 tup[2] = False


TypeError: 'tuple' object does not support item assignment
#如果元组中的一个对象是可变的
tup[1].append(5)
tup
('foo', [1, 2, 3, 5], True)
#使用+号连接元组来生成更长的元组
("foo",True,[1,2,3])+(6,0)+("bar",)
('foo', True, [1, 2, 3], 6, 0, 'bar')
#将元组乘以整数,则会和列表一样,生成含有多份拷贝的元组
#请注意对象自身并没有复制,只是指向它们的引用进行了复制
tup*2
('foo', [1, 2, 3, 5], True, 'foo', [1, 2, 3, 5], True)
3.1.1.1元组拆包
  • 如果你想要将元组型的表达式赋值给变量,Python会对等号右边的值进行拆包
  • 常见使用场景
    • 交换变量名
    • 遍历元组或列表组成的序列
    • 从函数返回多个值
tup = (4,5,6)
a,b,c = tup
c
6
#即使是嵌套元组也可以拆包
tup = (4,5,[False,56])
a,b,c = tup
c
[False, 56]
#使用这个功能,你可以轻易地交换变量名
a,b = 1,2
a
1
b
2
b,a = a,b
a
2
b
1
#拆包的一个常用场景就是遍历元组或列表组成的序列
seq = [(1,2,3),(4,5,6),(7,8,9)]
for a,b,c in seq:
    print(a,b,c)
1 2 3
4 5 6
7 8 9
#拆包的一个常用场景就是遍历元组或列表组成的序列
seq = [(1,2,3),(4,5,6),(7,8,9)]
for a,b,c in seq:
    print('a={0},b={1},c={2}'.format(a,b,c))
a=1,b=2,c=3
a=4,b=5,c=6
a=7,b=8,c=9
#Python语言新增了一些更为高级的元组拆包功能,用于帮助你从元组的起始位置“采集“一些元素。
#这个功能使用特殊的语法*rest,用于在函数调用时获取任意长度的位置参数列表
values = 1,2,3,4,5
a,b,*rest = values
a,b
(1, 2)
rest
[3, 4, 5]
#很多Python编程者会使用下划线(_)来表示不想要的变
a,b,*_ = values
3.1.1.2元组方法
  • 由于元组的内容和长度是无法改变的,它的实例方法很少。一个常见的有用方法是count(列表中也可用),用于计量某个数值在元组中出现的次数
a = (1,2,3,4,5,5,7)
a.count(5)
2

3.1.2 列表

#使用中括号[]或者list类型函数来定义列表
a = [2,3,None,'false']
tup = (1,23,None,"false")
b = list(tup)
b
[1, 23, None, 'false']
#如果是None,没有东西返回
b[1]
23
#列表可以修改
b[1] = "hello"
b
[1, 'hello', None, 'false']
#list函数在数据处理中常用于将迭代器或者生成器转化为列表
gen = range(10)
gen
range(0, 10)
list(gen)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3.1.2.1 增加和移除元素
  • append方法可以将元素添加到列表的尾部
  • 使用insert方法可以将元素插入到指定的列表位置
  • Python collections模块之deque()详解https://blog.csdn.net/chl183/article/details/106958004
  • insert的反操作是pop,该操作会将特定位置的元素移除并返回
  • 通过remove方法移除,该方法会定位第一个符合要求的值并移除它
b.append("world")
b
[1, 'hello', None, 'false', 'world']
#插入位置的范围在0到列表长度之间
b.insert(0,"country")
b
['country', 1, 'hello', None, 'false', 'country', 'world']
#按照索引删除
b.pop(2)
'country'
b
['country', 1, 'world']
#按照元素删除
b.remove('world')
b
['country']
#使用in关键字可以检查一个值是否在列表中
'country' in b
True
#not关键字可以用作in的反义词,表示“不在”
'country' not in b
False
  • 与字典、集合(后面会介绍)相比,检查列表中是否包含一个值是非常缓慢的。这是因为Python在列表中进行了线性逐个扫描,而在字典和集合中Python是同时检查所有元素的(基于哈希表)
3.1.2.2 连接和联合列表
  • 与元组类似,两个列表可以使用+号连接
[1,2,3]+["false",None]
[1, 2, 3, 'false', None]
#extend方法向该列表添加多个元素
x = [1,2,3]+["false",None]
x.extend([67,78])
x
[1, 2, 3, 'false', None, 67, 78]
  • 请注意通过添加内容来连接列表是一种相对高代价的操作,这是因为连接过程中创建了新列表,并且还要复制对象。使用extend将元素添加到已经存在的列表是更好的方式,尤其是在你需要构建一个大型列表时
  • 更倾向于使用extend添加比较大的数据而不是用+号的形式
3.1.2.3 排序
  • 调用列表的sort方法对列表进行内部排序(无须新建一个对象)
#a.sort会返回<function list.sort(*, key=None, reverse=False)>;a.sort()不会返回任何东西
a = [6,3,242,32,89,231]
a.sort()
a
[3, 6, 32, 89, 231, 242]
#sort有一些选项偶尔会派上用场。其中一项是传递一个二级排序key——一个用于生成排序值的函数
b = ["sa","hello","hannan","qw"]
b.sort(key=len)
b
['sa', 'qw', 'hello', 'hannan']
3.1.2.4 二分搜索和已排序列表的维护
  • bisect.bisect会找到元素应当被插入的位置,并保持序列排序,而bisect.insort将元素插入到相应位置
  • bisect模块的函数并不会检查列表是否已经排序,因为这么做代价太大。因此,对未排序列表使用bisect的函数虽然不会报错,但可能会导致不正确的结果。
import bisect
c = [1,2,3,2,12,6,7]
bisect.bisect(c,2)
4
bisect.bisect(c,18)
7
bisect.insort(c,6)
c
[1, 2, 3, 2, 12, 6, 6, 7]
3.1.2.5 切片
  • 使用切片符号可以对大多数序列类型选取其子集,它的基本形式是将start:stop传入到索引符号[ ]中
  • 起始位置start的索引是包含的,而结束位置stop的索引并不包含,因此元素的数量是stop-start
seq = [7,2,3,7,5,6,0,1]
seq[1:5]
[2, 3, 7, 5]
#可以将一个元素替换成两个以上的元素
seq[3:4] = [6,33]
seq
[7, 2, 3, 6, 33, 5, 6, 0, 1]
#start和stop是可以省略的,如果省略的话会默认传入序列的起始位置或结束位置
seq[:4]
[7, 2, 3, 6]
seq[2:]
[3, 6, 33, 5, 6, 0, 1]
#负索引可以从序列的尾部进行索引
seq[-4:]
[5, 6, 0, 1]
#步进值step可以在第二个冒号后面使用,意思是每隔多少个数取一个值
seq[-4::2]
[5, 0]
#当需要对列表或元组进行翻转时,一种很聪明的用法就是向步进传值-1
seq[::-1]
[1, 0, 6, 5, 33, 6, 3, 2, 7]

3.1.3 内建序列函数

3.1.3.1 enumerate
  • Python内建了enumerate函数,返回了(i, value)元组的序列,其中value是元素的值,i是元素的索引
  • 在绘图时,在图上添加数值标签的时候会使用到
#当你需要对数据建立索引时,一种有效的模式就是使用enumerate构造一个字典,将序列值(假设是唯一的)映射到索引位置上
some_list = ["foo","bar","baz"]
mapping = {}
for i,v in enumerate(some_list):
    mapping[i] = v
mapping
{0: 'foo', 1: 'bar', 2: 'baz'}
3.1.3.2 sorted
  • sorted函数返回一个根据任意序列中的元素新建的已排序列表
a = [6,3,242,32,89,231]
sorted(a)
[3, 6, 32, 89, 231, 242]
b = "horse race"
sorted(b)
[' ', 'a', 'c', 'e', 'e', 'h', 'o', 'r', 'r', 's']
3.1.3.3 zip
  • zip将列表、元组或其他序列的元素配对,新建一个元组构成的列表
#zipped返回<zip at 0x2781c66f7c0>
seq1 = ["foo","bar","baz"]
seq2 = ["one","two","three"]
zipped = zip(seq1,seq2)
list(zipped)
[('foo', 'one'), ('bar', 'two'), ('baz', 'three')]
#zip可以处理任意长度的序列,它生成列表长度由最短的序列决定
seq1 = ["foo","bar","baz","hello"]
seq2 = ["one","two","three"]
zipped = zip(seq1,seq2)
list(zipped)
[('foo', 'one'), ('bar', 'two'), ('baz', 'three')]
#zip的常用场景为同时遍历多个序列,有时候会和enumerate同时使用
for i,(a,b) in enumerate(zip(seq1,seq2)):
    print(i,a,b)
0 foo one
1 bar two
2 baz three
#给定一个已“配对”的序列时,zip函数有一种机智的方式去“拆分”序列。这种方式的另一种思路就是将行的列表转换为列的列表
#注意这里需要在a前面加*,否则会出错
a = [(1,"h"),(2,"r"),(3,"u")]
first_name,last_name = zip(*a)
first_name
(1, 2, 3)
last_name
('h', 'r', 'u')
3.1.3.4 reversed
  • reversed函数将序列的元素倒序排列
  • reversed是一个生成器(将在后续内容讨论),因此如果没有实例化(例如使用list函数或进行for循环)的时候,它并不会产生一个倒序的列表
#reversed(a)返回reversed(a)
a = list(range(10))
list(reversed(a))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

3.1.4 字典

  • dict(字典)可能是Python内建数据结构中最重要的。
  • 它更为常用的名字是哈希表或者是关联数组。字典是拥有灵活尺寸的键值对集合,其中键和值都是Python对象。
  • 用大括号{}是创建字典的一种方式,在字典中用逗号将键值对分隔
d1 = {"a":"some values","b":[1,2,3,4]}
d1
{'a': 'some values', 'b': [1, 2, 3, 4]}
#访问、插入或设置字典中的元素,就像访问列表和元组中的元素一样
d1[7] = "an inter"
d1
{'a': 'some values', 'b': [1, 2, 3, 4], 7: 'an inter'}
d1["b"].append(5)
d1
{'a': 'some values', 'b': [1, 2, 3, 4, 5], 'hoo': 'foo', 'c': 'bar'}
#可以用检查列表或元组中是否含有一个元素的相同语法来检查字典是否含有一个键
"b" in d1
True
#可以使用del关键字或pop方法删除值,pop方法会在删除的同时返回被删的值,并删除键
del d1[7]
d1
{'a': 'some values', 'b': [1, 2, 3, 4]}
d1.pop("a")
'some values'
d1
{'b': [1, 2, 3, 4]}
#keys方法和values方法会分别为你提供字典键、值的迭代器
d1.keys()
dict_keys(['b'])
d1.values()
dict_values([[1, 2, 3, 4]])
#update方法将两个字典合并
#update方法改变了字典中元素位置,因此对于任何原字典中已经存在的键,
#如果传给update方法的数据也含有相同的键,则它的值将会被覆盖。
d1.update({"hoo":"foo","c":"bar"})
d1
{'a': 'some values', 'b': [1, 2, 3, 4], 'hoo': 'foo', 'c': 'bar'}
3.1.4.1 从序列生成字典
  • 字典本质上是2-元组(含有2个元素的元组)的集合,字典是可以接受一个2-元组的列表作为参数的
mapping = dict(zip(range(5),reversed(range(5))))
mapping
{0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
3.1.4.2 默认值
words = ["apple","boo","bar","foo"]
by_letter = {}
for word in words:
    letter = word[0]
    if letter not in by_letter:
        by_letter[letter] = word
    else :
        break
by_letter
{'a': 'apple', 'b': 'boo'}
words = ["apple","boo","bar","atom","foo"]
by_letter = {}
for word in words:
    letter = word[0]
    if letter not in by_letter:
        by_letter[letter] = word
    else :
        break
by_letter
{'a': 'apple', 'b': 'boo'}
#字典的setdefault方法
by_letter = {}
for word in words:
    letter = word[0]
    by_letter.setdefault(letter,[]).append(word)
by_letter
{'a': ['apple', 'atom'], 'b': ['boo', 'bar'], 'f': ['foo']}
3.1.4.3 有效的字典键类型
  • 通过hash函数可以检查一个对象是否可以哈希化
hash("string")
2343056889896338451

3.1.5 集合

  • 集合是一种无序且元素唯一的容器
  • 通过set函数或者是用字面值集与大括号的语法
set([2,2,2,1,2,3,5])
{1, 2, 3, 5}
{2,2,2,1,2,3,5}
{1, 2, 3, 5}
#两个集合的联合就是两个集合中不同元素的并集
#可以通过union方法或|二元操作符完成
a = {1,2,3,4,5}
b = {3,4,5,6,7,8}
a.union(b)
{1, 2, 3, 4, 5, 6, 7, 8}
a|b
{1, 2, 3, 4, 5, 6, 7, 8}
a.intersection(b)
{3, 4, 5}
a&b
{3, 4, 5}
c = a.copy()
c |= b
c
{1, 2, 3, 4, 5, 6, 7, 8}
d = a.copy()
d &= b
d
{3, 4, 5}
函数替代方法描述
a.add(x)N/A将元素x加入集合a
a.clear( )N/A
a.remove(x)N/A
a.pop()N/A
a.union(b)a|ba和b中的所有不同元素
a.update(b)a|=b将a的内容设置为a和b的并集
a.intersection(b)a&ba、b中同时包含的元素
a.intersection_ update(b)a&= b将a的内容设置为a和b的交集
a.difference(b)a-b在a不在b的元素
a.difference_ update(b)a-=b将a的内容设为在a不在b的元素
a.symmetric_ _difference(b)a^b所有在a或b中,但不是同时在a.b中的元素
a.symmetric_ difference_ update(b)a^=b将a的内容设为所有在a或b中,但不是同时在a、b中的元素
a. issubset(b)N/A如果a包含于b返回True

a.add(x) N/A 将元素x加入集合a
a.clear( )N/A将集合重置为空,清空所有元素
a.remove(x)N/A从集合a移除某个元素
a.pop()N/A移除任意元素,如果集合是空的抛出keyError
a.union(b)a|ba和b中的所有不同元素
a.update(b)a|=b将a的内容设置为a和b的并集
a.intersection(b)a&ba、b中同时包含的元素
a. intersection_ update(b)a&= b将a的内容设置为a和b的交集
a.difference(b)a-b在a不在b的元素.
a.difference_ update(b)a-=b将a的内容设为在a不在b的元素
a. symmetric_ difference(b)a^b 所有在a或b中,但不是同时在a.b中的元素
a. symmetric
difference_ update(b) a^=b将a的内容设为所有在a或b中,但不是同时在a、b中的元素
a. issubset(b)N/A如果a包含于b返回True

#和字典类似,集合的元素必须是不可变的。如果想要包含列表型的元素,必须先转换为元组
my_data = [1,2,3,4]
my_set = tuple(my_data)
my_set
(1, 2, 3, 4)
#检查一个集合是否是另一个结合的子集(包含于)或超集(包含)
a_set = {1,2,3,4,5}
{1,2,7}.issubset(a_set)
False
#当且仅当两个集合的内容一模一样时,两个集合才相等
{1,2,3} == {3,2,1}
True

3.1.6 列表、集合和字典的推导式

  • 它允许你过滤一个容器的元素,用一种简明的表达式转换传递给过滤器的元素,从而生成一个新的列表
strings = ["a","as","bat","car","python"]
[x.upper() for x in strings if len(x) >2 ]
['BAT', 'CAR', 'PYTHON']
unique_lengths = {len(x) for x in strings}
unique_lengths
{1, 2, 3, 6}
#使用map函数更函数化、更简洁地表达
set(map(len,strings))
{1, 2, 3, 6}
3.1.6.1 嵌套列表推导式
all_data = [['John','Emily','Michael','Mary','Steven'],['Maria','Juan','Javier','Natalia','Pilar']]
all_data[1][2].count("e")
1
name_of_interset = []
for names in all_data:
    enough_es = [name for name in names if name.count("e")>=2]
    name_of_interset.append(enough_es)
name_of_interset
[['Steven'], []]
name_of_interset = []
for names in all_data:
    enough_es = [name for name in names if name.count("e")>=2]
    name_of_interset.extend(enough_es)
name_of_interset
['Steven']
result = [name for names in all_data for name in names if name.count("e")>=2]
result
['Steven']
#首先大范围在小范围
#for表达式的顺序应当和你写嵌套for循环来替代列表推导式的顺序一致
some_tups = [(1,2,3),(4,5,6),(7,8,9)]
flattened = [x for tups in some_tups for x in tups ]
flattened
[1, 2, 3, 4, 5, 6, 7, 8, 9]
flattened = []
for tups in some_tups:
    for x in tups:
        flattened.append(x)
flattened
[1, 2, 3, 4, 5, 6, 7, 8, 9]
#嵌套推导式的语法要和列表推导式中的列表推导式区分开,列表推导式中的列表推导式也是非常有效的
[[x for x in tups] for tups in some_tups]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3.2 函数

  • 函数声明时使用def关键字,返回时使用return关键字
  • 如果Python达到函数的尾部时仍然没有遇到return语句,就会自动返回None
  • 每个函数都可以有位置参数和关键字参数。关键字参数最常用于指定默认值或可选参数。
  • 函数参数的主要限制是关键字参数必须跟在位置参数(如果有的话)后。
  • 你可以按照任意顺序指定关键字参数,这可以让你不必强行记住函数参数的顺序,而只需用参数名指定。
#在前面的函数中,x和y是位置参数,z是关键字参数。这意味着函数可以通过以下任意一种方式进行调用
def my_function(x,y,z=1.5):
    if z > 1:
        return z*(x+y)
    else :
        return z/(x+y)
my_function(1,2,3)
9
my_function(1,2)
4.5
my_function(1,2,z = 0.7)
0.2333333333333333
my_function(x = 1,y = 2,z = 0.7)
0.2333333333333333

3.2.1 命名空间、作用域和本地函数

  • 函数有两种连接变量的方式:全局、本地。
  • 在Python中另一种更贴切地描述变量作用域的名称是命名空间。
#当调用func()时,空的列表a会被创建,五个元素被添加到列表,之后a会在函数退出时被销毁。
def func():
    a = []
    for i in range(5):
        a.append(i)
a = []
def func():
    for i in range(5):
        a.append(i)
#在函数外部给变量赋值是可以的,但是那些变量必须使用global关键字声明为全局变量
a = None
def func():
    global a 
    a = []
a
[]

3.2.2 返回多个值

def f():
    a = 5
    b = 6
    c = 7
    return a,b,c
#这里实质上是返回了一个对象,也就是元组,而元组之后又被拆包为多个结果变量。
d,e,f = f()
e
6
return_values = f()
return_values
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-10-968b6126a2b4> in <module>
----> 1 return_values = f()
      2 return_values


TypeError: 'int' object is not callable
def f():
    a = 5
    b = 6
    c = 7
    return {"a":a,"b":b,"c":c}
f()
{'a': 5, 'b': 6, 'c': 7}

3.2.3 函数是对象

  • Python的函数是对象
#去除空格,移除标点符号,调整适当的大小写
status = ['Alabama','Georgia!','georgia','Florida','south','carolina##','West virginia?']
#使用内建的字符串方法,结合标准库中的正则表达式模块re
import re
def clear_strings(strings):
    result = []
    for i in range(len(status)):
        value = strings[i]
        value = re.sub('[! # ?]','',value)
        value = value.title()#首字母大写
        result.append(value)
    return result
clear_strings(status)
['Alabama',
 'Georgia',
 'Georgia',
 'Florida',
 'South',
 'Carolina',
 'Westvirginia']

3.2.4 匿名(Lambda)函数

  • Python支持所谓的匿名或lambda函数。
  • 匿名函数是一种通过单个语句生成函数的方式,其结果是返回值。
  • 匿名函数使用lambda关键字定义,该关键字仅表达“我们声明一个匿名函数”的意思
  • 和def关键字声明的函数不同,匿名函数对象自身并没有一个显式的__name__属性,这是lambda函数被称为匿名函数的一个原因
#根据字符串中不同字母的数量对一个字符串集合进行排序
strings = ['foo','card','bar','aaaa','abab']
strings.sort(key=lambda x :len(set(list(x))))
strings
['aaaa', 'foo', 'abab', 'bar', 'card']

3.2.5 柯里化:部分参数应用

  • 柯里化是计算机科学术语(以数学家Haskell Curry命名),它表示通过部分参数应用的方式从已有的函数中衍生出新的函数。

3.2.6 生成器

  • 通过一致的方式遍历序列,这是Python的一个重要特性。这个特性是通过迭代器协议来实现的,迭代器协议是一种令对象可遍历的通用方式
  • 迭代器就是一种用于在上下文中(比如for循环)向Python解释器生成对象的对象。
  • 大部分以列表或列表型对象为参数的方法都可以接收任意的迭代器对象
  • 包括内建方法比如min、max和sum,以及类型构造函数比如list和tuple
some_dict = {"a":1,"b":2,"c":3}
#遍历一个字典,获得字典的键
for key in some_dict:
    print(key)
a
b
c
for i in some_dict:
    print(i)
a
b
c
dict_iterator = iter(some_dict)
dict_iterator
<dict_keyiterator at 0x26f2c1aa3b0>
list(dict_iterator)
['a', 'b', 'c']
#如需创建一个生成器,只需要在函数中将返回关键字return替换为yield关键字
def squares(n=10):
    print("from 1 to {0}".format(n**2))
    for i in range(1,n+1):
        yield i**2
gen = squares()
gen
<generator object squares at 0x0000026F2C1E8D60>
for x in gen:
    print(x)
from 1 to 100
1
4
9
16
25
36
49
64
81
100
3.2.6.1 生成器表达式
  • 用生成器表达式来创建生成器更为简单。
  • 生成器表达式与列表、字典、集合的推导式很类似,创建一个生成器表达式,只需要将列表推导式的中括号替换为小括号即可
gen = (x**2 for x in range(10))
gen
<generator object <genexpr> at 0x0000026F2C2AEBA0>
list(gen)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
#上面的代码与下面更为复杂的生成器是等价的
def _make_gen():
    for i in range(10):
        yield i**2
gen = _make_gen()
gen
<generator object _make_gen at 0x0000026F2D9275F0>
list(gen)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
#在很多情况下,生成器表达式可以作为函数参数用于替代列表推导式
sum(x**2 for x in range(10))
285
dict((i,i**2) for i in range(5))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
3.2.6.2 itertools模块
  • 标准库中的itertools模块是适用于大多数数据算法的生成器集合
import itertools
first_letter = lambda x: x[0]
names = ['A1an','Adam','Wes','Wi1l','Albert','Steven']
for letter,names in itertools.groupby (names, first_letter) :
    print(letter,list(names))
A ['A1an', 'Adam']
W ['Wes', 'Wi1l']
A ['Albert']
S ['Steven']

3.2.7 错误和异常处理

  • 优雅地处理Python的错误或异常是构建稳定程序的重要组成部分。在数据分析应用中,很多函数只能处理特定的输入。
  • 某些情况下,你可能想要处理一个异常,但是你希望一部分代码无论try代码块是否报错都要执行。为了实现这个目的,使用finally关键字
  • 可以使用else来执行当try代码块成功执行时才会执行的代码
3.2.7.1 IPython中的异常

3.3 文件与操作系统

  • 打开文件进行读取或写入,需要使用内建函数open和绝对、相对路径
  • tell方法可以给出句柄当前的位置
  • 用sys模块来检查文件的默认编码
  • seek方法可以将句柄位置改变到文件中特定的字节

3.3.1 字节与Unicode文件

  • 需要在非ASCⅡ文本数据上进行数据分析,那么精通Python的Unicode功能是很有必要的。

3.4 本章小结

第四章NumPy基础:数组与向量化计算

4.1 NumPy ndarray:多维数组对象

  • NumPy的核心特征之一就是N-维数组对象——ndarray
  • 一个ndarray是一个通用的多维同类数据容器,它包含的每一个元素均为相同类型
import numpy as np
data = np.random.randn(2,3)
data
array([[0.29331975, 0.9468983 , 0.77589914],
       [0.47945117, 0.32126585, 0.01654545]])
data*10
array([[2.93319746, 9.46898301, 7.75899144],
       [4.7945117 , 3.21265851, 0.16545452]])
data+data
array([[0.58663949, 1.8937966 , 1.55179829],
       [0.95890234, 0.6425317 , 0.0330909 ]])
#每一个数组都有一个shape属性,用来表征数组每一维度的数量
data.shape
(2, 3)
#每一个数组都有一个dtype属性,用来描述数组的数据类型
data.dtype
dtype('float64')

4.1.1 生成ndarray

  • 生成数组最简单的方式就是使用array函数。array函数接收任意的序列型对象(当然也包括其他的数组),生成一个新的包含传递数据的NumPy数组
data1 = [2.1,4,5,9.3]
arr1 = np.array(data1)
arr1
array([2.1, 4. , 5. , 9.3])
#嵌套序列
data2 = [[2.1,4,5,9.3],[2,3,1,1]]
arr2 = np.array(data2)
arr2
array([[2.1, 4. , 5. , 9.3],
       [2. , 3. , 1. , 1. ]])
arr2.ndim
2
arr2.shape
(2, 4)
arr1.dtype
dtype('float64')
#zeros可以一次性创造全0数组,ones可以一次性创造全1数组。empty则可以创建一个没有初始化数值的数组
np.zeros(2)
array([0., 0.])
#注意这里需要小括号
np.zeros(shape = (2,5))
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
#这里返回的并没有作者说的全0数组,应该就是返回未初始化的垃圾数值
#使用np.empty来生成一个全0数组,并不安全,有些时候它可能会返回未初始化的垃圾数值
np.empty((2,3,2))
array([[[7.93765247e-312, 3.16202013e-322],
        [0.00000000e+000, 0.00000000e+000],
        [0.00000000e+000, 6.00774234e-067]],

       [[3.14455224e+179, 6.01760737e-067],
        [7.45958567e-038, 6.89467970e-042],
        [2.36040853e+184, 4.25503767e+174]]])
#arange是Python内建函数range的数组版
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

4.1.2 ndarray的数据类型

  • 数据类型,即dtype,是一个特殊的对象,它包含了ndarray需要为某一种类型数据所申明的内存块信息(也称为元数据,即表示数据的数据)
  • 使用astype时总是生成一个新的数组,即使你传入的dtype与之前一样
#注意float64前面需要加上np.,或者可以直接使用float,则不需要添加np.,数据类型也是float64
#同理int32也是同样的
arr1 = np.array([1,2,3],dtype = np.float64)
arr1.dtype
dtype('float64')
arr2 = np.array([1,2,3],dtype = float)
arr2.dtype
dtype('float64')
arr2 = np.array([1,2,3],dtype = np.int32)
arr2.dtype
dtype('int32')
#使用astype方法显式地转换数组的数据类型
arr = np.array([1,2,3,4,5])
arr.dtype
dtype('int32')
float_arr = arr.astype(np.float64)
float_arr.dtype
dtype('float64')
#如果把浮点数转换成整数,则小数点后的部分将被消除
arr = np.array([1.3,2.5,-3.6,4.9,-5.3])
arr.dtype
dtype('float64')
float_arr = arr.astype(np.int32)
float_arr.dtype
dtype('int32')
float_arr
array([ 1,  2, -3,  4, -5])
#通过astype将字符串转换为数字
#在NumPy中,当使用numpy.string_类型作字符串数据要小心,因为NumPy会修正它的大小或删除输入且不发出警告。
numeric_arr = np.array(["2.3","4.5","7","9.0"],dtype = np.string_)
float_arr = numeric_arr.astype(np.float64)
float_arr 
array([2.3, 4.5, 7. , 9. ])
#使用另一个数组的dtype属性
int_arr = np.arange(10)
calibers = np.array([1,2,3],dtype = np.float64)
int_arr.astype(calibers.dtype)
array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])

4.1.3 NumPy数组算术

  • 数组之所以重要是因为它允许你进行批量操作而无须任何for循环。
  • NumPy用户称这种特性为向量化。
  • 任何在两个等尺寸数组之间的算术操作都应用了逐元素操作的方式
arr = np.array([[1,2,3],[3,4,5]])
arr
array([[1, 2, 3],
       [3, 4, 5]])
arr*arr
array([[ 1,  4,  9],
       [ 9, 16, 25]])
arr - arr
array([[0, 0, 0],
       [0, 0, 0]])
#带有标量计算的算术操作,会把计算参数传递给数组的每一个元素
1/arr
array([[1.        , 0.5       , 0.33333333],
       [0.33333333, 0.25      , 0.2       ]])
arr*0.5
array([[0.5, 1. , 1.5],
       [1.5, 2. , 2.5]])
#同尺寸数组之间的比较,会产生一个布尔值数组
#不同尺寸的数组间的操作,将会用到广播特性
arr2 =  np.array([[0,12,23],[2,67,90]])
arr2 > arr
array([[False,  True,  True],
       [False,  True,  True]])

4.1.4 基础索引与切片

  • 区别于Python的内建列表,数组的切片是原数组的视图。这意味着数据并不是被复制了,任何对于视图的修改都会反映到原数组上
  • (由于NumPy被设计成适合处理非常大的数组,你可以想象如果NumPy持续复制数据会引起多少内存问题。)
  • 不写切片值的[:]将会引用数组的所有值
#一维数组比较简单,看起来和Python的列表很类似
arr1 = np.arange(10)
arr1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr1[5]
5
arr1[2:6]
array([2, 3, 4, 5])
arr1[2:6] = 12
arr1
array([ 0,  1, 12, 12, 12, 12,  6,  7,  8,  9])
#如果你还是想要一份数组切片的拷贝而不是一份视图的话,你就必须显式地复制这个数组
arr1[2:6].copy()
array([12, 12, 12, 12])
arr2d = np.array([[1,2,3],[11,12,13],[21,22,23]])
arr2d[2]
array([21, 22, 23])
#单个元素可以通过递归的方式获得
arr2d[2][2]
23
#可以通过传递一个索引的逗号分隔列表去选择单个元素
arr2d[2,2]
23
arr3d = np.array([[[1,2,3],[11,12,13]],[[21,22,23],[41,42,43]]])
arr3d[0]
array([[ 1,  2,  3],
       [11, 12, 13]])
arr3d[0,1]
array([11, 12, 13])
4.1.4.1 数组的切片索引
arr = np.array([0,1,2,3,64,64,64,8,9])
arr
array([ 0,  1,  2,  3, 64, 64, 64,  8,  9])
arr[1:6]
array([ 1,  2,  3, 64, 64])
arr2d = np.array([[1,2,3],[11,12,13],[21,22,23]])
arr2d
array([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])
#表达式arr2d[:2]的含义为选择arr2d的前两“行”
arr2d[:2]
array([[ 1,  2,  3],
       [11, 12, 13]])
arr2d[:2,1:]
array([[ 2,  3],
       [12, 13]])
#可以选择第二行但是只选择前两列
arr2d[1,1:]
array([12, 13])
#单独一个冒号表示选择整个轴上的数组,因此你可以按照下面的方式在更高维度上进行切片
arr2d[:,1:]
array([[ 2,  3],
       [12, 13],
       [22, 23]])
#对切片表达式赋值时,整个切片都会重新赋值
arr2d[:2,1:] = 0
arr2d
array([[ 1,  0,  0],
       [11,  0,  0],
       [21, 22, 23]])

4.1.5 布尔索引

  • 使用布尔值索引选择数据时,总是生成数据的拷贝,即使返回的数组并没有任何变化。
  • Python的关键字and和or对布尔值数组并没有用,请使用&(and)和|(or)来代替
names = np.array(["Bob","Joe","Will","Bob","Will","Bob","Bob"])
data = np.random.randn(7,4)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Bob', 'Bob'], dtype='<U4')
data
array([[-0.31567413,  0.21075985,  1.35192139,  0.29466683],
       [ 0.09323436, -0.22595805,  0.48826832, -1.11022322],
       [-0.14077013, -0.2255605 ,  2.54537756, -0.75138372],
       [ 1.0264757 ,  0.98484041, -0.64920039, -1.58000295],
       [-0.76545971, -1.39263939, -0.50921365,  1.52282598],
       [-1.04048087,  0.0652562 ,  0.77910129, -1.19046351],
       [-0.26920253, -0.94964351, -1.61560275, -0.26496221]])
names == "Will"
array([ True, False, False,  True, False,  True,  True])
#布尔值数组的长度必须和数组轴索引长度一致
#当布尔值数组的长度不正确时,布尔值选择数据的方法并不会报错,因此我建议在使用该特性的时候要小心
data[names == "Will"]
array([[-0.14077013, -0.2255605 ,  2.54537756, -0.75138372],
       [-0.76545971, -1.39263939, -0.50921365,  1.52282598]])
data[names == "Will",2:]
array([[ 2.54537756, -0.75138372],
       [-0.50921365,  1.52282598]])
#可以使用!=或在条件表达式前使用~对条件取反
data[names != "Will"]
array([[-0.31567413,  0.21075985,  1.35192139,  0.29466683],
       [ 0.09323436, -0.22595805,  0.48826832, -1.11022322],
       [ 1.0264757 ,  0.98484041, -0.64920039, -1.58000295],
       [-1.04048087,  0.0652562 ,  0.77910129, -1.19046351],
       [-0.26920253, -0.94964351, -1.61560275, -0.26496221]])
data[~(names == "Will")]
array([[-0.31567413,  0.21075985,  1.35192139,  0.29466683],
       [ 0.09323436, -0.22595805,  0.48826832, -1.11022322],
       [ 1.0264757 ,  0.98484041, -0.64920039, -1.58000295],
       [-1.04048087,  0.0652562 ,  0.77910129, -1.19046351],
       [-0.26920253, -0.94964351, -1.61560275, -0.26496221]])
#~符号可以在你想要对一个通用条件进行取反时使用
cond = names == "Will"
data[~cond]
array([[-0.31567413,  0.21075985,  1.35192139,  0.29466683],
       [ 0.09323436, -0.22595805,  0.48826832, -1.11022322],
       [ 1.0264757 ,  0.98484041, -0.64920039, -1.58000295],
       [-1.04048087,  0.0652562 ,  0.77910129, -1.19046351],
       [-0.26920253, -0.94964351, -1.61560275, -0.26496221]])
#当要选择三个名字中的两个时,可以对多个布尔值条件进行联合,需要使用数学操作符如&(and)和|(or)
mask = (names == "Will") | (names == "Joe")
mask
array([False,  True,  True, False,  True, False, False])
data[mask]
array([[ 0.09323436, -0.22595805,  0.48826832, -1.11022322],
       [-0.14077013, -0.2255605 ,  2.54537756, -0.75138372],
       [-0.76545971, -1.39263939, -0.50921365,  1.52282598]])
#将data中所有的负值设置为0
data[data < 0] = 0 
data[data > 0] = 1  
data
array([[0., 1., 1., 1.],
       [1., 0., 1., 0.],
       [0., 0., 1., 0.],
       [1., 1., 0., 0.],
       [0., 0., 0., 1.],
       [0., 1., 1., 0.],
       [0., 0., 0., 0.]])
#利用一维布尔值数组对每一行设置数值也是非常简单的
data[names == "Joe"] = 7
data
array([[0., 1., 1., 1.],
       [7., 7., 7., 7.],
       [0., 0., 1., 0.],
       [1., 1., 0., 0.],
       [0., 0., 0., 1.],
       [0., 1., 1., 0.],
       [0., 0., 0., 0.]])

4.1.6 神奇索引

  • 神奇索引是NumPy中的术语,用于描述使用整数数组进行数据索引
  • 请牢记神奇索引与切片不同,它总是将数据复制到一个新的数组中。
arr = np.empty((8,4))
for i in range(8):
    arr[i] = i
arr
array([[0., 0., 0., 0.],
       [1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.]])
#通过传递一个包含指明所需顺序的列表或数组
arr[[4,3,0,6]]
array([[4., 4., 4., 4.],
       [3., 3., 3., 3.],
       [0., 0., 0., 0.],
       [6., 6., 6., 6.]])
#如果使用负的索引,将从尾部进行选择
arr[[-3,-5,-1]]
array([[5., 5., 5., 5.],
       [3., 3., 3., 3.],
       [7., 7., 7., 7.]])
arr = np.arange(32).reshape(8,4)
arr
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23],
       [24, 25, 26, 27],
       [28, 29, 30, 31]])
#如果不考虑数组的维数(本例中是二维),神奇索引的结果总是一维的。
arr[[1,6,2],[1,2,3]]
array([ 5, 26, 11])
arr[[1,6,2]][:,[1,2,1]]
array([[ 5,  6,  5],
       [25, 26, 25],
       [ 9, 10,  9]])

4.1.7 数组转置和换轴

  • 数组拥有transpose方法,也有特殊的T属性
arr = np.arange(15).reshape(3,5)
arr
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
arr.T
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
#当计算矩阵内积会使用np.dot
np.dot(arr.T,arr)
array([[125, 140, 155, 170, 185],
       [140, 158, 176, 194, 212],
       [155, 176, 197, 218, 239],
       [170, 194, 218, 242, 266],
       [185, 212, 239, 266, 293]])
#对于更高维度的数组,transpose方法可以接收包含轴编号的元组,用于置换轴
arr = np.arange(16).reshape((2,2,4))
arr
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])
arr.transpose((1,0,2))
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])
#ndarray有一个swapaxes方法,该方法接收一对轴编号作为参数,并对轴进行调整用于重组数据
#swapaxes返回的是数据的视图,而没有对数据进行复制。
arr.swapaxes(1,2)
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],

       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])

4.2 通用函数:快速的逐元素数组函数

  • 通用函数,也可以称为ufunc,是一种在ndarray数据中进行逐元素操作的函数。
  • 一元和二元应该与一元一次方程里面的理解是一样的,未知数的个数
  • 一元通用函数
    | 函数名 | 描述 |
    | --------- | ---------------------------------------- |
    | abs、fabs | 逐元素地计算整数、浮点数或复数的绝对值 |
    | sqrt | 计算每个元素的平方根(与arr *** 0.5 相等) |
    | square | 计算每个元素的平方(与arr**2相等) |
  • 二元通用函数
    | 函数名 | 描述 |
    | ----------------------------------------------------- | ------------------------------------------------------------ |
    | add | 将数组的对应元素相加 |
    | subtract | 在第二个数组中,将第一个数组中包含的元素去除 |
    | multiply | 将数组的对应元素相乘 |
    | divide, floor_divide | 除或整除(放弃余数) |
    | power | 将第二个数组的元素作为第一个数组对应元素的幂次方 |
    | maximum,fmax | 逐个元素计算最大值,fmax忽略NaN |
    | minimum,fmin | 逐个元素计算最小值,fmin忽略NaN |
    | mod | 按元素的求模计算(即求除法的余数) |
    | copysign | 将第一个数组的符号值改为第二个数组的符号值 |
    | greater,greater_equal,less,less_equal,equal,not_equal | 进行逐个元素的比较,返回布尔值数组(与 数学操作符>. >=. <. <=. ==、!=效果一致) |
    | logical_and,logical_or,logical_xor | 进行逐个元素的逻辑操作(与逻辑操作符&、|、^效果一致) |
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.sqrt(arr)
array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,
       2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])
np.exp(arr)
array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
       5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
       2.98095799e+03, 8.10308393e+03])
x = np.random.randn(8)
y = np.random.randn(8)
x
array([ 0.47558794,  1.76289222, -0.0145971 , -1.11324245, -1.36569064,
        0.4139789 ,  0.63763297, -0.49070227])
y
array([ 0.42249673,  0.4340302 , -0.81489642,  0.03024444,  0.74262733,
       -1.55340271, -1.30271516, -1.38870596])
#numpy.maximum逐个元素地将x和y中元素的最大值计算出来
np.maximum(x,y)
array([ 0.47558794,  1.76289222, -0.0145971 ,  0.03024444,  0.74262733,
        0.4139789 ,  0.63763297, -0.49070227])

4.3 使用数组进行面向数组编程

  • 这种利用数组表达式来替代显式循环的方法,称为向量化。
points = np.arange(-5,5,0.01)
points 
array([-5.0000000e+00, -4.9900000e+00, -4.9800000e+00, -4.9700000e+00,
       -4.9600000e+00, -4.9500000e+00, -4.9400000e+00, -4.9300000e+00,
       -4.9200000e+00, -4.9100000e+00, -4.9000000e+00, -4.8900000e+00,
       -4.8800000e+00, -4.8700000e+00, -4.8600000e+00, -4.8500000e+00,
       -4.8400000e+00, -4.8300000e+00, -4.8200000e+00, -4.8100000e+00,
       -4.8000000e+00, -4.7900000e+00, -4.7800000e+00, -4.7700000e+00,
       -4.7600000e+00, -4.7500000e+00, -4.7400000e+00, -4.7300000e+00,
       -4.7200000e+00, -4.7100000e+00, -4.7000000e+00, -4.6900000e+00,
       -4.6800000e+00, -4.6700000e+00, -4.6600000e+00, -4.6500000e+00,
       -4.6400000e+00, -4.6300000e+00, -4.6200000e+00, -4.6100000e+00,
       -4.6000000e+00, -4.5900000e+00, -4.5800000e+00, -4.5700000e+00,
       -4.5600000e+00, -4.5500000e+00, -4.5400000e+00, -4.5300000e+00,
       -4.5200000e+00, -4.5100000e+00, -4.5000000e+00, -4.4900000e+00,
       -4.4800000e+00, -4.4700000e+00, -4.4600000e+00, -4.4500000e+00,
       -4.4400000e+00, -4.4300000e+00, -4.4200000e+00, -4.4100000e+00,
       -4.4000000e+00, -4.3900000e+00, -4.3800000e+00, -4.3700000e+00,
       -4.3600000e+00, -4.3500000e+00, -4.3400000e+00, -4.3300000e+00,
       -4.3200000e+00, -4.3100000e+00, -4.3000000e+00, -4.2900000e+00,
       -4.2800000e+00, -4.2700000e+00, -4.2600000e+00, -4.2500000e+00,
       -4.2400000e+00, -4.2300000e+00, -4.2200000e+00, -4.2100000e+00,
       -4.2000000e+00, -4.1900000e+00, -4.1800000e+00, -4.1700000e+00,
       -4.1600000e+00, -4.1500000e+00, -4.1400000e+00, -4.1300000e+00,
       -4.1200000e+00, -4.1100000e+00, -4.1000000e+00, -4.0900000e+00,
       -4.0800000e+00, -4.0700000e+00, -4.0600000e+00, -4.0500000e+00,
       -4.0400000e+00, -4.0300000e+00, -4.0200000e+00, -4.0100000e+00,
       -4.0000000e+00, -3.9900000e+00, -3.9800000e+00, -3.9700000e+00,
       -3.9600000e+00, -3.9500000e+00, -3.9400000e+00, -3.9300000e+00,
       -3.9200000e+00, -3.9100000e+00, -3.9000000e+00, -3.8900000e+00,
       -3.8800000e+00, -3.8700000e+00, -3.8600000e+00, -3.8500000e+00,
       -3.8400000e+00, -3.8300000e+00, -3.8200000e+00, -3.8100000e+00,
       -3.8000000e+00, -3.7900000e+00, -3.7800000e+00, -3.7700000e+00,
       -3.7600000e+00, -3.7500000e+00, -3.7400000e+00, -3.7300000e+00,
       -3.7200000e+00, -3.7100000e+00, -3.7000000e+00, -3.6900000e+00,
       -3.6800000e+00, -3.6700000e+00, -3.6600000e+00, -3.6500000e+00,
       -3.6400000e+00, -3.6300000e+00, -3.6200000e+00, -3.6100000e+00,
       -3.6000000e+00, -3.5900000e+00, -3.5800000e+00, -3.5700000e+00,
       -3.5600000e+00, -3.5500000e+00, -3.5400000e+00, -3.5300000e+00,
       -3.5200000e+00, -3.5100000e+00, -3.5000000e+00, -3.4900000e+00,
       -3.4800000e+00, -3.4700000e+00, -3.4600000e+00, -3.4500000e+00,
       -3.4400000e+00, -3.4300000e+00, -3.4200000e+00, -3.4100000e+00,
       -3.4000000e+00, -3.3900000e+00, -3.3800000e+00, -3.3700000e+00,
       -3.3600000e+00, -3.3500000e+00, -3.3400000e+00, -3.3300000e+00,
       -3.3200000e+00, -3.3100000e+00, -3.3000000e+00, -3.2900000e+00,
       -3.2800000e+00, -3.2700000e+00, -3.2600000e+00, -3.2500000e+00,
       -3.2400000e+00, -3.2300000e+00, -3.2200000e+00, -3.2100000e+00,
       -3.2000000e+00, -3.1900000e+00, -3.1800000e+00, -3.1700000e+00,
       -3.1600000e+00, -3.1500000e+00, -3.1400000e+00, -3.1300000e+00,
       -3.1200000e+00, -3.1100000e+00, -3.1000000e+00, -3.0900000e+00,
       -3.0800000e+00, -3.0700000e+00, -3.0600000e+00, -3.0500000e+00,
       -3.0400000e+00, -3.0300000e+00, -3.0200000e+00, -3.0100000e+00,
       -3.0000000e+00, -2.9900000e+00, -2.9800000e+00, -2.9700000e+00,
       -2.9600000e+00, -2.9500000e+00, -2.9400000e+00, -2.9300000e+00,
       -2.9200000e+00, -2.9100000e+00, -2.9000000e+00, -2.8900000e+00,
       -2.8800000e+00, -2.8700000e+00, -2.8600000e+00, -2.8500000e+00,
       -2.8400000e+00, -2.8300000e+00, -2.8200000e+00, -2.8100000e+00,
       -2.8000000e+00, -2.7900000e+00, -2.7800000e+00, -2.7700000e+00,
       -2.7600000e+00, -2.7500000e+00, -2.7400000e+00, -2.7300000e+00,
       -2.7200000e+00, -2.7100000e+00, -2.7000000e+00, -2.6900000e+00,
       -2.6800000e+00, -2.6700000e+00, -2.6600000e+00, -2.6500000e+00,
       -2.6400000e+00, -2.6300000e+00, -2.6200000e+00, -2.6100000e+00,
       -2.6000000e+00, -2.5900000e+00, -2.5800000e+00, -2.5700000e+00,
       -2.5600000e+00, -2.5500000e+00, -2.5400000e+00, -2.5300000e+00,
       -2.5200000e+00, -2.5100000e+00, -2.5000000e+00, -2.4900000e+00,
       -2.4800000e+00, -2.4700000e+00, -2.4600000e+00, -2.4500000e+00,
       -2.4400000e+00, -2.4300000e+00, -2.4200000e+00, -2.4100000e+00,
       -2.4000000e+00, -2.3900000e+00, -2.3800000e+00, -2.3700000e+00,
       -2.3600000e+00, -2.3500000e+00, -2.3400000e+00, -2.3300000e+00,
       -2.3200000e+00, -2.3100000e+00, -2.3000000e+00, -2.2900000e+00,
       -2.2800000e+00, -2.2700000e+00, -2.2600000e+00, -2.2500000e+00,
       -2.2400000e+00, -2.2300000e+00, -2.2200000e+00, -2.2100000e+00,
       -2.2000000e+00, -2.1900000e+00, -2.1800000e+00, -2.1700000e+00,
       -2.1600000e+00, -2.1500000e+00, -2.1400000e+00, -2.1300000e+00,
       -2.1200000e+00, -2.1100000e+00, -2.1000000e+00, -2.0900000e+00,
       -2.0800000e+00, -2.0700000e+00, -2.0600000e+00, -2.0500000e+00,
       -2.0400000e+00, -2.0300000e+00, -2.0200000e+00, -2.0100000e+00,
       -2.0000000e+00, -1.9900000e+00, -1.9800000e+00, -1.9700000e+00,
       -1.9600000e+00, -1.9500000e+00, -1.9400000e+00, -1.9300000e+00,
       -1.9200000e+00, -1.9100000e+00, -1.9000000e+00, -1.8900000e+00,
       -1.8800000e+00, -1.8700000e+00, -1.8600000e+00, -1.8500000e+00,
       -1.8400000e+00, -1.8300000e+00, -1.8200000e+00, -1.8100000e+00,
       -1.8000000e+00, -1.7900000e+00, -1.7800000e+00, -1.7700000e+00,
       -1.7600000e+00, -1.7500000e+00, -1.7400000e+00, -1.7300000e+00,
       -1.7200000e+00, -1.7100000e+00, -1.7000000e+00, -1.6900000e+00,
       -1.6800000e+00, -1.6700000e+00, -1.6600000e+00, -1.6500000e+00,
       -1.6400000e+00, -1.6300000e+00, -1.6200000e+00, -1.6100000e+00,
       -1.6000000e+00, -1.5900000e+00, -1.5800000e+00, -1.5700000e+00,
       -1.5600000e+00, -1.5500000e+00, -1.5400000e+00, -1.5300000e+00,
       -1.5200000e+00, -1.5100000e+00, -1.5000000e+00, -1.4900000e+00,
       -1.4800000e+00, -1.4700000e+00, -1.4600000e+00, -1.4500000e+00,
       -1.4400000e+00, -1.4300000e+00, -1.4200000e+00, -1.4100000e+00,
       -1.4000000e+00, -1.3900000e+00, -1.3800000e+00, -1.3700000e+00,
       -1.3600000e+00, -1.3500000e+00, -1.3400000e+00, -1.3300000e+00,
       -1.3200000e+00, -1.3100000e+00, -1.3000000e+00, -1.2900000e+00,
       -1.2800000e+00, -1.2700000e+00, -1.2600000e+00, -1.2500000e+00,
       -1.2400000e+00, -1.2300000e+00, -1.2200000e+00, -1.2100000e+00,
       -1.2000000e+00, -1.1900000e+00, -1.1800000e+00, -1.1700000e+00,
       -1.1600000e+00, -1.1500000e+00, -1.1400000e+00, -1.1300000e+00,
       -1.1200000e+00, -1.1100000e+00, -1.1000000e+00, -1.0900000e+00,
       -1.0800000e+00, -1.0700000e+00, -1.0600000e+00, -1.0500000e+00,
       -1.0400000e+00, -1.0300000e+00, -1.0200000e+00, -1.0100000e+00,
       -1.0000000e+00, -9.9000000e-01, -9.8000000e-01, -9.7000000e-01,
       -9.6000000e-01, -9.5000000e-01, -9.4000000e-01, -9.3000000e-01,
       -9.2000000e-01, -9.1000000e-01, -9.0000000e-01, -8.9000000e-01,
       -8.8000000e-01, -8.7000000e-01, -8.6000000e-01, -8.5000000e-01,
       -8.4000000e-01, -8.3000000e-01, -8.2000000e-01, -8.1000000e-01,
       -8.0000000e-01, -7.9000000e-01, -7.8000000e-01, -7.7000000e-01,
       -7.6000000e-01, -7.5000000e-01, -7.4000000e-01, -7.3000000e-01,
       -7.2000000e-01, -7.1000000e-01, -7.0000000e-01, -6.9000000e-01,
       -6.8000000e-01, -6.7000000e-01, -6.6000000e-01, -6.5000000e-01,
       -6.4000000e-01, -6.3000000e-01, -6.2000000e-01, -6.1000000e-01,
       -6.0000000e-01, -5.9000000e-01, -5.8000000e-01, -5.7000000e-01,
       -5.6000000e-01, -5.5000000e-01, -5.4000000e-01, -5.3000000e-01,
       -5.2000000e-01, -5.1000000e-01, -5.0000000e-01, -4.9000000e-01,
       -4.8000000e-01, -4.7000000e-01, -4.6000000e-01, -4.5000000e-01,
       -4.4000000e-01, -4.3000000e-01, -4.2000000e-01, -4.1000000e-01,
       -4.0000000e-01, -3.9000000e-01, -3.8000000e-01, -3.7000000e-01,
       -3.6000000e-01, -3.5000000e-01, -3.4000000e-01, -3.3000000e-01,
       -3.2000000e-01, -3.1000000e-01, -3.0000000e-01, -2.9000000e-01,
       -2.8000000e-01, -2.7000000e-01, -2.6000000e-01, -2.5000000e-01,
       -2.4000000e-01, -2.3000000e-01, -2.2000000e-01, -2.1000000e-01,
       -2.0000000e-01, -1.9000000e-01, -1.8000000e-01, -1.7000000e-01,
       -1.6000000e-01, -1.5000000e-01, -1.4000000e-01, -1.3000000e-01,
       -1.2000000e-01, -1.1000000e-01, -1.0000000e-01, -9.0000000e-02,
       -8.0000000e-02, -7.0000000e-02, -6.0000000e-02, -5.0000000e-02,
       -4.0000000e-02, -3.0000000e-02, -2.0000000e-02, -1.0000000e-02,
       -1.0658141e-13,  1.0000000e-02,  2.0000000e-02,  3.0000000e-02,
        4.0000000e-02,  5.0000000e-02,  6.0000000e-02,  7.0000000e-02,
        8.0000000e-02,  9.0000000e-02,  1.0000000e-01,  1.1000000e-01,
        1.2000000e-01,  1.3000000e-01,  1.4000000e-01,  1.5000000e-01,
        1.6000000e-01,  1.7000000e-01,  1.8000000e-01,  1.9000000e-01,
        2.0000000e-01,  2.1000000e-01,  2.2000000e-01,  2.3000000e-01,
        2.4000000e-01,  2.5000000e-01,  2.6000000e-01,  2.7000000e-01,
        2.8000000e-01,  2.9000000e-01,  3.0000000e-01,  3.1000000e-01,
        3.2000000e-01,  3.3000000e-01,  3.4000000e-01,  3.5000000e-01,
        3.6000000e-01,  3.7000000e-01,  3.8000000e-01,  3.9000000e-01,
        4.0000000e-01,  4.1000000e-01,  4.2000000e-01,  4.3000000e-01,
        4.4000000e-01,  4.5000000e-01,  4.6000000e-01,  4.7000000e-01,
        4.8000000e-01,  4.9000000e-01,  5.0000000e-01,  5.1000000e-01,
        5.2000000e-01,  5.3000000e-01,  5.4000000e-01,  5.5000000e-01,
        5.6000000e-01,  5.7000000e-01,  5.8000000e-01,  5.9000000e-01,
        6.0000000e-01,  6.1000000e-01,  6.2000000e-01,  6.3000000e-01,
        6.4000000e-01,  6.5000000e-01,  6.6000000e-01,  6.7000000e-01,
        6.8000000e-01,  6.9000000e-01,  7.0000000e-01,  7.1000000e-01,
        7.2000000e-01,  7.3000000e-01,  7.4000000e-01,  7.5000000e-01,
        7.6000000e-01,  7.7000000e-01,  7.8000000e-01,  7.9000000e-01,
        8.0000000e-01,  8.1000000e-01,  8.2000000e-01,  8.3000000e-01,
        8.4000000e-01,  8.5000000e-01,  8.6000000e-01,  8.7000000e-01,
        8.8000000e-01,  8.9000000e-01,  9.0000000e-01,  9.1000000e-01,
        9.2000000e-01,  9.3000000e-01,  9.4000000e-01,  9.5000000e-01,
        9.6000000e-01,  9.7000000e-01,  9.8000000e-01,  9.9000000e-01,
        1.0000000e+00,  1.0100000e+00,  1.0200000e+00,  1.0300000e+00,
        1.0400000e+00,  1.0500000e+00,  1.0600000e+00,  1.0700000e+00,
        1.0800000e+00,  1.0900000e+00,  1.1000000e+00,  1.1100000e+00,
        1.1200000e+00,  1.1300000e+00,  1.1400000e+00,  1.1500000e+00,
        1.1600000e+00,  1.1700000e+00,  1.1800000e+00,  1.1900000e+00,
        1.2000000e+00,  1.2100000e+00,  1.2200000e+00,  1.2300000e+00,
        1.2400000e+00,  1.2500000e+00,  1.2600000e+00,  1.2700000e+00,
        1.2800000e+00,  1.2900000e+00,  1.3000000e+00,  1.3100000e+00,
        1.3200000e+00,  1.3300000e+00,  1.3400000e+00,  1.3500000e+00,
        1.3600000e+00,  1.3700000e+00,  1.3800000e+00,  1.3900000e+00,
        1.4000000e+00,  1.4100000e+00,  1.4200000e+00,  1.4300000e+00,
        1.4400000e+00,  1.4500000e+00,  1.4600000e+00,  1.4700000e+00,
        1.4800000e+00,  1.4900000e+00,  1.5000000e+00,  1.5100000e+00,
        1.5200000e+00,  1.5300000e+00,  1.5400000e+00,  1.5500000e+00,
        1.5600000e+00,  1.5700000e+00,  1.5800000e+00,  1.5900000e+00,
        1.6000000e+00,  1.6100000e+00,  1.6200000e+00,  1.6300000e+00,
        1.6400000e+00,  1.6500000e+00,  1.6600000e+00,  1.6700000e+00,
        1.6800000e+00,  1.6900000e+00,  1.7000000e+00,  1.7100000e+00,
        1.7200000e+00,  1.7300000e+00,  1.7400000e+00,  1.7500000e+00,
        1.7600000e+00,  1.7700000e+00,  1.7800000e+00,  1.7900000e+00,
        1.8000000e+00,  1.8100000e+00,  1.8200000e+00,  1.8300000e+00,
        1.8400000e+00,  1.8500000e+00,  1.8600000e+00,  1.8700000e+00,
        1.8800000e+00,  1.8900000e+00,  1.9000000e+00,  1.9100000e+00,
        1.9200000e+00,  1.9300000e+00,  1.9400000e+00,  1.9500000e+00,
        1.9600000e+00,  1.9700000e+00,  1.9800000e+00,  1.9900000e+00,
        2.0000000e+00,  2.0100000e+00,  2.0200000e+00,  2.0300000e+00,
        2.0400000e+00,  2.0500000e+00,  2.0600000e+00,  2.0700000e+00,
        2.0800000e+00,  2.0900000e+00,  2.1000000e+00,  2.1100000e+00,
        2.1200000e+00,  2.1300000e+00,  2.1400000e+00,  2.1500000e+00,
        2.1600000e+00,  2.1700000e+00,  2.1800000e+00,  2.1900000e+00,
        2.2000000e+00,  2.2100000e+00,  2.2200000e+00,  2.2300000e+00,
        2.2400000e+00,  2.2500000e+00,  2.2600000e+00,  2.2700000e+00,
        2.2800000e+00,  2.2900000e+00,  2.3000000e+00,  2.3100000e+00,
        2.3200000e+00,  2.3300000e+00,  2.3400000e+00,  2.3500000e+00,
        2.3600000e+00,  2.3700000e+00,  2.3800000e+00,  2.3900000e+00,
        2.4000000e+00,  2.4100000e+00,  2.4200000e+00,  2.4300000e+00,
        2.4400000e+00,  2.4500000e+00,  2.4600000e+00,  2.4700000e+00,
        2.4800000e+00,  2.4900000e+00,  2.5000000e+00,  2.5100000e+00,
        2.5200000e+00,  2.5300000e+00,  2.5400000e+00,  2.5500000e+00,
        2.5600000e+00,  2.5700000e+00,  2.5800000e+00,  2.5900000e+00,
        2.6000000e+00,  2.6100000e+00,  2.6200000e+00,  2.6300000e+00,
        2.6400000e+00,  2.6500000e+00,  2.6600000e+00,  2.6700000e+00,
        2.6800000e+00,  2.6900000e+00,  2.7000000e+00,  2.7100000e+00,
        2.7200000e+00,  2.7300000e+00,  2.7400000e+00,  2.7500000e+00,
        2.7600000e+00,  2.7700000e+00,  2.7800000e+00,  2.7900000e+00,
        2.8000000e+00,  2.8100000e+00,  2.8200000e+00,  2.8300000e+00,
        2.8400000e+00,  2.8500000e+00,  2.8600000e+00,  2.8700000e+00,
        2.8800000e+00,  2.8900000e+00,  2.9000000e+00,  2.9100000e+00,
        2.9200000e+00,  2.9300000e+00,  2.9400000e+00,  2.9500000e+00,
        2.9600000e+00,  2.9700000e+00,  2.9800000e+00,  2.9900000e+00,
        3.0000000e+00,  3.0100000e+00,  3.0200000e+00,  3.0300000e+00,
        3.0400000e+00,  3.0500000e+00,  3.0600000e+00,  3.0700000e+00,
        3.0800000e+00,  3.0900000e+00,  3.1000000e+00,  3.1100000e+00,
        3.1200000e+00,  3.1300000e+00,  3.1400000e+00,  3.1500000e+00,
        3.1600000e+00,  3.1700000e+00,  3.1800000e+00,  3.1900000e+00,
        3.2000000e+00,  3.2100000e+00,  3.2200000e+00,  3.2300000e+00,
        3.2400000e+00,  3.2500000e+00,  3.2600000e+00,  3.2700000e+00,
        3.2800000e+00,  3.2900000e+00,  3.3000000e+00,  3.3100000e+00,
        3.3200000e+00,  3.3300000e+00,  3.3400000e+00,  3.3500000e+00,
        3.3600000e+00,  3.3700000e+00,  3.3800000e+00,  3.3900000e+00,
        3.4000000e+00,  3.4100000e+00,  3.4200000e+00,  3.4300000e+00,
        3.4400000e+00,  3.4500000e+00,  3.4600000e+00,  3.4700000e+00,
        3.4800000e+00,  3.4900000e+00,  3.5000000e+00,  3.5100000e+00,
        3.5200000e+00,  3.5300000e+00,  3.5400000e+00,  3.5500000e+00,
        3.5600000e+00,  3.5700000e+00,  3.5800000e+00,  3.5900000e+00,
        3.6000000e+00,  3.6100000e+00,  3.6200000e+00,  3.6300000e+00,
        3.6400000e+00,  3.6500000e+00,  3.6600000e+00,  3.6700000e+00,
        3.6800000e+00,  3.6900000e+00,  3.7000000e+00,  3.7100000e+00,
        3.7200000e+00,  3.7300000e+00,  3.7400000e+00,  3.7500000e+00,
        3.7600000e+00,  3.7700000e+00,  3.7800000e+00,  3.7900000e+00,
        3.8000000e+00,  3.8100000e+00,  3.8200000e+00,  3.8300000e+00,
        3.8400000e+00,  3.8500000e+00,  3.8600000e+00,  3.8700000e+00,
        3.8800000e+00,  3.8900000e+00,  3.9000000e+00,  3.9100000e+00,
        3.9200000e+00,  3.9300000e+00,  3.9400000e+00,  3.9500000e+00,
        3.9600000e+00,  3.9700000e+00,  3.9800000e+00,  3.9900000e+00,
        4.0000000e+00,  4.0100000e+00,  4.0200000e+00,  4.0300000e+00,
        4.0400000e+00,  4.0500000e+00,  4.0600000e+00,  4.0700000e+00,
        4.0800000e+00,  4.0900000e+00,  4.1000000e+00,  4.1100000e+00,
        4.1200000e+00,  4.1300000e+00,  4.1400000e+00,  4.1500000e+00,
        4.1600000e+00,  4.1700000e+00,  4.1800000e+00,  4.1900000e+00,
        4.2000000e+00,  4.2100000e+00,  4.2200000e+00,  4.2300000e+00,
        4.2400000e+00,  4.2500000e+00,  4.2600000e+00,  4.2700000e+00,
        4.2800000e+00,  4.2900000e+00,  4.3000000e+00,  4.3100000e+00,
        4.3200000e+00,  4.3300000e+00,  4.3400000e+00,  4.3500000e+00,
        4.3600000e+00,  4.3700000e+00,  4.3800000e+00,  4.3900000e+00,
        4.4000000e+00,  4.4100000e+00,  4.4200000e+00,  4.4300000e+00,
        4.4400000e+00,  4.4500000e+00,  4.4600000e+00,  4.4700000e+00,
        4.4800000e+00,  4.4900000e+00,  4.5000000e+00,  4.5100000e+00,
        4.5200000e+00,  4.5300000e+00,  4.5400000e+00,  4.5500000e+00,
        4.5600000e+00,  4.5700000e+00,  4.5800000e+00,  4.5900000e+00,
        4.6000000e+00,  4.6100000e+00,  4.6200000e+00,  4.6300000e+00,
        4.6400000e+00,  4.6500000e+00,  4.6600000e+00,  4.6700000e+00,
        4.6800000e+00,  4.6900000e+00,  4.7000000e+00,  4.7100000e+00,
        4.7200000e+00,  4.7300000e+00,  4.7400000e+00,  4.7500000e+00,
        4.7600000e+00,  4.7700000e+00,  4.7800000e+00,  4.7900000e+00,
        4.8000000e+00,  4.8100000e+00,  4.8200000e+00,  4.8300000e+00,
        4.8400000e+00,  4.8500000e+00,  4.8600000e+00,  4.8700000e+00,
        4.8800000e+00,  4.8900000e+00,  4.9000000e+00,  4.9100000e+00,
        4.9200000e+00,  4.9300000e+00,  4.9400000e+00,  4.9500000e+00,
        4.9600000e+00,  4.9700000e+00,  4.9800000e+00,  4.9900000e+00])
#np.meshgrid函数接收两个一维数组,并根据两个数组的所有(x, y)对生成一个二维矩阵
xs,ys = np.meshgrid(points,points)
xs
array([[-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       ...,
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99]])
ys
array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],
       [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
       [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
       ...,
       [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],
       [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],
       [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])
z = np.sqrt(xs**2+ys**2)
z
array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,
        7.06400028],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       ...,
       [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,
        7.04279774],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568]])
import matplotlib.pyplot as plt
plt.imshow(z)
<matplotlib.image.AxesImage at 0x1e51152feb0>


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2UhfLeQ-1640752034425)(output_399_1.png)]

4.3.1 将条件逻辑作为数组操作

  • numpy.where函数是三元表达式x if condition else y的向量化版本。
  • np.where的第二个和第三个参数并不需要是数组,它们可以是标量。
  • 传递给np.where的数组既可以是同等大小的数组,也可以是标量。
xarr = [1.1,1.2,1.3,1.4,1.5]
yarr = [2.1,2.2,2.3,2.4,2.5]
cond = [False,True,False,False,True]
#假设cond中的元素为True时,我们取xarr中的对应元素值,否则取yarr中的元素
result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
result
#首先,如果数组很大的话,速度会很慢(因为所有的工作都是通过解释器解释Python代码完成)。其次,当数组是多维时,就无法凑效了。
[2.1, 1.2, 2.3, 2.4, 1.5]
result = np.where(cond,xarr,yarr)
result 
array([2.1, 1.2, 2.3, 2.4, 1.5])
arr = np.random.randn(4,4)
arr
array([[ 0.0279815 , -0.03226408,  0.86484912, -0.08501145],
       [ 0.98888936, -0.79318502,  0.23349129,  0.5547258 ],
       [ 0.33158546,  0.31742717, -1.59492796,  0.29142641],
       [ 0.33042836, -1.78994005,  0.11780007, -1.47899861]])
result = np.where(arr<0,arr,2)
result
array([[ 2.        , -0.03226408,  2.        , -0.08501145],
       [ 2.        , -0.79318502,  2.        ,  2.        ],
       [ 2.        ,  2.        , -1.59492796,  2.        ],
       [ 2.        , -1.78994005,  2.        , -1.47899861]])
result = np.where(arr<0,-2,2)
result
array([[ 2, -2,  2, -2],
       [ 2, -2,  2,  2],
       [ 2,  2, -2,  2],
       [ 2, -2,  2, -2]])
#你可以使用np.where将标量和数组联合
np.where(arr<0,2,arr)
array([[0.0279815 , 2.        , 0.86484912, 2.        ],
       [0.98888936, 2.        , 0.23349129, 0.5547258 ],
       [0.33158546, 0.31742717, 2.        , 0.29142641],
       [0.33042836, 2.        , 0.11780007, 2.        ]])

4.3.2 数学和统计方法

  • 聚合函数(通常也叫缩减函数)
  • 既可以直接调用数组实例的方法,也可以使用顶层的NumPy函数。
  • 像mean、sum等函数可以接收一个可选参数axis
  • cumsum和cumprod并不会聚合,它们会产生一个中间结果
  • 基础数组统计方法
    | 方法|描述|
    | ---- | ---- |
    | sum | 沿着轴向计算所有元素的累和,0长度的数组,累和为0|
    | mean| 数学平均,0长度的数组平均值为NaN|
    | std,var |标准差和方差,可以选择自由度调整(默认分母是n)|
    | min,max|最小值和最大值|
    | argmin, argmax|最小值和最大值的位置|
arr = np.arange(12).reshape(3,4)
arr
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
arr.mean()
5.5
np.mean(arr)
5.5
arr.sum()
66
np.sum(arr)
66
#像mean、sum等函数可以接收一个可选参数axis(这里书上面说法有问题)
#arr.mean(1)表示“计算每一行的平均值”
arr.mean(axis = 1)
array([1.5, 5.5, 9.5])
arr.mean(1)
array([1.5, 5.5, 9.5])
#arr.sum(0)表示“计算每一列的累和”
arr.sum(axis = 0)
array([12, 15, 18, 21])
arr.sum(0)
array([12, 15, 18, 21])
#cumsum和cumprod并不会聚合,它们会产生一个中间结果
arr = np.array([1,2,3,4,5,6,7])
arr.cumsum()
array([ 1,  3,  6, 10, 15, 21, 28], dtype=int32)
arr.cumprod()
array([   1,    2,    6,   24,  120,  720, 5040], dtype=int32)
#cumsum这样的累积函数返回相同长度的数组,但是可以在指定轴向上根据较低维度的切片进行部分聚合
arr = np.array([[1,2,3],[4,5,6]])
arr
array([[1, 2, 3],
       [4, 5, 6]])
arr.cumsum(1)
array([[ 1,  3,  6],
       [ 4,  9, 15]], dtype=int32)
arr.cumsum(0)
array([[1, 2, 3],
       [5, 7, 9]], dtype=int32)

4.3.3 布尔值数组的方法

  • 布尔值会被强制为1(True)和0(False)。因此,sum通常可以用于计算布尔值数组中的True的个数
  • 对于布尔值数组,有两个非常有用的方法any和all。any检查数组中是否至少有一个True,而all检查是否每个值都是True
#正数个数
arr = np.random.randn(100)
(arr>0).sum()
49
bools = np.array([False,True,False,True])
#any检查数组中是否至少有一个True
bools.any()
True
#all检查是否每个值都是True
bools.all()
False

4.3.4 排序

  • 和Python的内建列表类型相似,NumPy数组可以使用sort方法按位置排序
  • 顶层的np.sort方法返回的是已经排序好的数组拷贝,而不是对原数组按位置排序。
arr = np.random.randn(6)
arr
array([-0.09465593,  0.48442829, -0.80286736,  0.29244109, -0.31614414,
       -0.4904135 ])
arr.sort()
arr
array([-0.80286736, -0.4904135 , -0.31614414, -0.09465593,  0.29244109,
        0.48442829])
#可以在多维数组中根据传递的axis值,沿着轴向对每个一维数据段进行排序
arr = np.random.randn(5,3)
arr
array([[ 0.73589519, -0.25249415, -0.18110702],
       [ 0.18183926,  0.36041412, -1.20684446],
       [ 0.16825528, -0.55328778,  0.77363473],
       [-2.38287785, -0.04767401, -0.22954949],
       [-0.49612544,  1.74657401,  0.02651629]])
arr.sort()
arr
array([[-0.25249415, -0.18110702,  0.73589519],
       [-1.20684446,  0.18183926,  0.36041412],
       [-0.55328778,  0.16825528,  0.77363473],
       [-2.38287785, -0.22954949, -0.04767401],
       [-0.49612544,  0.02651629,  1.74657401]])
arr.sort(1)
arr
array([[-0.25249415, -0.18110702,  0.73589519],
       [-1.20684446,  0.18183926,  0.36041412],
       [-0.55328778,  0.16825528,  0.77363473],
       [-2.38287785, -0.22954949, -0.04767401],
       [-0.49612544,  0.02651629,  1.74657401]])
arr.sort(0)
arr
array([[-2.38287785, -0.22954949, -0.04767401],
       [-1.20684446, -0.18110702,  0.36041412],
       [-0.55328778,  0.02651629,  0.73589519],
       [-0.49612544,  0.16825528,  0.77363473],
       [-0.25249415,  0.18183926,  1.74657401]])
#下面的例子计算的是一个数组的分位数,并选出分位数所对应的值,这是一种应急的方式
large_arr = np.random.randn(1000)
large_arr.sort()
large_arr[int(len(large_arr)*0.05)]
-1.667884606593057

4.3.5 唯一值与其他集合逻辑

  • np.unique,返回的是数组中唯一值排序后形成的数组
  • np.in1d,可以检查一个数组中的值是否在另外一个数组中,并返回一个布尔值数组
  • 数组的集合操作
    | 方法|描述|
    | ---- | ---- |
    |intersect1d(x, y)|计算x和y的交集,并排序|
    |union1d(x, y)|计算x和y的并集,并排序|
    |in1d(x, y)|计算x中的元素是否包含在y中,返回一个布尔值数组|
    |setdiff1d(x, y) |差集,在x中但不在y中的x的元素|
    |setxor1d(x, y)|异或集,在x或y中,但不属于x、y交集的元素|
#np.unique,返回的是数组中唯一值排序后形成的数组
names = np.array(["Bob","Joe","Will","Bob","Will","Bob","Bob"])
np.unique(names)
array(['Bob', 'Joe', 'Will'], dtype='<U4')
ints = np.array([3,3,3,4,4,2,2,1])
np.unique(ints)
array([1, 2, 3, 4])
#将np.unique和纯Python实现相比较
sorted(set(ints))
[1, 2, 3, 4]
#np.in1d,可以检查一个数组中的值是否在另外一个数组中,并返回一个布尔值数组
values = np.array([6,0,0,2,3,5,6])
np.in1d(values,[6,5])
array([ True, False, False, False, False,  True,  True])

4.4 使用数组进行文件输入和输出

  • NumPy可以在硬盘中将数据以文本或二进制文件的形式进行存入硬盘或由硬盘载入。
  • np.save和np.load是高效存取硬盘数据的两大工具函数。数组在默认情况下是以未压缩的格式进行存储的,后缀名是.npy
#如果文件存放路径中没写.npy时,后缀名会被自动加上
arr = np.arange(10)
np.save('some_array',arr)
np.load('some_array.npy')
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.savez('array_archive.npz',a = arr,b = arr)
#当载入一个.npy文件的时候,你会获得一个字典型的对象,并通过该对象很方便地载入单个数组
arch = np.load('array_archive.npz')
arch['b']
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#使用numpy.savez_compressed将数据存入已经压缩的文件
np.savez_compressed('arrays_compressed.npz',a = arr,b = arr)

4.5 线性代数

  • x.dot(y)等价于np.dot(x, y)
  • 特殊符号@也作为中缀操作符,用于点乘矩阵操作
  • 常用numpy.linalg函数
    | 方法|描述|
    | ---- | ---- |
    |diag|将一个方阵的对角(或非对角)元素作为一维数组返回,或者将一维数组转换成一个方阵,并且在非对角线上有零点|
    |dot|矩阵点乘|
    |trace|计算对角元素和|
    |det|计算矩阵的行列式|
    |eig|计算方阵的特征值和特征向量|
    |inv|计算方阵的逆矩阵|
    |pinv|计算矩阵的Moore-Penrose伪逆|
    |qr|计算QR分解|
    |svd|计算奇异值分解(SVD)|
    |solve|求解x的线性系统Ax = b,其中A是方阵|
    |lstsq|计算Ax = b的最小二乘解|
x = np.array([[1,2,3],[4,5,6]])
y = np.array([[6,23],[-1,7],[8,9]])
x 
array([[1, 2, 3],
       [4, 5, 6]])
y
array([[ 6, 23],
       [-1,  7],
       [ 8,  9]])
x.dot(y)
array([[ 28,  64],
       [ 67, 181]])
#x.dot(y)等价于np.dot(x, y)
np.dot(x, y)
array([[ 28,  64],
       [ 67, 181]])
#一个二维数组和一个长度合适的一维数组之间的矩阵乘积,其结果是一个一维数组
np.dot(x,np.ones(3))
array([ 6., 15.])
np.dot(x,np.zeros(3))
array([0., 0.])
#特殊符号@也作为中缀操作符,用于点乘矩阵操作
x @ np.ones(3)
array([ 6., 15.])

4.6 伪随机数生成

  • numpy.random模块填补了Python内建的random模块的不足,可以高效地生成多种概率分布下的完整样本值数组。
  • 可以通过np.random.seed更改NumPy的随机数种子
  • numpy.random中的部分函数列表
#使用normal来获得一个4×4的正态分布样本数组
samples = np.random.normal(size = (4,4))
samples
array([[ 0.5380071 ,  0.47450501,  0.03845957, -1.02357224],
       [ 0.03490259, -0.84530932,  1.13398569, -1.19187065],
       [ 1.48156032,  0.46925679, -0.38656015, -1.01776325],
       [ 0.44296535, -0.47960224, -1.46982352,  0.45302383]])
#你可以通过np.random.seed更改NumPy的随机数种子
np.random.seed(1234)
#为了避免全局状态,你可以使用numpy.random.RandomState生成一个随机数生成器,使数据独立于其他的随机数状态
rng = np.random.RandomState(1234)
rng.randn(10)
array([ 0.47143516, -1.19097569,  1.43270697, -0.3126519 , -0.72058873,
        0.88716294,  0.85958841, -0.6365235 ,  0.01569637, -2.24268495])

4.7 示例:随机漫步

  • 随机漫步的模拟(https://en.wikipedia.org/wiki/Random_walk)提供了一个使用数组操作的说明性应用。

4.8 本章小结

#首先,让我们考虑一个简单的随机漫步,从0开始,步进为1和-1,且两种步进发生的概率相等。
import random 
position = 0
walk = [position]
steps = 1000
for i in range(steps):
    step = 1 if random.randint(0,1) else - 1
    position += step
    walk.append(position)
import matplotlib.pyplot as plt 
plt.plot(walk[:100])
[<matplotlib.lines.Line2D at 0x1b53b2efbb0>]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NoOsBTm-1640752034425)(output_464_1.png)]

第五章 pandas入门

  • 最大的不同在于pandas是用来处理表格型或异质型数据的。而NumPy则相反,它更适合处理同质型的数值类数组数据。
  • 还可以方便地从本地命名空间中导入Series和DataFrame,它们是常用的类
import pandas as pd
from pandas import Series,DataFrame

5.1 pandas数据结构介绍

5.1.1 Series

  • Series是一种一维的数组型对象,它包含了一个值序列(与NumPy中的类型相似),并且包含了数据标签,称为索引(index)
  • 交互式环境中Series的字符串表示,索引在左边,值在右边
  • 默认生成的索引是从0到N-1(N是数据的长度)
  • 通过values属性和index属性分别获得Series对象的值和索引
  • 通常需要创建一个索引序列,用标签标识每个数据点
  • 与NumPy的数组相比,你可以在从数据中选择数据的时候使用标签来进行索引
  • pandas中使用isnull和notnull函数来检查缺失数据
obj = pd.Series([4,7,-5,3])
obj
0    4
1    7
2   -5
3    3
dtype: int64
#与range(4)相似
obj.index
RangeIndex(start=0, stop=4, step=1)
#注意需要加上s,并且不用加括号
obj.values
array([ 4,  7, -5,  3], dtype=int64)
#通常需要创建一个索引序列,用标签标识每个数据点
obj2 = pd.Series([4,7,-5,3],index = ["a","b","c","d"])
obj2
a    4
b    7
c   -5
d    3
dtype: int64
obj2.index
Index(['a', 'b', 'c', 'd'], dtype='object')
#与NumPy的数组相比,你可以在从数据中选择数据的时候使用标签来进行索引
obj2["b"]
7
#['c', 'a', 'd']包含的不是数字而是字符串,作为索引列表
obj2[['c', 'a', 'd']]
c   -5
a    4
d    3
dtype: int64
obj2[obj2>0]
a    4
b    7
d    3
dtype: int64
np.exp(obj2)
a      54.598150
b    1096.633158
c       0.006738
d      20.085537
dtype: float64
#可以认为它是一个长度固定且有序的字典,因为它将索引值和数据值按位置配对
'b' in obj2
True
'f' in obj2
False
#如果你已经有数据包含在Python字典中,你可以使用字典生成一个Series
sdata = {"ohin":3500,"Texs":2000,"orenge":9000}
obj3 = pd.Series(sdata)
obj3
ohin      3500
Texs      2000
orenge    9000
dtype: int64
#对应的值是NaN(not a number),这是pandas中标记缺失值或NA值的方式。
states = ["California","ohin","Texs"]
obj4 = pd.Series(sdata,states)
obj4
California       NaN
ohin          3500.0
Texs          2000.0
dtype: float64
#pandas中使用isnull和notnull函数来检查缺失数据
pd.isnull(obj4)
California     True
ohin          False
Texs          False
dtype: bool
pd.notnull(obj4)
California    False
ohin           True
Texs           True
dtype: bool
obj4.isnull()
California     True
ohin          False
Texs          False
dtype: bool
obj4.notnull()
California    False
ohin           True
Texs           True
dtype: bool
#在数学操作中自动对齐索引是Series的一个非常有用的特性
obj3
ohin      3500
Texs      2000
orenge    9000
dtype: int64
obj4
California       NaN
ohin          3500.0
Texs          2000.0
dtype: float64
#如果你有数据库经验,你可以认为这个特性与数据库的join操作是非常相似的
obj3+obj4
California       NaN
Texs          4000.0
ohin          7000.0
orenge           NaN
dtype: float64
#Series对象自身和其索引都有name属性,这个特性与pandas其他重要功能集成在一起
obj4.name = "population"
obj4
California       NaN
ohin          3500.0
Texs          2000.0
Name: population, dtype: float64
obj4.index.name = "states"
obj4
states
California       NaN
ohin          3500.0
Texs          2000.0
Name: population, dtype: float64
#Series的索引可以通过按位置赋值的方式进行改变
obj
0    4
1    7
2   -5
3    3
dtype: int64
obj.index = ['Bob','Jef','Steve','Robot']
obj
Bob      4
Jef      7
Steve   -5
Robot    3
dtype: int64

5.1.2 DataFrame

  • DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值、字符串、布尔值等)。
  • DataFrame既有行索引也有列索引,它可以被视为一个共享相同索引的Series的字典。
  • DataFrame构造函数的有效输入
    | 方法|描述|
    | ---- | ---- |
    |2D ndarray|数据的矩阵,行和列的标签是可选参数|
    |数组、列表和元组构成的字典|每个序列成为DataFrame的一列,所有的序列必须长度相等|
    |NumPy结构化/记录化数组|与数组构成的字典一致
    |Series构成的字典|每个值成为一列,每个Series的索引联合起来形成结果的行索引,也可以显式地传递索引|
    |字典构成的字典|每一个内部字典成为一列,键联合起来形成结果的行索引|
    |字典或Series构成的列表|列表中的一个元素形成DataFrame的一行,字典键或Series索引联合起来形成DataFrame的列标签|
    |列表或元组构成的列表|与2D ndarray的情况-致|
    |其他DataFrame|如果不显示传递索引,则会使用原DataFrame的索引|
    |NumPy MaskedArray|与2D ndarray的情况类似,但隐蔽值会在结果DataFrame中成为NA/缺失值|
#有多种方式可以构建DataFrame,其中最常用的方式是利用包含等长度列表或NumPy数组的字典来形成DataFrame
#产生的DataFrame会自动为Sereies分配索引,并且列会按照排序的顺序排列
#如果你使用的是Jupyter notebook, pandas的DataFrame对象将会展示为一个对浏览器更为友好的HTML表格
data = { 'states':['ohio','ohio','ohio','Nevada','Nevada','Nevada']
        ,'year':[2001,2002,2003,2004,2005,2006]
        ,'pop':[1.5,1.7,2.3,3.6,2.9,3.2]   
        }
fram = pd.DataFrame(data)
fram
statesyearpop
0ohio20011.5
1ohio20021.7
2ohio20032.3
3Nevada20043.6
4Nevada20052.9
5Nevada20063.2
#对于大型DataFrame, head方法将会只选出头部的五行
fram.head()
statesyearpop
0ohio20011.5
1ohio20021.7
2ohio20032.3
3Nevada20043.6
4Nevada20052.9
#如果你指定了列的顺序,DataFrame的列将会按照指定顺序排列
pd.DataFrame(data,columns = ['year','pop','states'])
yearpopstates
020011.5ohio
120021.7ohio
220032.3ohio
320043.6Nevada
420052.9Nevada
520063.2Nevada
#如果你传的列不包含在字典中,将会在结果中出现缺失值
fram2 = pd.DataFrame(data,columns = ['year','pop','states','debt'],index = ['one','two','three','four','five','six'])
fram2
yearpopstatesdebt
one20011.5ohioNaN
two20021.7ohioNaN
three20032.3ohioNaN
four20043.6NevadaNaN
five20052.9NevadaNaN
six20063.2NevadaNaN
#DataFrame中的一列,可以按字典型标记或属性那样检索为Series
fram2['states']
one        ohio
two        ohio
three      ohio
four     Nevada
five     Nevada
six      Nevada
Name: states, dtype: object
#在IPython中,属性型连接(比如frame2.year)和列名的tab补全是非常方便的。
#frame2[colunm]对于任意列名均有效,但是frame2.column只在列名是有效的Python变量名时有效。
#请注意,返回的Series与原DataFrame有相同的索引,且Series的name属性也会被合理地设置。
fram2.year
one      2001
two      2002
three    2003
four     2004
five     2005
six      2006
Name: year, dtype: int64
#行也可以通过位置或特殊属性loc进行选取
fram2.loc['three']
year      2003
pop        2.3
states    ohio
debt       NaN
Name: three, dtype: object
#列的引用是可以修改的
fram2['debt'] = 16.5
fram2
yearpopstatesdebt
one20011.5ohio16.5
two20021.7ohio16.5
three20032.3ohio16.5
four20043.6Nevada16.5
five20052.9Nevada16.5
six20063.2Nevada16.5
fram2['debt'] = np.arange(6.0)
fram2
yearpopstatesdebt
one20011.5ohio0.0
two20021.7ohio1.0
three20032.3ohio2.0
four20043.6Nevada3.0
five20052.9Nevada4.0
six20063.2Nevada5.0
#当你将列表或数组赋值给一个列时,值的长度必须和DataFrame的长度相匹配。如果你将Series赋值给一列时,
#Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值
val = pd.Series([-1.2,-1.5,-1.7],index = ['one','four','five'])
fram2['debt'] = val
fram2
yearpopstatesdebt
one20011.5ohio-1.2
two20021.7ohioNaN
three20032.3ohioNaN
four20043.6Nevada-1.5
five20052.9Nevada-1.7
six20063.2NevadaNaN
#del关键字可以像在字典中那样对DataFrame删除列
#frame2.eastern的语法无法创建新的列。
fram2['eastern'] = fram2.states == 'ohio'
fram2
yearpopstatesdebteastern
one20011.5ohio-1.2True
two20021.7ohioNaNTrue
three20032.3ohioNaNTrue
four20043.6Nevada-1.5False
five20052.9Nevada-1.7False
six20063.2NevadaNaNFalse
del fram2['eastern']
#从DataFrame中选取的列是数据的视图,而不是拷贝。因此,对Series的修改会映射到DataFrame中。如果需要复制,则应当显式地使用Series的copy方法
fram2.columns
Index(['year', 'pop', 'states', 'debt'], dtype='object')
#另一种常用的数据形式是包含字典的嵌套字典
pop = { 'Nevada':{2001:2.4,2002:2.9},
       'ohio':{2000:1.5,2001:1.7,2002:3.6}}
fram3 = pd.DataFrame(pop)
fram3
Nevadaohio
20012.41.7
20022.93.6
2000NaN1.5
#可以将使用类似NumPy的语法对DataFrame进行转置操作(调换行和列)
fram3.T
200120022000
Nevada2.42.9NaN
ohio1.73.61.5
#内部字典的键被联合、排序后形成了结果的索引。如果已经显式指明索引的话,内部字典的键将不会被排序
fram4 = pd.DataFrame(pop,index = [2001,2002,2003])
fram4
Nevadaohio
20012.41.7
20022.93.6
2003NaNNaN
#包含Series的字典也可以用于构造DataFrame
pdata = { 'Nevada':fram3['Nevada'][:-1],
       'ohio':fram3['ohio'][:-2]}
pd.DataFrame(pdata)
Nevadaohio
20012.41.7
20022.9NaN
#如果DataFrame的索引和列拥有name属性,则这些name属性也会被显示
fram3.index.name = 'year'
fram3.columns.name = 'state'
fram3
stateNevadaohio
year
20012.41.7
20022.93.6
2000NaN1.5
#和Series类似,DataFrame的values属性会将包含在DataFrame中的数据以二维ndarray的形式返回
fram3.values
array([[2.4, 1.7],
       [2.9, 3.6],
       [nan, 1.5]])
#如果DataFrame的列是不同的dtypes,则values的dtype会自动选择适合所有列的类型
fram2.values
array([[2001, 1.5, 'ohio', -1.2],
       [2002, 1.7, 'ohio', nan],
       [2003, 2.3, 'ohio', nan],
       [2004, 3.6, 'Nevada', -1.5],
       [2005, 2.9, 'Nevada', -1.7],
       [2006, 3.2, 'Nevada', nan]], dtype=object)

5.1.3 索引对象

  • 根据重复标签进行筛选,会选取所有重复标签对应的数据。每个索引都有一些集合逻辑的方法和属性,这些方法和属性解决了关于它所包含的数据的其他常见问题
    | 方法|描述|
    | ---- | ---- |
    |append|将额外的索引对象粘贴到原索引后,产生一个新的索引|
    |difference|计算两个索引的差集|
    |intersection|计算两个索引的交集|
    |union|计算两个索引的并集|
    |isin|计算表示每一个值是否在传值容器中的布尔数组|
    |delete|将位置i的元素删除,并产生新的索引|
    |drop|根据传参删除指定索引值,并产生新的索引|
    |insert|在位置i插入元素,并产生新的索引
    |is_ monotonic|如果索引序列递增则返回True|
    |is_ unique|如果索引序列唯一则返回True|
    |unique|计算索引的唯-值序列|
obj = pd.Series(range(3),index = ['a','b','c'])
index = obj.index
index
Index(['a', 'b', 'c'], dtype='object')
index[1:]
Index(['b', 'c'], dtype='object')
#索引对象是不可变的,因此用户是无法修改索引对象的
index[1] = 'd'
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-45-64cad221b87a> in <module>
      1 #索引对象是不可变的,因此用户是无法修改索引对象的
----> 2 index[1] = 'd'


D:\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in __setitem__(self, key, value)
   4275     @final
   4276     def __setitem__(self, key, value):
-> 4277         raise TypeError("Index does not support mutable operations")
   4278 
   4279     def __getitem__(self, key):


TypeError: Index does not support mutable operations
#不变性使得在多种数据结构中分享索引对象更为安全
labels = pd.Index(np.arange(3))
labels
Int64Index([0, 1, 2], dtype='int64')
obj2 = pd.Series([1.56,2.0,3.4],index = labels)
obj2
0    1.56
1    2.00
2    3.40
dtype: float64
obj2.index is labels
True
#除了类似数组,索引对象也像一个固定大小的集合
fram3.columns
Index(['Nevada', 'ohio'], dtype='object', name='state')
'ohio' in fram3.columns
True
2003 in fram3.columns
False
#与Python集合不同,pandas索引对象可以包含重复标签
dup_labels = ['foo','foo','bar','bar']
dup_labels
['foo', 'foo', 'bar', 'bar']

5.2 基本功能

5.2.1 重建索引

#reindex是pandas对象的重要方法,该方法用于创建一个符合新索引的新对象
obj = pd.Series([1.2,1.5,2.7,2.9],index = ['d','b','a','c'])
obj
d    1.2
b    1.5
a    2.7
c    2.9
dtype: float64
#Series调用reindex方法时,会将数据按照新的索引进行排列,如果某个索引值之前并不存在,则会引入缺失值
obj.reindex(['a','b','c','d','e'])
a    2.7
b    1.5
c    2.9
d    1.2
e    NaN
dtype: float64
#method可选参数允许我们使用诸如ffill等方法在重建索引时插值,ffill方法会将值前向填充
obj3 = pd.Series(['blue','purple','yellow'],index =[0,2,4])
obj3 
0      blue
2    purple
4    yellow
dtype: object
obj3.reindex(range(6),method = 'ffill')
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object
#在DataFrame中,reindex可以改变行索引、列索引,也可以同时改变二者。当仅传入一个序列时,结果中的行会重建索引
frame = pd.DataFrame(np.arange(9).reshape(3,3),
                    index = ['a','b','c'],
                   columns=['ohio','Texas','California'])
frame
ohioTexasCalifornia
a012
b345
c678
fram2 = frame.reindex(['a','b','c','d'])
fram2
ohioTexasCalifornia
a0.01.02.0
b3.04.05.0
c6.07.08.0
dNaNNaNNaN
#列可以使用columns关键字重建索引
states = ['Texas','Utah','California']
frame.reindex(columns = states,copy=False)
frame
ohioTexasCalifornia
a012
b345
c678
#我们更深入地探索时,你可以使用loc进行更为简洁的标签索引,许多用户更倾向于使用这种方式
frame.loc[['a','b'],['Texas','California']]
TexasCalifornia
a12
b45

5.2.2 轴向上删除条目

obj = pd.Series(np.arange(5.0),index = ['a','b','c','d','e'])
obj
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64
new_obj = obj.drop('c')
new_obj
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64
obj.drop(['d','e'])
a    0.0
b    1.0
c    2.0
dtype: float64
#在DataFrame中,索引值可以从轴向上删除
data = pd.DataFrame(np.arange(16).reshape(4,4),
                   index = ['Texas','Utah','California','New work'],
                   columns = ['one','two','three','four'])
data
onetwothreefour
Texas0123
Utah4567
California891011
New work12131415
#在调用drop时使用标签序列会根据行标签删除值(轴0)
data.drop(['Utah','Texas'])
onetwothreefour
California891011
New work12131415
#你可以通过传递axis=1或axis='columns’来从列中删除值
data.drop('two',axis=1)
onethreefour
Texas023
Utah467
California81011
New work121415
data.drop(['two','four'],axis='columns')
onethree
Texas02
Utah46
California810
New work1214
#很多函数,例如drop,会修改Series或DataFrame的尺寸或形状,这些方法直接操作原对象而不返回新对象
obj.drop('c',inplace = True)
obj
d    1.2
b    1.5
a    2.7
dtype: float64

5.2.3 索引、选择与过滤

  • Series的索引(obj[…])与NumPy数组索引的功能类似,只不过Series的索引值可以不仅仅是整数。
obj = pd.Series(np.arange(4.0),index = ['a','b','c','d'])
obj
a    0.0
b    1.0
c    2.0
d    3.0
dtype: float64
obj['b']
1.0
obj[1]
1.0
obj[2:4]
c    2.0
d    3.0
dtype: float64
obj[['b','a','d']]
b    1.0
a    0.0
d    3.0
dtype: float64
obj[[1,3]]
b    1.0
d    3.0
dtype: float64
obj[obj < 2]
a    0.0
b    1.0
dtype: float64
#普通的Python切片中是不包含尾部的,Series的切片与之不同
obj['b':'c']
b    1.0
c    2.0
dtype: float64
#使用这些方法设值时会修改Series相应的部分
obj['b':'c'] = 5
obj
a    0.0
b    5.0
c    5.0
d    3.0
dtype: float64
#使用单个值或序列,可以从DataFrame中索引出一个或多个列
data = pd.DataFrame(np.arange(16).reshape(4,4),
                   index = ['Texas','Utah','California','New work'],
                   columns = ['one','two','three','four'])
data
onetwothreefour
Texas0123
Utah4567
California891011
New work12131415
data['two']
Texas          1
Utah           5
California     9
New work      13
Name: two, dtype: int32
data[['three','one']]
threeone
Texas20
Utah64
California108
New work1412
#可以根据一个布尔值数组切片或选择数据
#行选择语法data[:2]非常方便。传递单个元素或一个列表到[]符号中可以选择列
data[:2]
onetwothreefour
Texas0123
Utah4567
data[data['three']>5]
onetwothreefour
Utah4567
California891011
New work12131415
data < 5
onetwothreefour
TexasTrueTrueTrueTrue
UtahTrueFalseFalseFalse
CaliforniaFalseFalseFalseFalse
New workFalseFalseFalseFalse
data[data < 5] = 0
data
onetwothreefour
Texas0000
Utah0567
California891011
New work12131415
5.2.3.1 使用loc和iloc选择数据
  • 针对DataFrame在行上的标签索引,我将介绍特殊的索引符号loc和iloc。
  • 他们允许你使用轴标签(loc)或整数标签(iloc)以NumPy风格的语法从DataFrame中选出数组的行和列的子集。
data
onetwothreefour
Texas0000
Utah0567
California891011
New work12131415
data.loc['New work',['one','four']]
one     12
four    15
Name: New work, dtype: int32
data.iloc[3,[0,3]]
one     12
four    15
Name: New work, dtype: int32
#除了单个标签或标签列表之外,索引功能还可以用于切片
data.loc[:'New work',['one','four']]
onefour
Texas00
Utah07
California811
New work1215
data.iloc[:3,[0,3]]
onefour
Texas00
Utah07
California811

5.2.4 整数索引

  • 为了更精确地处理,可以使用loc(用于标签)或iloc(用于整数)
ser = pd.Series(np.arange(3.0))
ser
0    0.0
1    1.0
2    2.0
dtype: float64
ser[:1]
0    0.0
dtype: float64
ser.loc[:0]
0    0.0
dtype: float64
ser.iloc[:1]
0    0.0
dtype: float64

5.2.5 算术和数据对齐

s1 = pd.Series([1.2,1.7,0.3,5.6],index = ['a','c','d','e'])
s2 = pd.Series([2.3,2.6,2.9,3.0],index = ['a','d','f','g'])
s1
a    1.2
c    1.7
d    0.3
e    5.6
dtype: float64
s2
a    2.3
d    2.6
f    2.9
g    3.0
dtype: float64
s1+s2
a    3.5
c    NaN
d    2.9
e    NaN
f    NaN
g    NaN
dtype: float64
df1 = pd.DataFrame(np.arange(9.0).reshape(3,3),columns=list('bcd'),
                  index = ['ohio','Texas','Colorado'])

df2 = pd.DataFrame(np.arange(12.0).reshape(4,3),columns=list('bde'),
                  index = ['Utah','ohio','Texas','Oregon'])
df1
bcd
ohio0.01.02.0
Texas3.04.05.0
Colorado6.07.08.0
df2
bde
Utah0.01.02.0
ohio3.04.05.0
Texas6.07.08.0
Oregon9.010.011.0
#由于’c’列和’e’列并不是两个DataFrame共有的列,这两列中产生了缺失值。对于行标签不同的DataFrame对象也是如此。
df1+df2
bcde
ColoradoNaNNaNNaNNaN
OregonNaNNaNNaNNaN
Texas9.0NaN12.0NaN
UtahNaNNaNNaNNaN
ohio3.0NaN6.0NaN
#如果你将两个行或列完全不同的DataFrame对象相加,结果将全部为空
df1 = pd.DataFrame({'A':[1,2]})
df2 = pd.DataFrame({'B':[3,4]})
df1
A
01
12
df2
B
03
14
df1 - df2
AB
0NaNNaN
1NaNNaN
5.2.5.1 使用填充值的算术方法
  • 在两个不同的索引化对象之间进行算术操作时,你可能会想要使用特殊填充值,比如当轴标签在一个对象中存在,在另一个对象中不存在时,你想将缺失值填充为0
  • 灵活算术方法
    |方法|描述|
    |—|---|
    |add, radd|加法(+)|
    |sub, rsub|减法()|
    |div, rdiv|除法()|
    |floordiv, rfloordiv|整除(/)|
    |mul, rmul|乘法(*)|
    |pow, rpow|幂次方(**)|
df1 = pd.DataFrame(np.arange(12.).reshape(3,4),columns=list('abcd'))
df1
abcd
00.01.02.03.0
14.05.06.07.0
28.09.010.011.0
df2 = pd.DataFrame(np.arange(20.).reshape(4,5),columns=list('abcde'))
df2
abcde
00.01.02.03.04.0
15.06.07.08.09.0
210.011.012.013.014.0
315.016.017.018.019.0
df2.loc[1,'b'] = np.nan
df2
abcde
00.01.02.03.04.0
15.0NaN7.08.09.0
210.011.012.013.014.0
315.016.017.018.019.0
df1+df2
abcde
00.02.04.06.0NaN
19.0NaN13.015.0NaN
218.020.022.024.0NaN
3NaNNaNNaNNaNNaN
#在df1上使用add方法,我将df2和一个fill_value作为参数传入
df1.add(df2,fill_value=0)
abcde
00.02.04.06.04.0
19.05.013.015.09.0
218.020.022.024.014.0
315.016.017.018.019.0
#这些方法中的每一个都有一个以r开头的副本,这些副本方法的参数是翻转的
1/df1
abcd
0inf1.0000000.5000000.333333
10.2500.2000000.1666670.142857
20.1250.1111110.1000000.090909
df1.rdiv(1)
abcd
0inf1.0000000.5000000.333333
10.2500.2000000.1666670.142857
20.1250.1111110.1000000.090909
df1.reindex(columns=df2.columns,fill_value=0)
abcde
00.01.02.03.00
14.05.06.07.00
28.09.010.011.00
5.2.5.2 DataFrame和Series间的操作
arr = np.arange(12.).reshape(3,4)
arr
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.],
       [ 8.,  9., 10., 11.]])
arr[0]
array([0., 1., 2., 3.])
#当我们从arr中减去arr[0]时,减法在每一行都进行了操作。这就是所谓的广播机制
arr - arr[0]
array([[0., 0., 0., 0.],
       [4., 4., 4., 4.],
       [8., 8., 8., 8.]])
frame = pd.DataFrame(np.arange(12.).reshape(4,3),
                    columns=list('bde'),
                    index=['Utah','ohio','Texas','Orgon'])
frame
bde
Utah0.01.02.0
ohio3.04.05.0
Texas6.07.08.0
Orgon9.010.011.0
series = frame.iloc[0]
series
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64
frame.loc['Utah']
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64
#默认情况下,DataFrame和Series的数学操作中会将Series的索引和DataFrame的列进行匹配,并广播到各行
frame - series
bde
Utah0.00.00.0
ohio3.03.03.0
Texas6.06.06.0
Orgon9.09.09.0
#如果一个索引值不在DataFrame的列中,也不在Series的索引中,则对象会重建索引并形成联合
series2 = pd.Series(range(3),index=['b','e','f'])
series2
b    0
e    1
f    2
dtype: int64
frame + series2
bdef
Utah0.0NaN3.0NaN
ohio3.0NaN6.0NaN
Texas6.0NaN9.0NaN
Orgon9.0NaN12.0NaN
#如果你想改为在列上进行广播,在行上匹配,你必须使用算术方法中的一种
series3 = frame['d']
series3
Utah      1.0
ohio      4.0
Texas     7.0
Orgon    10.0
Name: d, dtype: float64
#你传递的axis值是用于匹配轴的。上面的示例中表示我们需要在DataFrame的行索引上对行匹配(axis='index’或axis=0),并进行广播
frame.sub(series3,axis='index')
bde
Utah-1.00.01.0
ohio-1.00.01.0
Texas-1.00.01.0
Orgon-1.00.01.0

5.2.6 函数应用和映射

#NumPy的通用函数(逐元素数组方法)对pandas对象也有效
frame = pd.DataFrame(np.random.randn(4,3),columns=list('bde'),
                    index=['Utah','ohio','Texas','Orgon'])
frame 
bde
Utah0.6997100.0826200.778282
ohio-0.702902-0.5907621.112169
Texas0.592566-0.356857-0.977514
Orgon1.817981-0.2124530.435315
frame.abs()
bde
Utah0.6997100.0826200.778282
ohio0.7029020.5907621.112169
Texas0.5925660.3568570.977514
Orgon1.8179810.2124530.435315
np.abs(frame)
bde
Utah0.6997100.0826200.778282
ohio0.7029020.5907621.112169
Texas0.5925660.3568570.977514
Orgon1.8179810.2124530.435315
#另一个常用的操作是将函数应用到一行或一列的一维数组上。DataFrame的apply方法可以实现这个功能
#列上进行加减
f = lambda x:x.max() - x.min()
frame.apply(f)
b    2.520883
d    0.673381
e    2.089682
dtype: float64
#如果你传递axis='columns’给apply函数,函数将会被每行调用一次
frame.apply(f,axis = 'columns')
Utah     0.695662
ohio     1.815071
Texas    1.570080
Orgon    2.030434
dtype: float64
#传递给apply的函数并不一定要返回一个标量值,也可以返回带有多个值的Series
def f(x):
    return pd.Series([x.min(),x.max()],index = ['min','max'])

frame.apply(f)
bde
min-0.702902-0.590762-0.977514
max1.8179810.0826201.112169
#逐元素的Python函数也可以使用。假设你想要根据frame中的每个浮点数计算一个格式化字符串,可以使用applymap方法
format1 = lambda x :'%.2f'%x
frame.applymap(format1)
bde
Utah0.700.080.78
ohio-0.70-0.591.11
Texas0.59-0.36-0.98
Orgon1.82-0.210.44
#使用applymap作为函数名是因为Series有map方法,可以将一个逐元素的函数应用到Series上
frame['e'].map(format1)
Utah      0.78
ohio      1.11
Texas    -0.98
Orgon     0.44
Name: e, dtype: object

5.2.7 排序和排名

  • 根据某些准则对数据集进行排序是另一个重要的内建操作。
  • 如需按行或列索引进行字典型排序,需要使用sort_index方法,该方法返回一个新的、排序好的对象
  • 排名中的平级关系打破方法
    |方法|描述|
    |—|---|
    |‘average’|默认:在每个组中分配平均排名|
    |‘min’|对整个组使用最小排名|
    |‘max’|对整个组使用最大排名|
    |‘first’|按照值在数据中出现的次序分配排名|
    |'dense '|类似于method=‘min’,但组间排名总是增加1,而不是一个组中的相等元素的数量幂次方(**)|
obj = pd.Series(range(4),index = ['d','b','a','c'])
obj 
d    0
b    1
a    2
c    3
dtype: int64
obj.sort_index()
a    2
b    1
c    3
d    0
dtype: int64
#在DataFrame中,你可以在各个轴上按索引排序
frame = pd.DataFrame(np.arange(8).reshape(2,4),
                    index = ['three','one'],
                    columns= ['d','a','b','c'])

frame
dabc
three0123
one4567
#按照行索引
frame.sort_index()
dabc
one4567
three0123
#按照列索引
frame.sort_index(axis=1)
abcd
three1230
one5674
frame.sort_values(by = 'a')
dabc
three0123
one4567
#数据默认会升序排序,但是也可以按照降序排序
frame.sort_index(axis=1,ascending=False)
dcba
three0321
one4765
#如果要根据Series的值进行排序,使用sort_values方法
obj = pd.Series([4,7,-3,2])
obj.sort_values()
2   -3
3    2
0    4
1    7
dtype: int64
#默认情况下,所有的缺失值都会被排序至Series的尾部
obj = pd.Series([4,7,np.nan,-3,2,np.nan])
obj.sort_values()
3   -3.0
4    2.0
0    4.0
1    7.0
2    NaN
5    NaN
dtype: float64
#当对DataFrame排序时,你可以使用一列或多列作为排序键。为了实现这个功能,传递一个或多个列名给sort_values的可选参数by
frame = pd.DataFrame({'b':[4,7,-3,2],
                     'a':[0,1,0,1]})

frame.sort_index(axis=1)
ab
004
117
20-3
312
frame.sort_values(by=['a','b'])
ba
2-30
040
321
171
frame.sort_index(axis=1).sort_values(by=['a','b'])
ab
20-3
004
312
117
#排名是指对数组从1到有效数据点总数分配名次的操作。Series和DataFrame的rank方法是实现排名的方法,
#默认情况下,rank通过将平均排名分配到每个组来打破平级关系
obj = pd.Series([7,-5,7,4,2,0,4])
obj
0    7
1   -5
2    7
3    4
4    2
5    0
6    4
dtype: int64
obj.rank()
0    6.5
1    1.0
2    6.5
3    4.5
4    3.0
5    2.0
6    4.5
dtype: float64
#排名也可以根据他们在数据中的观察顺序进行分配
obj.rank(method='first')
0    6.0
1    1.0
2    7.0
3    4.0
4    3.0
5    2.0
6    5.0
dtype: float64
#你可以按降序排名
obj.rank(ascending=False,method='max')
0    2.0
1    7.0
2    2.0
3    4.0
4    5.0
5    6.0
6    4.0
dtype: float64
#DataFrame可以对行或列计算排名
frame = pd.DataFrame({'b':[1,2,3,4],
                     'a':[2,6,3,0],
                     'c':[-2,5,8,0]})
frame
bac
012-2
1265
2338
3400
frame.rank(axis='columns')
bac
02.03.01.0
11.03.02.0
21.51.53.0
33.01.51.5

5.2.8 含有重复标签的轴索引

obj = pd.Series(range(5),index=['a','a','b','b','c'])
obj
a    0
a    1
b    2
b    3
c    4
dtype: int64
#索引的is_unique属性可以告诉你它的标签是否唯一
obj.index.is_unique
False
#带有重复索引的情况下,数据选择是与之前操作有差别的主要情况
obj['a']
a    0
a    1
dtype: int64
df = pd.DataFrame(np.random.randn(4,3),index = ['a','a','b','b'])
df
012
a-1.0533350.546850-1.340218
a-1.295823-2.939633-0.800708
b-0.737360-1.1913850.538147
b2.336073-0.5090760.924366
df.loc['b']
012
b-0.737360-1.1913850.538147
b2.336073-0.5090760.924366

5.3 描述性统计的概述与计算

  • 归约方法可选参数
    |方法|描述|
    |—|---|
    |axis|归约轴,0为行向,1为列向|
    |skipna|排除缺失值,默认为True|
    |level|如果轴是多层索引的(MultiIndex), 该参数可以缩减分组层级|
df = pd.DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,1.3]],
                 index = ['a','b','c','d'],
                 columns = ['one','two'])
df
onetwo
a1.40NaN
b7.10-4.5
cNaNNaN
d0.751.3
#调用DataFrame的sum方法返回一个包含列上加和的Series
df.sum()
one    9.25
two   -3.20
dtype: float64
#传入axis='columns’或axis=1,则会将一行上各个列的值相加
df.sum(axis='columns')
a    1.40
b    2.60
c    0.00
d    2.05
dtype: float64
#除非整个切片上(在本例中是行或列)都是NA,否则NA值是被自动排除的。可以通过禁用skipna来实现不排除NA值
df.mean(axis='columns',skipna = False)
a      NaN
b    1.300
c      NaN
d    1.025
dtype: float64
#idxmin和idxmax,返回的是间接统计信息,比如最小值或最大值的索引值
df.idxmin()
one    d
two    b
dtype: object
df.idxmax()
one    b
two    d
dtype: object
#除了归约方法外,有的方法是积累型方法
df.cumsum()
onetwo
a1.40NaN
b8.50-4.5
cNaNNaN
d9.25-3.2
#还有一类方法既不是归约型方法也不是积累型方法。describe就是其中之一,它一次性产生多个汇总统计
df.describe()
onetwo
count3.0000002.000000
mean3.083333-1.600000
std3.4936854.101219
min0.750000-4.500000
25%1.075000-3.050000
50%1.400000-1.600000
75%4.250000-0.150000
max7.1000001.300000
#对于非数值型数据,describe产生另一种汇总统计
obj = pd.Series(['a','a','b','c']*4)
obj.describe()
count     16
unique     3
top        a
freq       8
dtype: object
  • 表5-8:描述性统计和汇总统计
    |方法|描述|
    |—|---|
    |count|非NA值的个数|
    |describe|计算Series 或DataFrame各列的汇总统计集合|
    |min, max|计算最小值、最大值|
    |argmin, argmax|分别计算最小值、最大值所在的索引位置(整数)|
    |idxmin,idxmax|分别计算最小值或最大值所在的索引标签|
    |quantile|计算样本的从0到1间的分位数|
    |Sum|加和|
    |mean|均值|
    |median|中位数(50% 分位数)|
    |mad|平均值的平均绝对偏差|
    |prod|所有值的积|
    |var|值的样本方差|
    |std|值的样本标准差|
    |skew|样本偏度(第三时刻)值|
    |kurt|样本峰度(第四时刻)的值|
    |Cumsum|累计值|
    |cummin,cummax|累计值的最小值或最大值|
    |cumprod|值的累计积|
    |diff|计算第一个算术差值(对时间序列有用)|
    |pct_change |计算百分比|

5.3.1 相关性和协方差

import pandas_datareader.data as web
all_data = {ticker:web.get_data_yahoo(ticker)
           for ticker in ['AAPL','IBM','MSFT','GOOG']}

all_data
{'AAPL':                   High         Low        Open       Close       Volume  \
 Date                                                                      
 2016-12-20   29.375000   29.170000   29.184999   29.237499   85700000.0   
 2016-12-21   29.350000   29.195000   29.200001   29.264999   95132800.0   
 2016-12-22   29.127501   28.910000   29.087500   29.072500  104343600.0   
 2016-12-23   29.129999   28.897499   28.897499   29.129999   56998000.0   
 2016-12-27   29.450001   29.122499   29.129999   29.315001   73187600.0   
 ...                ...         ...         ...         ...          ...   
 2021-12-13  182.130005  175.529999  181.119995  175.740005  153237000.0   
 2021-12-14  177.740005  172.210007  175.250000  174.330002  139380400.0   
 2021-12-15  179.500000  172.309998  175.110001  179.300003  131063300.0   
 2021-12-16  181.139999  170.750000  179.279999  172.259995  150185800.0   
 2021-12-17  173.470001  169.690002  169.929993  171.139999  195432700.0   
 
              Adj Close  
 Date                    
 2016-12-20   27.520725  
 2016-12-21   27.546612  
 2016-12-22   27.365414  
 2016-12-23   27.419537  
 2016-12-27   27.593679  
 ...                ...  
 2021-12-13  175.740005  
 2021-12-14  174.330002  
 2021-12-15  179.300003  
 2021-12-16  172.259995  
 2021-12-17  171.139999  
 
 [1258 rows x 6 columns],
 'IBM':                   High         Low        Open       Close      Volume  \
 Date                                                                     
 2016-12-20  160.850861  159.130020  160.124283  160.229446   2274632.0   
 2016-12-21  160.554489  157.982788  158.938812  159.971313   3740182.0   
 2016-12-22  160.831741  159.254303  160.000000  159.713196   2931520.0   
 2016-12-23  160.124283  159.130020  159.655838  159.378586   1779455.0   
 2016-12-27  160.592728  159.512421  159.636703  159.789673   1461785.0   
 ...                ...         ...         ...         ...         ...   
 2021-12-13  124.360001  120.790001  123.760002  122.580002   6847500.0   
 2021-12-14  125.029999  122.300003  122.349998  123.760002   5716100.0   
 2021-12-15  124.820000  122.180000  123.800003  123.110001   4990000.0   
 2021-12-16  126.639999  123.480003  123.510002  125.930000   7280500.0   
 2021-12-17  128.639999  125.209999  125.870003  127.400002  10379000.0   
 
              Adj Close  
 Date                    
 2016-12-20  127.391281  
 2016-12-21  127.186043  
 2016-12-22  126.980827  
 2016-12-23  126.714798  
 2016-12-27  127.041634  
 ...                ...  
 2021-12-13  122.580002  
 2021-12-14  123.760002  
 2021-12-15  123.110001  
 2021-12-16  125.930000  
 2021-12-17  127.400002  
 
 [1258 rows x 6 columns],
 'MSFT':                   High         Low        Open       Close      Volume  \
 Date                                                                     
 2016-12-20   63.799999   63.029999   63.689999   63.540001  26028400.0   
 2016-12-21   63.700001   63.119999   63.430000   63.540001  17096300.0   
 2016-12-22   64.099998   63.410000   63.840000   63.549999  22176600.0   
 2016-12-23   63.540001   62.799999   63.450001   63.240002  12403800.0   
 2016-12-27   64.070000   63.209999   63.209999   63.279999  11763200.0   
 ...                ...         ...         ...         ...         ...   
 2021-12-13  343.790009  339.079987  340.679993  339.399994  28899400.0   
 2021-12-14  334.640015  324.109985  333.220001  328.339996  44438700.0   
 2021-12-15  335.190002  324.500000  328.609985  334.649994  35381100.0   
 2021-12-16  336.760010  323.019989  335.709991  324.899994  35034800.0   
 2021-12-17  324.920013  317.250000  320.880005  323.799988  47750300.0   
 
              Adj Close  
 Date                    
 2016-12-20   59.078098  
 2016-12-21   59.078098  
 2016-12-22   59.087402  
 2016-12-23   58.799171  
 2016-12-27   58.836357  
 ...                ...  
 2021-12-13  339.399994  
 2021-12-14  328.339996  
 2021-12-15  334.649994  
 2021-12-16  324.899994  
 2021-12-17  323.799988  
 
 [1258 rows x 6 columns],
 'GOOG':                    High          Low         Open        Close   Volume  \
 Date                                                                      
 2016-12-20   798.650024   793.270020   796.760010   796.419983   951000   
 2016-12-21   796.676025   787.099976   795.840027   794.559998  1211300   
 2016-12-22   793.320007   788.580017   792.359985   791.260010   972200   
 2016-12-23   792.739990   787.280029   790.900024   789.909973   623400   
 2016-12-27   797.859985   787.656982   790.679993   791.549988   789100   
 ...                 ...          ...          ...          ...      ...   
 2021-12-13  2971.250000  2927.199951  2968.879883  2934.090088  1205200   
 2021-12-14  2908.840088  2844.850098  2895.399902  2899.409912  1238900   
 2021-12-15  2950.344971  2854.110107  2887.320068  2947.370117  1364000   
 2021-12-16  2971.030029  2881.850098  2961.540039  2896.770020  1370000   
 2021-12-17  2889.201904  2835.760010  2854.290039  2856.060059  2162800   
 
               Adj Close  
 Date                     
 2016-12-20   796.419983  
 2016-12-21   794.559998  
 2016-12-22   791.260010  
 2016-12-23   789.909973  
 2016-12-27   791.549988  
 ...                 ...  
 2021-12-13  2934.090088  
 2021-12-14  2899.409912  
 2021-12-15  2947.370117  
 2021-12-16  2896.770020  
 2021-12-17  2856.060059  
 
 [1258 rows x 6 columns]}
price = pd.DataFrame({ticker:data['Adj Close']
                     for ticker,data in all_data.items()})
price
AAPLIBMMSFTGOOG
Date
2016-12-2027.520725127.39128159.078098796.419983
2016-12-2127.546612127.18604359.078098794.559998
2016-12-2227.365414126.98082759.087402791.260010
2016-12-2327.419537126.71479858.799171789.909973
2016-12-2727.593679127.04163458.836357791.549988
...............
2021-12-13175.740005122.580002339.3999942934.090088
2021-12-14174.330002123.760002328.3399962899.409912
2021-12-15179.300003123.110001334.6499942947.370117
2021-12-16172.259995125.930000324.8999942896.770020
2021-12-17171.139999127.400002323.7999882856.060059

1258 rows × 4 columns

Volume = pd.DataFrame({ticker:data['Volume']
                     for ticker,data in all_data.items()})
Volume
AAPLIBMMSFTGOOG
Date
2016-12-2085700000.02274632.026028400.0951000
2016-12-2195132800.03740182.017096300.01211300
2016-12-22104343600.02931520.022176600.0972200
2016-12-2356998000.01779455.012403800.0623400
2016-12-2773187600.01461785.011763200.0789100
...............
2021-12-13153237000.06847500.028899400.01205200
2021-12-14139380400.05716100.044438700.01238900
2021-12-15131063300.04990000.035381100.01364000
2021-12-16150185800.07280500.035034800.01370000
2021-12-17195432700.010379000.047750300.02162800

1258 rows × 4 columns

returns = price.pct_change()

AAPLIBMMSFTGOOG
Date
2021-12-13-0.020674-0.012169-0.009167-0.013254
2021-12-14-0.0080230.009626-0.032587-0.011820
2021-12-150.028509-0.0052520.0192180.016541
2021-12-16-0.0392640.022906-0.029135-0.017168
2021-12-17-0.0065020.011673-0.003386-0.014054
#Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性。相应地,cov计算的是协方差
returns['MSFT'].corr(returns['IBM'])
0.4973985942857425
returns.MSFT.corr(returns['IBM'])
0.4973985942857425
returns['MSFT'].cov(returns['IBM'])
0.00014275531886403115
#DataFrame的corr和cov方法会分别以DataFrame的形式返回相关性和协方差矩阵
returns.corr()
AAPLIBMMSFTGOOG
AAPL1.0000000.4297430.7364240.658843
IBM0.4297431.0000000.4973990.469242
MSFT0.7364240.4973991.0000000.778161
GOOG0.6588430.4692420.7781611.000000
#使用DataFrame的corrwith方法,你可以计算出DataFrame中的行或列与另一个序列或DataFrame的相关性。
#该方法传入一个Series时,会返回一个含有为每列计算相关性值的Series
returns.corrwith(returns.IBM)
AAPL    0.429743
IBM     1.000000
MSFT    0.497399
GOOG    0.469242
dtype: float64
returns.corrwith(Volume)
AAPL   -0.073139
IBM    -0.134489
MSFT   -0.065349
GOOG   -0.110807
dtype: float64

5.3.2 唯一值、计数和成员属性

方法描述
isin计算表征Series中每个值是否包含于传入序列的布尔值数组
match计算数组中每个值的整数索引,形成-一个唯-值数组。有助于数据;对齐和join类型的操作
unique计算Series 值中的唯-值数组,按照观察顺序返回
value_ counts返回一个Series,索引是唯一值序列,值是计数个数,按照个数降序排序
quantile计算样本的从0到1间的分位数
Sum加和
mean均值
median中位数(50% 分位数)
mad平均值的平均绝对偏差
prod所有值的积
var值的样本方差
std值的样本标准差
skew样本偏度(第三时刻)值
kurt样本峰度(第四时刻)的值
Cumsum累计值
cummin,cummax累计值的最小值或最大值
cumprod值的累计积
diff计算第一个算术差值(对时间序列有用)
pct_ change计算百分比
obj = pd.Series(['c','a','d','a','b','a','a','d'])
uniques = obj.unique()
uniques.sort()
#value_counts计算Series包含的值的个数
obj.value_counts()
a    4
d    2
b    1
c    1
dtype: int64
#value_counts也是有效的pandas顶层方法,可以用于任意数组或序列
pd.value_counts(obj.values,sort=False)
b    1
d    2
c    1
a    4
dtype: int64
#isin执行向量化的成员属性检查,还可以将数据集以Series或DataFrame一列的形式过滤为数据集的值子集
mask = obj.isin(['b','c'])
mask
0     True
1    False
2    False
3    False
4     True
5    False
6    False
7    False
dtype: bool
obj[mask]
0    c
4    b
dtype: object
#与isin相关的Index.get_indexer方法,可以提供一个索引数组,这个索引数组可以将可能非唯一值数组转换为另一个唯一值数组
to_match = pd.Series(['c','a','b','b','c','a'])
unique_vals = pd.Series(['c','b','a'])
pd.Index(unique_vals).get_indexer(to_match)
array([0, 2, 1, 1, 0, 2], dtype=int64)
#计算DataFrame多个相关列的直方图
data = pd.DataFrame({'QU1':[1,3,4,3,4],
                    'QU2':[2,3,1,2,3],
                    'QU3':[1,5,2,2,4]})
data
QU1QU2QU3
0121
1335
2412
3322
4434
#将pandas.value_counts传入DataFrame的apply函数可以得到
#结果中的行标签是所有列中出现的不同值,数值则是这些不同值在每个列中出现的次数
result = data.apply(pd.value_counts).fillna(0)
result
QU1QU2QU3
11.01.01.0
20.02.02.0
32.02.00.0
42.00.01.0
50.00.01.0

5.4 本章小结

第六章 数据载入、存储及文件格式

  • 输入和输出通常有以下几种类型:读取文本文件及硬盘上其他更高效的格式文件、从数据库载入数据、与网络资源进行交互(比如Web API)

6.1 文本格式数据的读写

  • Pandas的解析函数
    |方法|描述|
    |—|---|
    |read_ CsV|从文件、URL或文件型对象读取分隔好的数据,逗号是默认分隔符|
    |read_ table|从文件、URL或文件型对象读取分隔好的数据,制表符(’\t’)是默认分隔符|
    |read_ fwf|从特定宽度格式的文件中读取数据(无分隔符)|
    |read
    clipboard|read_ table的剪贴板版本,在将表格从Web页面上转换成数据时有用|
    |read_ excel|从Excel的XLS或XLSX文件中读取表格数据|
    |read_ hdf|读取用pandas存储的HDF5文件|
    |read_ html|从HTML文件中读取所有表格数据|
    |read_json|从JSON JavaScript Object Notation)字符串中读取数据|
    |read_ msgpack|读取MessagePack二进制格式的pandas数据|
    |read_ pickle|读取以Python pickle格式存储的任意对象|
    |read_ sas|读取存储在SAS系统中定制存储格式的SAS数据集|
    |read_ sql|将SQL查询的结果(使用SQLAlchemy)读取为pandas的DataFrame|
    |read_ stata|读取Stata格式的数据集|
    |read_feather|读取Feather二进制格式|
df = pd.read_csv('examples/ex1.csv')
df
abcdmessage
01234hello
15678world
29101112foo
#可以使用read_table,并指定分隔符
pd.read_table('examples/ex1.csv',sep=',')
abcdmessage
01234hello
15678world
29101112foo
#有的文件并不包含表头行
pd.read_csv('examples/ex2.csv',header = None,sep=',')
01234
01234hello
15678world
29101112foo
#假设你想要message列成为返回DataFrame的索引,你可以指定位置4的列为索引,或将’message’传给参数index_col
names = ['a','b','c','d','message']
pd.read_csv('examples/ex2.csv',names = names,index_col = 'message')
abcd
message
hello1234
world5678
foo9101112
parsed = pd.read_csv('examples/csv_mindex.csv',index_col = ['key1','key2'])
parsed
value1value2
key1key2
onea12
b34
c56
d78
twoa910
b1112
c1314
d1516
list(open('examples/ex3.txt'))
['            A         B         C\n',
 'aaa -0.264438 -1.026059 -0.619500\n',
 'bbb  0.927272  0.302904 -0.032399\n',
 'ccc -0.264273 -0.386314 -0.217601\n',
 'ddd -0.871858 -0.348382  1.100491\n']
#由于列名的数量比数据的列数少一个,因此read_table推断第一列应当作为DataFrame的索引
result = pd.read_table('examples/ex3.txt',sep = '\s+')
result
ABC
aaa-0.264438-1.026059-0.619500
bbb0.9272720.302904-0.032399
ccc-0.264273-0.386314-0.217601
ddd-0.871858-0.3483821.100491
#使用skiprows来跳过第一行、第三行和第四行
pd.read_csv('examples/ex4.csv',skiprows=[0,2,3])
abcdmessage
01234hello
15678world
29101112foo
#缺失值处理是文件解析过程中一个重要且常常微妙的部分。通常情况下,缺失值要么不显示(空字符串),要么用一些标识值。
#默认情况下,pandas使用一些常见的标识,例如NA和NULL
result = pd.read_table('examples/ex5.csv',sep = ',')
result
somethingabcdmessage
0one123.04NaN
1two56NaN8world
2three91011.012foo
pd.isnull(result)
somethingabcdmessage
0FalseFalseFalseFalseFalseTrue
1FalseFalseFalseTrueFalseFalse
2FalseFalseFalseFalseFalseFalse
#na_values选项可以传入一个列表或一组字符串来处理缺失值
result = pd.read_table('examples/ex5.csv',sep = ',',na_values=['1'])
result
somethingabcdmessage
0oneNaN23.04NaN
1two5.06NaN8world
2three9.01011.012foo
#在字典中,每列可以指定不同的缺失值标识
sentinels = {'message':['foo','NA'],'something':['two']}
result = pd.read_table('examples/ex5.csv',sep = ',',na_values=sentinels)
result
somethingabcdmessage
0one123.04NaN
1NaN56NaN8world
2three91011.012NaN
  • Pandas的解析函数
    |方法|描述|
    |—|---|
    |path|表明文件系统位置的字符串、URL或文件型对象|
    |sep或delimiter|用于分隔每行字段的字符序列或正则表达式|
    |header|用作列名的行号,默认是0 (第-行),如果没有列名的话,应该为None
    |index_ col|用作结果中行索引的列号或列名,可以是一个单一的名称/数字,也可以是一个分层索引|
    |names|结果的列名列表,和header=None一起用|
    |skiprows|从文件开头处起,需要跳过的行数或行号列表:|
    |na_ values|需要用NA替换的值序列|
    |comment|在行结尾处分隔注释的字符|
    |parse_ dates|尝试将数据解析为datetime,默认是False。如果为True,将尝试解析所有的列。也可以指定列号或列名列表来进行解析。如果列表的元素是元组或列表,将会把多个列组合在-起进行解析(例如日期/时间将拆分为两列)|
    |keep_ date_ col|如果连接列到解析日期上,保留被连接的列,默认是False|
    |converters|包含列名称映射到函数的字典(例如{‘foo’ :f}会把函数f应用到’foo’列)|
    |dayfirst|解析非明确日期时,按照国际格式处理(例如7/6/2012 -> June7,2012),默认为False|

6.1.1 分块读入文本文件

  • 当处理大型文件或找出正确的参数集来正确处理大文件时,你可能需要读入文件的一个小片段或者按小块遍历文件。
#在尝试大文件之前,我们可以先对pandas的显示设置进行调整,使之更为紧凑
pd.options.display.max_rows = 10
result = pd.read_table('examples/ex6.csv',sep = ',')
result
onetwothreefourkey
00.467976-0.038649-0.295344-1.824726L
1-0.3588931.4044530.704965-0.200638B
2-0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
..................
99952.311896-0.417070-1.409599-0.515821L
9996-0.479893-0.6504190.745152-0.646038E
99970.5233310.7871120.4860661.093156K
9998-0.3625590.598894-1.8432010.887292G
9999-0.096376-1.012999-0.657431-0.5733150

10000 rows × 5 columns

#如果你只想读取一小部分行(避免读取整个文件),可以指明nrows
result = pd.read_table('examples/ex6.csv',sep = ',',nrows=5)
result
onetwothreefourkey
00.467976-0.038649-0.295344-1.824726L
1-0.3588931.4044530.704965-0.200638B
2-0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
#为了分块读入文件,可以指定chunksize作为每一块的行数
chunker = pd.read_table('examples/ex6.csv',sep = ',',chunksize=1000)
chunker
<pandas.io.parsers.TextFileReader at 0x219218cbf10>
#read_csv返回的TextParser对象允许你根据chunksize遍历文件
chunker = pd.read_table('examples/ex6.csv',sep = ',',chunksize=1000)
tot = pd.Series([])
for piece in chunker:
    tot = tot.add(piece['key'].value_counts(),fill_value = 0)
tot = tot.sort_values(ascending = False)
<ipython-input-24-4e4a5f0a0109>:3: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
  tot = pd.Series([])

6.1.2 将数据写入文本格式

data = pd.read_csv('examples/ex5.csv')
data
somethingabcdmessage
0one123.04NaN
1two56NaN8world
2three91011.012foo
data.to_csv('examples/out.csv')
#当然,其他的分隔符也是可以的(写入到sys.stdout时,控制台中打印的文本结果)
import sys
data.to_csv(sys.stdout,sep = '|')
|something|a|b|c|d|message
0|one|1|2|3.0|4|
1|two|5|6||8|world
2|three|9|10|11.0|12|foo
#缺失值在输出时以空字符串出现。你也许想要用其他标识值对缺失值进行标注
data.to_csv(sys.stdout,na_rep = "NULL")
,something,a,b,c,d,message
0,one,1,2,3.0,4,NULL
1,two,5,6,NULL,8,world
2,three,9,10,11.0,12,foo
#如果没有其他选项被指定的话,行和列的标签都会被写入。不过二者也都可以禁止写入
data.to_csv(sys.stdout,index=False,header=False)
one,1,2,3.0,4,
two,5,6,,8,world
three,9,10,11.0,12,foo
#你也可以仅写入列的子集,并且按照你选择的顺序写入
data.to_csv(sys.stdout,index=False,columns = ['a','b','c'])
a,b,c
1,2,3.0
5,6,
9,10,11.0
#Series也有to_csv方法
dates = pd.date_range('1/1/2000',periods=7)
ts = pd.Series(np.arange(7),index = dates)
ts.to_csv('examples/tseries.csv')
ts
2000-01-01    0
2000-01-02    1
2000-01-03    2
2000-01-04    3
2000-01-05    4
2000-01-06    5
2000-01-07    6
Freq: D, dtype: int32

6.1.3 使用分隔格式

#对于任何带有单字符分隔符的文件,你可以使用Python的内建csv模块。要使用它,需要将任一打开的文件或文件型对象传给csv.reader
import csv
f = open('examples/ex7.csv')
reader = csv.reader(f)
#像遍历文件那样遍历reader会产生元组,元组的值为删除了引号的字符
for line in reader:
    print(line)
['a', 'b', 'c']
['1', '2', '3']
['1', '2', '3']
with open('examples/ex7.csv') as f:
    lines = list(csv.reader(f))
lines
[['a', 'b', 'c'], ['1', '2', '3'], ['1', '2', '3']]
header,values = lines[0],lines[1:]
header
['a', 'b', 'c']
values
[['1', '2', '3'], ['1', '2', '3']]
data_dict = {h:v for h,v in zip(header,zip(*values))}
data_dict
{'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')}

6.1.4 JSON数据

  • JSON(JavaScript Object Notation的简写)已经成为Web浏览器和其他应用间通过HTTP请求发送数据的标准格式。
  • 对象中的所有键都必须是字符串
obj ="""
{"name":"Wes",
"places_ lived": ["United States","Spain","Germany"],
"pet":null,
"siblings":[{"name":"Scott","age":30, "pets": ["Zeus","Zuko"]},
{"age":38,"name": "Katie","pets": ["Sixes","Stache","Cisco"]}]}
"""
import json
result = json.loads(obj)
result
{'name': 'Wes',
 'places_ lived': ['United States', 'Spain', 'Germany'],
 'pet': None,
 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']},
  {'age': 38, 'name': 'Katie', 'pets': ['Sixes', 'Stache', 'Cisco']}]}
#json.dumps可以将Python对象转换回JSON
asjson = json.dumps(result)
asjson
'{"name": "Wes", "places_ lived": ["United States", "Spain", "Germany"], "pet": null, "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]}, {"age": 38, "name": "Katie", "pets": ["Sixes", "Stache", "Cisco"]}]}'
siblings = pd.DataFrame(result["siblings"],columns = ['name','age'])
siblings
nameage
0Scott30
1Katie38
#pandas.read_json可以自动将JSON数据集按照指定次序转换为Series或DataFrame
data = pd.read_json('examples/example.json')
data
abc
0123
1456
2789
#如果你需要从pandas中将数据导出为JSON,一种办法是对Series和DataFrame使用to_json方法
print(data.to_json())
{"a":{"0":1,"1":4,"2":7},"b":{"0":2,"1":5,"2":8},"c":{"0":3,"1":6,"2":9}}
print(data.to_json(orient='records'))
[{"a":1,"b":2,"c":3},{"a":4,"b":5,"c":6},{"a":7,"b":8,"c":9}]

6.1.5 XML和HTML:网络抓取

  • pandas的内建函数read_html可以使用lxml和Beautiful Soup等库将HTML中的表自动解析为DataFrame对象
import lxml
import beautifulsoup4
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

<ipython-input-39-e646caa245dd> in <module>
----> 1 import beautifulsoup4


ModuleNotFoundError: No module named 'beautifulsoup4'
tables = pd.read_html('examples/fdic_failed_bank_list.html')
len(tables)
1
failures = tables[0]
failures.head()
Bank NameCitySTCERTAcquiring InstitutionClosing DateUpdated Date
0Allied BankMulberryAR91Today's BankSeptember 23, 2016November 17, 2016
1The Woodbury Banking CompanyWoodburyGA11297United BankAugust 19, 2016November 17, 2016
2First CornerStone BankKing of PrussiaPA35312First-Citizens Bank & Trust CompanyMay 6, 2016September 6, 2016
3Trust Company BankMemphisTN9956The Bank of Fayette CountyApril 29, 2016September 6, 2016
4North Milwaukee State BankMilwaukeeWI20364First-Citizens Bank & Trust CompanyMarch 11, 2016June 16, 2016
close_timestamps = pd.to_datetime(failures['Closing Date'])
close_timestamps.dt.year.value_counts()
2010    157
2009    140
2011     92
2012     51
2008     25
2013     24
2014     18
2002     11
2015      8
2016      5
2001      4
2004      4
2003      3
2007      3
2000      2
Name: Closing Date, dtype: int64
6.1.5.1 使用lxml.objectify解析XML
  • XML(eXtensible Markup Language)是另一种常用的结构化数据格式,它使用元数据支持分层、嵌套数据。
from lxml import objectify
path = 'example/mta_perf/Performance_MNR.xml'
parsed = objectify.parse(open(path))
root = parsed.getroot()
---------------------------------------------------------------------------

FileNotFoundError                         Traceback (most recent call last)

<ipython-input-46-22c8866b96c7> in <module>
      1 from lxml import objectify
      2 path = 'example/mta_perf/Performance_MNR.xml'
----> 3 parsed = objectify.parse(open(path))
      4 root = parsed.getroot()


FileNotFoundError: [Errno 2] No such file or directory: 'example/mta_perf/Performance_MNR.xml'

6.2 二进制格式

  • 使用Python内建的pickle序列化模块进行二进制格式操作是存储数据(也称为序列化)最高效、最方便的方式之一。
  • pickle仅被推荐作为短期的存储格式。问题在于pickle很难确保格式的长期有效性;一个今天被pickle化的对象可能明天会因为库的新版本而无法反序列化。我们尽可能保持向后兼容性,但在将来的某个时候,可能有必要“打破”pickle格式
frame = pd.read_csv('examples/ex1.csv')
frame
abcdmessage
01234hello
15678world
29101112foo
frame.to_pickle('examples/frame_pickle')
pd.read_pickle('examples/frame_pickle')
abcdmessage
01234hello
15678world
29101112foo

6.2.1 使用HDF5格式

frame = pd.DataFrame({'a':np.random.randn(100)})
frame
a
0-0.302048
11.382578
2-0.961553
3-0.390501
4-0.441857
......
95-0.876892
96-0.447401
97-0.443915
98-0.980782
991.710659

100 rows × 1 columns

store = pd.HDFStore('mydata.h5')
store
<class 'pandas.io.pytables.HDFStore'>
File path: mydata.h5
store['obj1'] = frame
store['obj1_col'] = frame['a']
store
<class 'pandas.io.pytables.HDFStore'>
File path: mydata.h5
store['obj1']
a
0-0.302048
11.382578
2-0.961553
3-0.390501
4-0.441857
......
95-0.876892
96-0.447401
97-0.443915
98-0.980782
991.710659

100 rows × 1 columns

#HDFStore支持两种存储模式,'fixed’和’table'。后者速度更慢,但支持一种特殊语法的查询操作
store.put('obj2',frame,format='table')
store.select('obj2',where = ['index>= 10 and index <= 15'])
a
101.428619
11-0.722998
12-0.493169
13-0.731987
14-0.826249
15-0.877255

6.2.2 读取Microsoft Excel文件

xlsx = pd.ExcelFile('examples/ex1.xlsx')
xlsx
<pandas.io.excel._base.ExcelFile at 0x2b6dfb29100>
pd.read_excel('examples/ex1.xlsx')
Unnamed: 0abcdmessage
001234hello
115678world
229101112foo
frame = pd.read_excel('examples/ex1.xlsx','Sheet1')
frame 
Unnamed: 0abcdmessage
001234hello
115678world
229101112foo
#如需将pandas数据写入到Excel格式中,你必须先生成一个ExcelWriter,然后使用pandas对象的to_excel方法将数据写入
writer = pd.ExcelWriter('examples/ex2.xlsx')
frame.to_excel(writer,'Sheet1')
writer.save()
#你也可以将文件路径传给to_excel,避免直接调用ExcelWriter
frame.to_excel('examples/ex2.xlsx')

6.3 与Web API交互

import requests
url = 'https://github.com/repos/pandas-dev/pandas/issues'

6.4 与数据库交互

6.5 本章小结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值