一、了解数据分析以及环境安装

1、流程

2、anaconda

【官网下载】

基本上一路next即可,需要修改的地方自己注意

如果没有配置环境变量的话:

经典操作:右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量

先添加一个变量,内容是安装的目录

然后向path变量中添加

测试是否成功,执行结果出现版本号即为成功

1
conda -V

3、jupyter

Jupyter是一个交互式的开发环境,是基于Web的代码笔记本
交互性、探索性的高效环境
每一步骤都能看到结果,很方便的查看之前的结果

安装:

1
pip install jupyter

打开:(可以在自己想要的工作目录下输入,只存放相关的为文件,jupyter的根目录就是当前工作路径)

1
jupyter notebook

二、介绍与安装模块

以下使用的是清华镜像源

  • numpy

介绍

NumPy 是一个 Python 包。 它代表 “Numeric Python”。 它是一个由多维数组对象和用于处理数组的例程集合组成的库。

使用NumPy,开发人员可以执行以下操作:

  • 数组的算数和逻辑运算。
  • 傅立叶变换和用于图形操作的例程。
  • 与线性代数有关的操作。 NumPy 拥有线性代数和随机数生成的内置函数。

为什么使用NumPy?

  • 对于同样的数值计算任务,使用Numpy比直接Python代码实现,优点:
    • 代码更简洁: Numpy直接以数组、矩阵为粒度计算并且支撑大量的数学函数,而python需要用for循环从底层实现;
    • 性能更高效: Numpy的数组存储效率和输入输出计算性能,比Python使用List或者嵌套List好很多;
      • 注: Numpy的数据存储和Python原生的List是不一样的
      • 注: Numpy的大部分代码都是C语言实现的,这是Numpy比纯Python代码高效的原因
  • Numpy是Python各种数据科学类库的基础库
    • 比如: Scipy,Scikit-Learn、TensorFlow,pandas等

安装

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
  • pandas
    介绍

pandas 是对表格数据模型在python上的模拟,它有简单的像SQL 对数据的处理,能够方便的在python上实现。

安装

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandas
  • matplotlib

介绍

Matplotlib 是一个用于在 Python 中绘制数组的 2D 图形库。虽然它起源于模仿 MATLAB 图形命令,但它独立于 MATLAB,可以以 Pythonic 和面向对象的方式使用。虽然 Matplotlib 主要是在纯 Python 中编写的,但它大量使用 NumPy 和其他扩展代码,即使对于大型数组也能提供良好的性能。

安装

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib

三、numpy

1、Ndarray 对象

  • NumPy 中定义的最重要的对象是称为 ndarray 的 N 维数组类型。 它描述相同类型的元素集合。 可以使用基于零的索引访问集合中的项目。
  • ndarray中的每个元素在内存中使用相同大小的块。 ndarray中的每个元素是数据类型对象的对象(称为 dtype)。
  • ndarray对象提取的任何元素(通过切片)由一个数组标量类型的 Python 对象表示。 下图显示了ndarray,数据类型对象(dtype)和数组标量类型之间的关系。

创建:

1
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

构造器参数:

参数 描述
object 任何暴露数组接口方法的对象都会返回一个数组或任何(嵌套)序列。
dtype 数组的所需数据类型,可选。(默认自动识别)
copy 可选,默认为true,对象是否被复制。
order C(按行)、F(按列)或 A(任意,默认)。
subok 默认情况下,返回的数组被强制为基类数组。 如果为true,则返回子类。
ndmin 指定返回数组的最小维数。

案例

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
32
import numpy as np

array1 = np.array([[1, 2, 3], [2, 3, 4]])
print('array1:')
print(array1)
# --- ndim ---------
array2 = np.array([1, 2, 3, 4, 5], ndmin=2)
print('array2:')
print(array2)
array3 = np.array([1, 2, 3, 4, 5], ndmin=3)
print('array3:')
print(array3)
# --- dtype -----------
array4 = np.array([1, 2, 3], dtype=complex)
print('array4:')
print(array4)
# --- 数据类型不同的话,则都会转变成内存最大的类型 ---
array5 = np.array([1, 2, '3'])
print('array5:')
print(array5)
# --- copy (默认为True) -------
array6 = np.array(array1)
# array6 = array1.copy() # 效果相同
print('copy的结果:')
print(id(array1), id(array6))
# --- subok -------
mat = np.mat([1, 2, 3]) # 创建一个矩阵
array7 = np.array(mat, subok=False)
array8 = np.array(mat, subok=True)
print('subok:')
print('为False:', type(array7))
print('为True:', type(array8))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
array1:
[[1 2 3]
[2 3 4]]
array2:
[[1 2 3 4 5]]
array3:
[[[1 2 3 4 5]]]
array4:
[1.+0.j 2.+0.j 3.+0.j]
array5:
['1' '2' '3']
copy的结果:
2963333225808 2963506355824
subok:
为True: <class 'numpy.ndarray'>
为False: <class 'numpy.matrix'>

2、NumPy - 数据类型

序号 数据类型 描述
1 bool 存储为一个字节的布尔值(真或假)
2 int 默认整数,相当于 C 的long,通常为int32int64
3 intc 相当于 C 的int,通常为int32int64
4 intp 用于索引的整数,相当于 C 的size_t,通常为int32int64
5 int8 字节(-128 ~ 127)
6 int16 16 位整数(-32768 ~ 32767)
7 int32 32 位整数(-2147483648 ~ 2147483647)
8 int64 64 位整数(-9223372036854775808 ~ 9223372036854775807)
9 uint8 8 位无符号整数(0 ~ 255)
10 uint16 16 位无符号整数(0 ~ 65535)
11 uint32 32 位无符号整数(0 ~ 4294967295)
12 uint64 64 位无符号整数(0 ~ 18446744073709551615)
13 float float64的简写
14 float16 半精度浮点:符号位,5 位指数,10 位尾数
15 float32 单精度浮点:符号位,8 位指数,23 位尾数
16 float64 双精度浮点:符号位,11 位指数,52 位尾数
17 complex complex128的简写
18 complex64 复数,由两个 32 位浮点表示(实部和虚部)
19 complex128 复数,由两个 64 位浮点表示(实部和虚部)
20 str 字符串类型
21 string 字符串类型,也就是byte类型

NumPy 数字类型是dtype(数据类型)对象的实例,每个对象具有唯一的特征。 这些类型可以是np.boolnp.float32等。

简写

字符 对应类型 字符 对应类型 字符 对应类型 字符 对应类型
b 布尔值 i 带符号整形 u 无符号整形 f 浮点型
c 复数浮点型 m 时间间隔(timedelta) M 日期时间(datatime) O Python对象
S, a 字符串 U Unicode V 原始数据类型

还可以将两个字符作为参数传给数据类型的构造函数。此时,第一个字符表示数据类型,第二个字符表示该类型在内存中占用的字节数(f2、f4、f8分别表示16、32、64位浮点数)数据类型长度如何选择

数据类型对象 (dtype)

数据类型对象描述了对应于数组的固定内存块的解释,取决于以下方面:

  • 数据类型(整数、浮点或者 Python 对象)
  • 数据大小
  • 字节序(小端或大端)
  • 在结构化类型的情况下,字段的名称,每个字段的数据类型,和每个字段占用的内存块部分。
  • 如果数据类型是子序列,它的形状和数据类型。

字节顺序取决于数据类型的前缀<><意味着编码是小端(最小有效字节存储在最小地址中)。 >意味着编码是大端(最大有效字节存储在最小地址中)。

dtype可由一下语法构造

1
numpy.dtype(object, align, copy)

参数为:

  • Object:被转换为数据类型的对象。
  • Align:如果为true,则向字段添加间隔,使其类似 C 的结构体。
  • Copy : 生成dtype对象的新副本,如果为flase,结果是内建数据类型对象的引用。

案例1

1
2
3
4
5
6
7
8
9
10
# 使用数组标量类型  
import numpy as np
dt1 = np.dtype(np.int32)
print(dt1, type(dt1))
# int8,int16,int32,int64 可替换为等价的字符串 'i1','i2','i4',以及其他。
dt2 = np.dtype('i4')
print(dt2, type(dt2))
# 使用端记号
dt3 = np.dtype('>i4')
print(dt3, type(dt3))

输出如下:

1
2
3
int32 <class 'numpy.dtype[int32]'>
int32 <class 'numpy.dtype[int32]'>
>i4 <class 'numpy.dtype[int32]'>

案例2

以下示例定义名为 student结构化数据类型,其中包含字符串字段name整数字段age浮点字段marks。 此dtype应用于ndarray对象。

1
2
3
4
5
6
7
import numpy as np

# 就类似结构体定义
student = np.dtype([('name', 'S20'), ('age', 'i1'), ('marks', 'f4')])
print(student)
array = np.array([tuple(['abc', 21, 50]),('xyz', 18, 75)], dtype=student)
print(array)

输出为:

1
2
[('name', 'S20'), ('age', 'i1'), ('marks', '<f4')]
[(b'abc', 21, 50.) (b'xyz', 18, 75.)]

案例

1
2
3
4
5
6
import numpy as np

array1 = np.array(range(10), dtype='i')
print(array1) # 输出为 [0 1 2 3 4 5 6 7 8 9]
array2 = np.array(range(10), dtype='f')
print(array2) # 输出为 [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]

3、NumPy - 数组属性

  • shape

这一数组属性返回一个包含数组维度的元组,它也可以用于调整数组大小。

案例

1
2
3
4
5
6
7
8
9
10
import numpy as np

array = np.array([[1,2,3],[4,5,6]])
print(array.shape, id(array))
print(array)
# 调整数组
array.shape = (3, 2)
print(array.shape, id(array))
print(array)
# 没有产生新的对象

输出为:

1
2
3
4
5
6
7
(2, 3) 2083924122672
[[1 2 3]
[4 5 6]]
(3, 2) 2083924122672
[[1 2]
[3 4]
[5 6]]
  • reshape()

NumPy 也提供了reshape()函数来调整数组大小。

案例1

1
2
3
4
5
import numpy as np 

a = np.array([[1,2,3],[4,5,6]])
b = a.reshape(3,2) # 未改变a
print(b)

输出如下:

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

案例2

1
2
3
4
5
6
7
# 一维数组  
import numpy as np

a = np.arange(24)
# 现在调整其大小
b = a.reshape(2,4,3) # b 现在拥有三个维度
print(b)

输出如下:

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

[[12 13 14]
[15 16 17]
[18 19 20]
[21 22 23]]]
  • ndarray.ndim

    这一数组属性返回数组的维数。

  • numpy.itemsize

    这一数组属性返回数组中每个元素的字节单位长度。

1
2
3
4
import numpy as np

array = np.array([[1,2,3], [4,5,6]], dtype='i4')
print(array.ndim, array.itemsize) # 输出为 2 4
  • numpy.size

    元素总个数

1
2
3
4
import numpy as np

array = np.array([[1, 2, 3], [2, 3, 4]])
print(array.size) # 输出为 6
  • numpy.dtype

    元素类型

  • numpy.astype()

    numpy数据类型转换,返回数据类型修改后的数据,但是原数据类型不变

1
2
3
4
5
6
import numpy as np

arrayA = np.array([[1, 2, 3], [2, 3, 4]])
print(arrayA.dtype) # 输出为 int32
arrayB = arrayA.astype('float')
print(arrayA.dtype, arrayB.dtype) # 输出为 int32 float64

4、NumPy - 创建数组

新的ndarray对象可以通过任何下列数组创建例程或使用低级ndarray构造函数构造。

  • numpy.empty()

它创建指定形状和dtype的未初始化数组。 它使用以下构造函数:

1
numpy.empty(shape, dtype = float, order = 'C')

构造器接受下列参数:

序号 参数及描述
1 shape 空数组的形状,整数或整数元组
2 dtype 所需的输出数组类型,可选
3 order 'C'为按行的 C 风格数组,'F'为按列的 Fortran 风格数组

案例

下面的代码展示空数组的例子:

1
2
3
4
5
import numpy as np

array1 = np.empty((3,2), dtype=int)
# array1 = np.empty([3,2], dtype=int) # 效果同上
print(array1)

输出为

1
2
3
[[22649312    1701344351] 
[1818321759 1885959276]
[16779776 156368896]]

注意:数组元素为随机值,因为它们未初始化

  • numpy.zeros() / numpy.ones()

返回特定大小,以 0 / 1 填充的新数组。

1
numpy.zeros(shape, dtype = float, order = 'C')

构造器接受下列参数:

序号 参数及描述
1 Shape 空数组的形状,整数或整数元组
2 Dtype 所需的输出数组类型,可选
3 Order 'C'为按行的 C 风格数组,'F'为按列的 Fortran 风格数组

案例

1
2
3
4
5
6
7
8
9
import numpy as np

array1 = np.zeros(5) # 含有 5 个 0 的数组,默认类型为 float
print(array1)
array2 = np.zeros((2, 2))
print(array2)
dt = np.dtype([('name', 'S20'), ('age', 'i4')])
array3 = np.zeros((2,2), dtype=dt)
print(array3)

输出为

1
2
3
4
5
[0. 0. 0. 0. 0.]
[[0. 0.]
[0. 0.]]
[[(b'', 0) (b'', 0)]
[(b'', 0) (b'', 0)]]

5、NumPy - 来自现有数据的数组

这一章中,我们会讨论如何从现有数据创建数组。

  • numpy.asarray()

此函数类似于numpy.array,除了它有较少的参数。 这个例程对于将 Python 序列转换为ndarray非常有用。

1
numpy.asarray(a, dtype=None, order=None)

构造器接受下列参数:

序号 参数及描述
1 a 任意形式的输入参数,比如列表、列表的元组、元组、元组的元组、元组的列表
2 dtype 通常,输入数据的类型会应用到返回的ndarray
3 order 'C'为按行的 C 风格数组,'F'为按列的 Fortran 风格数组

下面的例子展示了如何使用asarray函数:

案例

1
2
3
4
5
6
7
8
9
# 将列表转换为 ndarray
import numpy as np

lst1 = [1, 2, 3]
array1 = np.asarray(lst1)
print(array1)
lst2 = [(1, 2, 3), (4, 5, 6)]
array2 = np.asarray(lst2)
print(array2)

输出为

1
2
3
[1 2 3]
[[1 2 3]
[4 5 6]]
  • numpy.frombuffer()

此函数将缓冲区解释为一维数组。 暴露缓冲区接口的任何对象都用作参数来返回ndarray

1
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

构造器接受下列参数:

序号 参数及描述
1 buffer 任何暴露缓冲区借口的对象
2 dtype 返回数组的数据类型,默认为float
3 count 需要读取的数据数量,默认为-1,读取所有数据
4 offset 需要读取的起始位置,默认为0

案例

下面的例子展示了frombuffer函数的用法。

1
2
3
4
5
import numpy as np

lst = b'helloworld'
array = np.frombuffer(lst, dtype='S1')
print(array)

输出如下:

1
[b'h' b'e' b'l' b'l' b'o' b'w' b'o' b'r' b'l' b'd']
  • numpy.fromiter()

此函数从任何可迭代对象构建一个ndarray对象,返回一个新的一维数组。

1
numpy.fromiter(iterable, dtype, count = -1)

构造器接受下列参数:

序号 参数及描述
1. iterable 任何可迭代对象
2. dtype 返回数组的数据类型
3. count 需要读取的数据数量,默认为-1,读取所有数据

以下示例展示了如何使用内置的range()函数返回列表对象。 此列表的迭代器用于形成ndarray对象。

案例

1
2
3
4
5
6
7
8
9
# 从列表中获得迭代器
import numpy as np

lst = range(5)
it = iter(lst)
# 使用迭代器创建 ndarray
# iter() 方法是python的内置函数,它可以将字符串、列表、元组等容器变成迭代器
x = np.fromiter(it, dtype=float)
print(x) # 输出为 [0. 1. 2. 3. 4.]

6、NumPy - 来自数值范围的数组

这一章中,我们会学到如何从数值范围创建数组。

  • numpy.arange()

这个函数返回ndarray对象,包含给定范围内的等间隔值。

1
numpy.arange(start, stop, step, dtype)

构造器接受下列参数:

序号 参数及描述
1 start 范围的起始值,默认为0
2 stop 范围的终止值(不包含)
3 step 两个值的间隔,默认为1
4 dtype 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

下面的例子展示了如何使用该函数:

案例

1
2
3
4
5
6
7
import numpy as np

array1 = np.arange(5)
print(array1) # 输出为 [0 1 2 3 4]
# 设置了 dtype
array2 = np.arange(5, dtype=float)
print(array2) # 输出为 [0. 1. 2. 3. 4.]
  • numpy.linspace()

此函数类似于arange()函数。 在此函数中,指定了范围之间的均匀间隔数量,而不是步长。 此函数的用法如下。

1
numpy.linspace(start, stop, num, endpoint, retstep, dtype)

构造器接受下列参数:

序号 参数及描述
1 start 序列的起始值
2 stop 序列的终止值,如果endpointtrue,该值包含于序列中
3 num 要生成的等间隔样例数量,默认为50
4 endpoint 序列中是否包含stop值,默认为ture
5 retstep 如果为true,返回样例,以及连续数字之间的步长
6 dtype 输出ndarray的数据类型

下面的例子展示了linspace()函数的用法。

案例

1
2
3
4
5
6
7
8
9
import numpy as np

array1 = np.linspace(10, 20, 5)
print(array1) # 输出为 [10. 12.5 15. 17.5 20. ]
array2 = np.linspace(10, 20, 5, endpoint=False)
print(array2) # 输出为 [10. 12. 14. 16. 18.]
# 输出 retstep 值
array3 = np.linspace(10, 20, 5, endpoint=False, retstep=True)
print(array3) # 输出为 (array([10., 12., 14., 16., 18.]), 2.0)
  • numpy.logspace()

此函数返回一个ndarray对象,其中包含在对数刻度上均匀分布的数字。 刻度的开始和结束端点是某个底数的幂,通常为 10。

1
numpy.logscale(start, stop, num, endpoint, base, dtype)

logspace函数的输出由以下参数决定:

序号 参数及描述
1 start 起始值是base ** start(base:底数)
2 stop 终止值是base ** stop
3 num 范围内的数值数量,默认为50
4 endpoint 如果为true,终止值包含在输出数组当中
5 base 对数空间的底数,默认为10
6 dtype 输出数组的数据类型,如果没有提供,则取决于其它参数

下面的例子展示了logspace函数的用法。

案例

1
2
3
4
5
6
7
8
import numpy as np
# 默认底数是 10

array1 = np.logspace(1.0, 2.0, num=10)
print(array1)
# 设置底数为 2
array2 = np.logspace(1, 10, num=10, base=2)
print(array2)

输出为:

1
2
3
[ 10.          12.91549665  16.68100537  21.5443469   27.82559402
35.93813664 46.41588834 59.94842503 77.42636827 100. ]
[ 2. 4. 8. 16. 32. 64. 128. 256. 512. 1024.]

7、NumPy - 切片和索引

ndarray对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样。
如前所述,ndarray对象中的元素遵循基于零的索引。 有三种可用的索引方法类型: 字段访问,基本切片高级索引

  • 基本切片

基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将startstopstep参数提供给内置的slice()函数来构造一个 Python slice()对象。 此slice对象被传递给数组来提取数组的一部分。

案例

1
2
3
4
5
import numpy as np

array = np.arange(10)
s = slice(2,7,2)
print(array[s]) # 输出为 [2 4 6]

在上面的例子中,ndarray对象由arange()函数创建。 然后,分别用起始,终止和步长值272定义切片对象。 当这个切片对象传递给ndarray时,会对它的一部分进行切片,从索引27,步长为2

  • 冒号分隔的切片

通过将由冒号分隔的切片参数(start:stop:step)直接提供给ndarray对象,也可以获得相同的结果。

案例

1
2
3
4
5
import numpy as np

array = np.arange(10)
b = array[2:7:2]
print(b) # 输出为 [2 4 6]

如果只输入一个参数,则将返回与索引对应的单个项目。 如果使用a:,则从该索引向后的所有项目将被提取。 如果使用两个参数(以:分隔),则对两个索引(不包括停止索引)之间的元素以默认步骤进行切片。

案例1

1
2
3
4
5
6
7
8
import numpy as np

array = np.arange(10)
# 对单个元素进行切片
print(array[5]) # 输出为 5
# 对始于索引的元素进行切片
print(array[2:]) # 输出为 [2 3 4 5 6 7 8 9]
print(array[2:5]) # 输出为 [2 3 4]

上面的描述也可用于多维ndarray

案例2

1
2
3
4
5
6
7
8
9
10
import numpy as np

array = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(array)
# 对始于索引的元素进行切片
print('现在我们从索引 a[1:] 开始对数组切片')
print(array[1:])
print('二次索引取得')
print(array[1])
print(array[1][2])

输出如下:

1
2
3
4
5
6
7
8
9
[[1 2 3]
[3 4 5]
[4 5 6]]
现在我们从索引 a[1:] 开始对数组切片
[[3 4 5]
[4 5 6]]
二次索引取得
[3 4 5]
5

切片还可以包括省略号(...),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray

案例3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 最开始的数组
import numpy as np

array = np.array([[1,2,3],[3,4,5],[4,5,6]])
print('我们的数组是:')
print(array)
# 这会返回第二列元素的数组:
print('第二列的元素是:')
print(array[...,1])
# 现在我们从第二行切片所有元素:
print('第二行的元素是:' )
print(array[1,...])
# 现在我们从第二列向后切片所有元素:
print('第二列及其剩余元素是:')
print(array[...,1:])

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
我们的数组是:
[[1 2 3]
[3 4 5]
[4 5 6]]
第二列的元素是:
[2 4 5]
第二行的元素是:
[3 4 5]
第二列及其剩余元素是:
[[2 3]
[4 5]
[5 6]]
  • np.where()

获取值的索引

1
2
3
import numpy as np
array = np.array([1,0,1,3,1,0])
print(np.where(array == 0))

8、NumPy - 高级索引

如果一个ndarray是非元组序列,数据类型为整数或布尔值的ndarray,或者至少一个元素为序列对象的元组,我们就能够用它来索引ndarray。高级索引始终返回数据的副本。 与此相反,切片只提供了一个视图。

有两种类型的高级索引:整数和布尔值。

8.1、整数索引

这种机制有助于基于 N 维索引来获取数组中任意元素。 每个整数数组表示该维度的下标值。 当索引的元素个数就是目标ndarray的维度时,会变得相当直接。

以下示例获取了ndarray对象中每一行指定列的一个元素。 因此,行索引包含所有行号,列索引指定要选择的元素。

案例1

1
2
3
4
5
6
7
import numpy as np

array = np.array([[1, 2], [3, 4], [5, 6]])
print('原数组')
print(array)
res = array[[0, 1, 2], [0, 1, 0]] # (0, 0), (1, 1), (2, 0),(第几行, 第几列)的值
print(res) # 输出为 [1 4 5]

输出为

1
2
3
4
5
原数组
[[1 2]
[3 4]
[5 6]]
[1 4 5]

下面的示例获取了 4X3 数组中的每个角处的元素。 行索引是[0,0][3,3],而列索引是[0,2][0,2]

案例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np

array = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print('我们的数组是:')
print(array)
rows1 = np.array([[0,0],[3,3]])
cols1 = np.array([[0,2],[0,2]])
res1 = array[rows1, cols1] # 行索引,列索引
print('这个数组的每个角处的元素是:')
print(res1)
cols2 = np.array([0,2,0,2])
rows2 = np.array([0,0,3,3])
res2 = array[rows2, cols2] # 行索引,列索引
print('这个数组的每个角处的元素是:')
print(res2)

输出如下:

1
2
3
4
5
6
7
8
9
10
我们的数组是:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
这个数组的每个角处的元素是:
[[ 0 2]
[ 9 11]]
这个数组的每个角处的元素是:
[ 0 2 9 11]

返回的结果是包含每个角元素的ndarray对象。

高级和基本索引可以通过使用切片:或省略号...与索引数组组合。 以下示例使用slice作为列索引和高级索引。 当切片用于两者时,结果是相同的。 但高级索引会导致复制,并且可能有不同的内存布局。

案例3

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np

array = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print('我们的数组是:')
print(array)
# 切片
res1 = array[1:4, 1:3] # 行切片,列切片
print('切片之后,我们的数组变为:')
print(res1)
# 对列使用高级索引
res2 = array[1:4, [1, 2]] # 行切片,列索引
print('对列使用高级索引来切片:')
print(res2)

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
我们的数组是:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
切片之后,我们的数组变为:
[[ 4 5]
[ 7 8]
[10 11]]
对列使用高级索引来切片:
[[ 4 5]
[ 7 8]
[10 11]]

8.2、布尔索引

当结果对象是布尔运算(例如比较运算符)的结果时,将使用此类型的高级索引。
提取出为True的元素

案例1

这个例子中,大于 5 的元素会作为布尔索引的结果返回。

1
2
3
4
5
6
7
8
import numpy as np 

array = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print('我们的数组是:')
print(array)
# 现在我们会打印出大于 5 的元素
print('大于 5 的元素是:')
print(array[array > 5])

输出如下:

1
2
3
4
5
6
7
我们的数组是:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
大于 5 的元素是:
[ 6 7 8 9 10 11]

案例2

这个例子使用了 ~(取补运算符)来过滤NaN

1
2
3
4
import numpy as np

array = np.array([np.nan, 1, 2, np.nan, 3, 4, 5])
print(array[~np.isnan(array)]) # 输出为 [1. 2. 3. 4. 5.]

案例3

以下示例显示如何从数组中过滤掉非复数元素。

1
2
3
4
import numpy as np

array = np.array([1, 2 + 6j, 5, 3.5 + 5j])
print(array[np.iscomplex(array)]) # 输出为 [2. +6.j 3.5+5.j]

案例4

  • numpy.argwhere()

    该函数返回数组中非 0 元素的索引,若是多维数组则返回行、列索引组成的索引坐标.

9、NumPy - 广播

术语广播是指 NumPy 在算术运算期间处理不同形状的数组的能力。 对数组的算术运算通常在相应的元素上进行。 如果两个阵列具有完全相同的形状,则这些操作被无缝执行。

案例1

1
2
3
4
5
6
import numpy as np

arrayA = np.array([1, 2, 3, 4])
arrayB = np.array([10, 20, 30, 40])
arrayC = arrayA * arrayB
print(arrayC) # 输出为 [ 10 40 90 160]

如果两个数组的维数不相同,则元素到元素的操作是不可能的。 然而,在 NumPy 中仍然可以对形状不相似的数组进行操作,因为它拥有广播功能。 较小的数组会广播到较大数组的大小,以便使它们的形状可兼容。

如果满足以下规则,可以进行广播

  • ndim较小的数组会在前面追加一个长度为 1 的维度。
  • 输出数组的每个维度的大小是输入数组该维度大小的最大值。
  • 如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则在计算中可它。
  • 如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。

如果上述规则产生有效结果,并且满足以下条件之一,那么数组被称为可广播的

  • 数组拥有相同形状。
  • 数组拥有相同的维数,每个维度拥有相同长度,或者长度为 1。
  • 数组拥有极少的维度,可以在其前面追加长度为 1 的维度,使上述条件成立。

对于广播规则另一种简单理解

  • 将两个数组的维度大小右对齐,然后比较对应维度上的数值
  • 如果数值相等或其中有一个为1或者为空,则能进行广播运算
  • 输出的维度大小为取数值大的数值。否则不能进行数组运算

案例2

1
2
3
4
5
6
7
8
9
10
import numpy as np

arrayA = np.array([[0.0, 0.0, 0.0], [10.0, 10.0, 10.0], [20.0, 20.0, 20.0], [30.0, 30.0, 30.0]])
arrayB = np.array([1.0, 2.0, 3.0])
print('第一个数组:')
print(arrayA)
print('第二个数组:')
print(arrayB)
print('第一个数组加第二个数组:')
print(arrayA + arrayB)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
第一个数组:
[[ 0. 0. 0.]
[10. 10. 10.]
[20. 20. 20.]
[30. 30. 30.]]
第二个数组:
[1. 2. 3.]
第一个数组加第二个数组:
[[ 1. 2. 3.]
[11. 12. 13.]
[21. 22. 23.]
[31. 32. 33.]]

案例2如何通过广播来兼容

10、NumPy - 数组上的迭代

NumPy 包包含一个迭代器对象numpy.nditer。 它是一个有效的多维迭代器对象,可以用于在数组上进行迭代。 数组的每个元素可使用 Python 的标准Iterator接口来访问。

案例1

让我们使用arange()函数创建一个 3X4 数组,并使用nditer对它进行迭代。

1
2
3
4
5
6
7
8
9
import numpy as np

a = np.arange(0,60,5)
a.shape = (3,4)
print('原始数组是:')
print(a)
print('迭代结果为')
for x in np.nditer(a):
print(x, end=' ')

输出为

1
2
3
4
5
6
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
迭代结果为
0 5 10 15 20 25 30 35 40 45 50 55

案例2

迭代的顺序匹配数组的内容布局,而不考虑特定的排序。 这可以通过迭代上述数组的转置来看到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np

array = np.arange(0, 60, 5)
array.shape = (3, 4)
print('原始数组是:')
print(array)
print('原数组迭代:')
for x in np.nditer(array):
print(x, end=' ')
t = array.T
print('\n转置后:')
print(t)
print('转置后的数组是:')
for x in np.nditer(t):
print(x, end=' ')

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
原数组迭代:
0 5 10 15 20 25 30 35 40 45 50 55
转置后:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
转置后的数组是:
0 5 10 15 20 25 30 35 40 45 50 55

10.1、迭代顺序

如果相同元素使用 F 风格顺序存储,则迭代器选择以更有效的方式对数组进行迭代。

案例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

array = np.arange(0, 60, 5)
array.shape = (3, 4)
print('原始数组是:')
print(array)
print('以 C 风格顺序排序:')
c = array.copy(order='C')
print(c)
print('迭代(C):')
for x in np.nditer(c):
print(x, end=' '),
print('\n以 F 风格顺序排序:')
f = array.copy(order='F')
print(f)
print('迭代(F):')
for x in np.nditer(f):
print(x, end=' ')

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
以 C 风格顺序排序:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
迭代(C):
0 5 10 15 20 25 30 35 40 45 50 55
以 F 风格顺序排序:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
迭代(F):
0 20 40 5 25 45 10 30 50 15 35 55

案例2

可以通过显式提醒,来强制nditer对象使用某种顺序:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array = np.arange(0, 60, 5)
array.shape = (3, 4)
print('原始数组是:')
print(array)
print('以 C 风格顺序排序:')
for x in np.nditer(array, order='C'):
print(x, end=' ')
print('\n以 F 风格顺序排序:')
for x in np.nditer(array, order='F'):
print(x, end=' ')

输出为

1
2
3
4
5
6
7
8
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
以 C 风格顺序排序:
0 5 10 15 20 25 30 35 40 45 50 55
以 F 风格顺序排序:
0 20 40 5 25 45 10 30 50 15 35 55

10.2、修改数组的值

nditer对象有另一个可选参数op_flags。 其默认值为只读,但可以设置为读写或只写模式。 这将允许使用此迭代器修改数组元素。

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np

array = np.arange(0, 60, 5)
array.shape = (3, 4)
print('原始数组是:')
print(array)
array[0, 0] = 2
print('修改左上角为2:')
print(array[0, 0])
print('迭代器修改:')
for i in np.nditer(array, op_flags=['readwrite']):
# i = 2 * i # 这个结果是未得到修改
i[...] = 2 * i
print(array)

输出为

1
2
3
4
5
6
7
8
9
10
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
修改左上角为2:
2
迭代器修改:
[[ 4 10 20 30]
[ 40 50 60 70]
[ 80 90 100 110]]

测试上面的案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

array = np.arange(2)
array.shape = (2, 1)
print('原数组为:')
print(array)
print('数组地址元素地址为:')
print('第1个元素:')
print(id(array[0, 0]))
print(id(array[0, 0][...]))
print('第2个元素:')
print(id(array[1, 0]))
print(id(array[1, 0][...]))
print('迭代器结果:')
for i in np.nditer(array, op_flags=['readwrite']):
print(f'第{i}个元素:')
print(id(i))
print(id(i[...]))

结果为:

10.3、外部循环

nditer类的构造器拥有flags参数,它可以接受下列值:

序号 参数及描述
1 c_index 可以跟踪 C 顺序的索引
2 f_index 可以跟踪 Fortran 顺序的索引
3 multi-index 每次迭代可以跟踪一种索引类型
4 external_loop 给出的值是具有多个值的一维数组,而不是零维数组

案例

在下面的示例中,迭代器遍历对应于每列的一维数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np

array = np.arange(0, 60, 5)
array.shape = (3, 4)
print('原始数组是:')
print(array)
print('c_index:')
for x in np.nditer(array, flags=['c_index'], order='F'):
print(x, end=' ')
print('\nf_index:')
for x in np.nditer(array, flags=['f_index'], order='F'):
print(x, end=' ')
print('\nmulti_index:')
for x in np.nditer(array, flags=['multi_index'], order='F'):
print(x, end=' ')
print('\nexternal_loop \'F\':')
for x in np.nditer(array, flags=['external_loop'], order='F'):
print(x, end=' ')
print('\nexternal_loop \'C\':')
for x in np.nditer(array, flags=['external_loop'], order='C'):
print(x, end=' ')

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
c_index:
0 20 40 5 25 45 10 30 50 15 35 55
f_index:
0 20 40 5 25 45 10 30 50 15 35 55
multi_index:
0 20 40 5 25 45 10 30 50 15 35 55
external_loop 'F':
[ 0 20 40] [ 5 25 45] [10 30 50] [15 35 55]
external_loop 'C':
[ 0 5 10 15 20 25 30 35 40 45 50 55]

10.4、广播迭代

如果两个数组是可广播的nditer组合对象能够同时迭代它们。 假设数组a具有维度 3X4,并且存在维度为 1X4 的另一个数组b,则使用以下类型的迭代器(数组b被广播到a的大小)。

案例

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array1 = np.arange(0, 60, 5)
array1 = array1.reshape(3, 4)
print('第一个数组:')
print(array1)
print('第二个数组:')
array2 = np.array([1, 2, 3, 4], dtype=int)
print(array2)
print('迭代结果:')
for x, y in np.nditer([array1, array2]):
print(f'{x}:{y}', end=' ')

输出为

1
2
3
4
5
6
7
8
第一个数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
第二个数组:
[1 2 3 4]
迭代结果:
0:1 5:2 10:3 15:4 20:1 25:2 30:3 35:4 40:1 45:2 50:3 55:4

11、NumPy - 数组操作

NumPy包中有几个例程用于处理ndarray对象中的元素。 它们可以分为以下类型:

11.0、NumPy的轴

11.1、修改形状

序号 形状及描述
1 reshape 不改变数据的条件下修改形状
2 flat 数组上的一维迭代器
3 flatten 返回折叠为一维的数组副本
4 ravel 返回连续的展开数组
  • numpy.reshape()

这个函数在不改变数据的条件下修改形状,它接受如下参数:

1
numpy.reshape(arr, newshape, order)

其中:

  • arr:要修改形状的数组
  • newshape:整数或者整数数组,新的形状应当兼容原有形状;(-1, 2),-1表示行自动变化,2表示两列
  • order'C'为 C 风格顺序,'F'为 F 风格顺序,'A'为保留原顺序。

案例

1
2
3
4
5
6
7
8
9
import numpy as np

arrayA = np.arange(8)
print('原始数组:')
print(arrayA)
# arrayB = arrayA.reshape(2, 4)
arrayB = np.reshape(arrayA, (2, 4))
print('修改后的数组:')
print(arrayB)

输出为

1
2
3
4
5
原始数组:
[0 1 2 3 4 5 6 7]
修改后的数组:
[[0 1 2 3]
[4 5 6 7]]
  • numpy.ndarray.flat

该函数返回数组上的一维迭代器,行为类似 Python 内建的迭代器。

案例

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array = np.arange(8).reshape(2, 4)
print('原始数组:')
print(array)
print('调用 flat 函数之后:')
print(array.flat)
# 返回展开数组中的下标的对应元素
print(array.flat[5])
print('for-in 迭代:')
for i in array.flat:
print(i, end=' ')

输出为

1
2
3
4
5
6
7
8
原始数组:
[[0 1 2 3]
[4 5 6 7]]
调用 flat 函数之后:
<numpy.flatiter object at 0x000002E0449B2390>
5
for-in 迭代:
0 1 2 3 4 5 6 7
  • numpy.ndarray.flatten()

该函数返回折叠为一维的数组副本,函数接受下列参数:

1
ndarray.flatten(order)

其中:

  • order'C' – 按行,'F' – 按列,'A' – 原顺序,'k' – 元素在内存中的出现顺序。

案例

1
2
3
4
5
6
7
8
9
10
import numpy as np

array = np.arange(8).reshape(2, 4)
print('原数组:')
print(array)
# default is column-major
print('展开的数组:')
print(array.flatten())
print('以 F 风格顺序展开的数组:')
print(array.flatten(order='F'))

输出为

1
2
3
4
5
6
7
原数组:
[[0 1 2 3]
[4 5 6 7]]
展开的数组:
[0 1 2 3 4 5 6 7]
以 F 风格顺序展开的数组:
[0 4 1 5 2 6 3 7]
  • numpy.ravel()

这个函数返回展开的一维数组,并且按需生成副本。返回的数组和输入数组拥有相同数据类型。这个函数接受两个参数。

1
numpy.ravel(a, order)

构造器接受下列参数:

  • order'C' – 按行,'F' – 按列,'A' – 原顺序,'k' – 元素在内存中的出现顺序。

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

array = np.arange(8).reshape(2, 4)
print('原数组:')
print(array)
print('调用 ravel 函数之后:')
# print(a.ravel()) # 效果相同
print(np.ravel(array))
print('以 F 风格顺序调用 ravel 函数之后:')
# print(a.ravel(order='F')) # 效果相同
print(np.ravel(array, order='F'))

输出为

1
2
3
4
5
6
7
原数组:
[[0 1 2 3]
[4 5 6 7]]
调用 ravel 函数之后:
[0 1 2 3 4 5 6 7]
以 F 风格顺序调用 ravel 函数之后:
[0 4 1 5 2 6 3 7]

11.2、翻转操作

序号 操作及描述
1 transpose 翻转数组的维度
2 ndarray.Tself.transpose()相同
3 rollaxis 向后滚动指定的轴
4 swapaxes 互换数组的两个轴
  • numpy.transpose()

这个函数翻转给定数组的维度。如果可能的话它会返回一个视图。函数接受下列参数:

1
numpy.transpose(arr, axes)

其中:

arr:要转置的数组

axes:整数的列表,对应维度,通常所有维度都会翻转。

案例

1
2
3
4
5
6
7
8
9
import numpy as np

array = np.arange(6).reshape(2, 3)
print('原数组:')
print(array)
print('转置数组:')
print(np.transpose(array))
# print(array.transpose()) # 效果相同
# print(array.T) # 效果相同

输出为

1
2
3
4
5
6
7
原数组:
[[0 1 2]
[3 4 5]]
转置数组:
[[0 3]
[1 4]
[2 5]]
  • numpy.ndarray.T

该函数属于ndarray类,行为类似于numpy.transpose

案例

1
# 同上
  • numpy.rollaxis()

该函数向后滚动特定的轴,直到一个特定位置。这个函数接受三个参数:

1
numpy.rollaxis(arr, axis, start)

其中:

  • arr:输入数组
  • axis:要向后滚动的轴,其它轴的相对位置不会改变
  • start:默认为零,表示完整的滚动。会滚动到特定位置。

案例

1
2
3
4
5
6
7
8
9
10
11
12
# 创建了三维的 ndarray
import numpy as np

array = np.arange(8).reshape(2, 2, 2)
print('原数组:')
print(array)
# 将轴 2 滚动到轴 0(宽度到深度)
print('调用 rollaxis 函数:')
print(np.rollaxis(array, 2))
# 将轴 0 滚动到轴 1:(宽度到高度)
print('调用 rollaxis 函数:')
print(np.rollaxis(array, 2, 1))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
原数组:
[[[0 1]
[2 3]]

[[4 5]
[6 7]]]
调用 rollaxis 函数:
[[[0 2]
[4 6]]

[[1 3]
[5 7]]]
调用 rollaxis 函数:
[[[0 2]
[1 3]]

[[4 6]
[5 7]]]
  • numpy.swapaxes()

该函数交换数组的两个轴。对于 1.10 之前的 NumPy 版本,会返回交换后数组的试图。这个函数接受下列参数:

1
numpy.swapaxes(arr, axis1, axis2)
  • arr:要交换其轴的输入数组
  • axis1:对应第一个轴的整数
  • axis2:对应第二个轴的整数

案例

1
2
3
4
5
6
7
8
import numpy as np

array = np.arange(8).reshape(2, 2, 2)
print('原数组:')
print(array)
# 现在交换轴 0(深度方向)到轴 2(宽度方向)
print('调用 swapaxes 函数后的数组:')
print(np.swapaxes(array, 2, 0))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
原数组:
[[[0 1]
[2 3]]

[[4 5]
[6 7]]]
调用 swapaxes 函数后的数组:
[[[0 4]
[2 6]]

[[1 5]
[3 7]]]

11.3、修改维度

序号 维度和描述
1 broadcast() 产生模仿广播的对象
2 broadcast_to() 将数组广播到新形状
3 expand_dims() 扩展数组的形状
4 squeeze() 从数组的形状中删除单维条目
  • broadcast()

如前所述,NumPy 已经内置了对广播的支持。 此功能模仿广播机制。 它返回一个对象,该对象封装了将一个数组广播到另一个数组的结果。

该函数使用两个数组作为输入参数。 下面的例子说明了它的用法。

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
import numpy as np

x = np.array([[1], [2], [3]])
y = np.array([4, 5, 6])
# 对 y 广播 x
arrayA = np.broadcast(x, y)
# 它拥有 iterator 属性,基于自身组件的迭代器元组
print('对 y 广播 x:')
r, arrayB = arrayA.iters
print(next(r), next(arrayB))
print(next(r), next(arrayB))
# shape 属性返回广播对象的形状
print('广播对象的形状:')
print(arrayA.shape)
# 手动使用 broadcast 将 x 与 y 相加
arrayA = np.broadcast(x, y)
arrayB = np.empty(arrayA.shape)
print('手动使用 broadcast 将 x 与 y 相加:')
print(arrayB.shape)
arrayB.flat = [u + v for (u, v) in arrayA]
print('调用 flat 函数:')
print(arrayB)
# 获得了和 NumPy 内建的广播支持相同的结果
print('x 与 y 的和:')
print(x + y)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
对 y 广播 x:
1 4
1 5
广播对象的形状:
(3, 3)
手动使用 broadcast 将 x 与 y 相加:
(3, 3)
调用 flat 函数:
[[5. 6. 7.]
[6. 7. 8.]
[7. 8. 9.]]
x 与 y 的和:
[[5 6 7]
[6 7 8]
[7 8 9]]
  • numpy.broadcast_to()

此函数将数组广播到新形状。 它在原始数组上返回只读视图。 它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError

注意 - 此功能可用于 1.10.0 及以后的版本。

该函数接受以下参数。

1
numpy.broadcast_to(array, shape, subok)

案例

1
2
3
4
5
6
7
import numpy as np

array = np.arange(4).reshape(1, 4)
print('原数组:')
print(array)
print('调用 broadcast_to 函数之后:')
print(np.broadcast_to(array, (4, 4)))

输出为

1
2
3
4
5
6
7
原数组:
[[0 1 2 3]]
调用 broadcast_to 函数之后:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
  • numpy.expand_dims()

函数通过在指定位置插入新的轴来扩展数组形状。该函数需要两个参数:

1
numpy.expand_dims(arr, axis)

其中:

arr:输入数组

axis:新轴插入的位置

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np

arrayX = np.array(([1, 2], [3, 4]))
print('数组X:')
print(arrayX)
arrayY = np.expand_dims(arrayX, axis=0)
print('数组Y:')
print(arrayY)
print('数组 x 和 y 的形状:', arrayX.shape, arrayY.shape)
# 在位置 1 插入轴
arrayY = np.expand_dims(arrayX, axis=1)
print('在位置 1 插入轴之后的数组 y:')
print(arrayY)
print('x.ndim 和 y.ndim:', arrayX.ndim, arrayY.ndim)
print('x.shape 和 y.shape:', arrayX.shape, arrayY.shape)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
数组X:
[[1 2]
[3 4]]
数组Y:
[[[1 2]
[3 4]]]
数组 x 和 y 的形状: (2, 2) (1, 2, 2)
在位置 1 插入轴之后的数组 y:
[[[1 2]]

[[3 4]]]
x.ndim 和 y.ndim: 2 3
x.shape 和 y.shape: (2, 2) (2, 1, 2)
  • numpy.squeeze()

函数从给定数组的形状中删除一维条目。 此函数需要两个参数。

1
numpy.squeeze(arr, axis)

其中:

arr:输入数组

axis:整数或整数元组,用于选择形状中单一维度条目的子集

案例

1
2
3
4
5
6
7
8
9
import numpy as np

arrayX = np.arange(9).reshape(1, 3, 3)
print('数组 X:')
print(arrayX)
arrayY = np.squeeze(arrayX)
print('数组 Y:')
print(arrayY)
print('数组 x 和 y 的形状:', arrayX.shape, arrayY.shape)

输出为

1
2
3
4
5
6
7
8
9
数组 X:
[[[0 1 2]
[3 4 5]
[6 7 8]]]
数组 Y:
[[0 1 2]
[3 4 5]
[6 7 8]]
数组 x 和 y 的形状: (1, 3, 3) (3, 3)

11.4、数组的连接

序号 数组及描述
1 concatenate() 沿着现存的轴连接数据序列
2 stack() 沿着新轴连接数组序列
3 hstack() 水平堆叠序列中的数组(列方向)
4 vstack() 竖直堆叠序列中的数组(行方向)
  • numpy.concatenate()

数组的连接是指连接。 此函数用于沿指定轴连接相同形状的两个或多个数组。 该函数接受以下参数。

1
numpy.concatenate((a1, a2, ...), axis)

其中:

a1, a2, ...相同类型的数组序列

axis:沿着它连接数组的轴,默认为 0

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np

array1 = np.array([[1, 2], [3, 4]])
print('第一个数组:')
print(array1)
array2 = np.array([[5, 6], [7, 8]])
print('第二个数组:')
print(array2)
# 两个数组的维度相同
print('沿轴 0 连接两个数组:')
print(np.concatenate((array1, array2)))
print('沿轴 1 连接两个数组:')
print(np.concatenate((array1, array2), axis=1))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
第一个数组:
[[1 2]
[3 4]]
第二个数组:
[[5 6]
[7 8]]
沿轴 0 连接两个数组:
[[1 2]
[3 4]
[5 6]
[7 8]]
沿轴 1 连接两个数组:
[[1 2 5 6]
[3 4 7 8]]
  • numpy.stack()

此函数沿新轴连接数组序列。 此功能添加自 NumPy 版本 1.10.0。 需要提供以下参数。

1
numpy.stack(arrays, axis)

其中:

arrays相同形状的数组序列

axis:返回数组中的轴,输入数组沿着它来堆叠

案例

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array1 = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组:')
print(array1)
array2 = np.array([[5, 6], [7, 8], [0, 0]])
print('第二个数组:')
print(array2)
print('沿轴 0 堆叠两个数组:')
print(np.stack((array1, array2), 0))
print('沿轴 1 堆叠两个数组:')
print(np.stack((array1, array2), 1))

输出为

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
第一个数组:
[[1 2]
[3 4]
[5 6]]
第二个数组:
[[5 6]
[7 8]
[0 0]]
沿轴 0 堆叠两个数组:
[[[1 2]
[3 4]
[5 6]]

[[5 6]
[7 8]
[0 0]]]
沿轴 1 堆叠两个数组:
[[[1 2]
[5 6]]

[[3 4]
[7 8]]

[[5 6]
[0 0]]]
  • numpy.hstack()

numpy.stack()函数的变体,通过堆叠来生成水平的单个数组。

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

array1 = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组:')
print(array1)
array2 = np.array([[5, 6], [7, 8], [0, 0]])
print('第二个数组:')
print(array2)
print('水平堆叠:')
array3 = np.hstack((array1, array2))
print(array3)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
第一个数组:
[[1 2]
[3 4]
[5 6]]
第二个数组:
[[5 6]
[7 8]
[0 0]]
水平堆叠:
[[1 2 5 6]
[3 4 7 8]
[5 6 0 0]]
  • numpy.vstack()

numpy.stack函数的变体,通过堆叠来生成竖直的单个数组。

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

array1 = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组:')
print(array1)
array2 = np.array([[5, 6], [7, 8], [0, 0]])
print('第二个数组:')
print(array2)
print('竖直堆叠:')
array3 = np.vstack((array1, array2))
print(array3)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
第一个数组:
[[1 2]
[3 4]
[5 6]]
第二个数组:
[[5 6]
[7 8]
[0 0]]
竖直堆叠:
[[1 2]
[3 4]
[5 6]
[5 6]
[7 8]
[0 0]]

11.5、数组分割

序号 数组及操作
1 split() 将一个数组分割为多个子数组
2 hsplit() 将一个数组水平分割为多个子数组(按列)
3 vsplit() 将一个数组竖直分割为多个子数组(按行)
  • numpy.split

该函数沿特定的轴将数组分割为子数组。函数接受三个参数:

1
numpy.split(ary, indices_or_sections, axis)

其中:

ary:被分割的输入数组

indices_or_sections:可以是整数,表明要从输入数组创建的,等大小的子数组的数量。 如果此参数是一维数组,则其元素表明要创建新子数组的点。

axis:默认为 0

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

array1 = np.arange(9)
print('第一个数组:')
print(array1)
print('将数组分为三个大小相等的子数组:')
array2 = np.split(array1, 3)
print(array2)
print('将数组在一维数组中表明的位置分割:')
array3 = np.split(array1, [5, 7])
print(array3)

输出为

1
2
3
4
5
6
第一个数组:
[0 1 2 3 4 5 6 7 8]
将数组分为三个大小相等的子数组:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
将数组在一维数组中表明的位置分割:
[array([0, 1, 2, 3, 4]), array([5, 6]), array([7, 8])]
  • numpy.hsplit

numpy.hsplitsplit()函数的特例,其中轴为 1 表示水平分割,无论输入数组的维度是什么。

案例

1
2
3
4
5
6
7
8
import numpy as np

array1 = np.arange(16).reshape(4, 4)
print('第一个数组:')
print(array1)
print('水平分割:')
array2 = np.hsplit(array1, 2)
print(array2)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
水平分割:
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]), array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]])]
  • numpy.vsplit

numpy.vsplitsplit()函数的特例,其中轴为 0 表示竖直分割,无论输入数组的维度是什么。下面的例子使之更清楚。

案例

1
2
3
4
5
6
7
8
import numpy as np

array1 = np.arange(16).reshape(4, 4)
print('第一个数组:')
print(array1)
print('竖直分割:')
array2 = np.vsplit(array1, 2)
print(array2)

输出为

1
2
3
4
5
6
7
8
9
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
竖直分割:
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]])]

11.6、添加/删除元素

序号 元素及描述
1 resize() 返回指定形状的新数组
2 append() 将值添加到数组末尾
3 insert() 沿指定轴将值插入到指定下标之前
4 delete() 返回删掉某个轴的子数组的新数组
5 unique() 寻找数组内的唯一元素
  • numpy.resize()

此函数返回指定大小的新数组。 如果新大小大于原始大小,则包含原始数组中的元素的重复副本。 该函数接受以下参数。

1
numpy.resize(arr, shape)

其中:

arr:要修改大小的输入数组

shape:返回数组的新形状

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np

array1 = np.array([[1, 2, 3], [4, 5, 6]])
print('第一个数组:')
print(array1)
print('第一个数组的形状:')
print(array1.shape)
array2 = np.resize(array1, (3, 2))
print('第二个数组:')
print(array2)
print('第二个数组的形状:')
print(array2.shape)
# 要注意 a 的第一行在 b 中重复出现,因为尺寸变大了
print('修改第二个数组的大小:')
array2 = np.resize(array1, (3, 3))
print(array2)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
第一个数组:
[[1 2 3]
[4 5 6]]
第一个数组的形状:
(2, 3)
第二个数组:
[[1 2]
[3 4]
[5 6]]
第二个数组的形状:
(3, 2)
修改第二个数组的大小:
[[1 2 3]
[4 5 6]
[1 2 3]]
  • numpy.append()

此函数在输入数组的末尾添加值。 附加操作不是原地的,而是分配新的数组。 此外,输入数组的维度必须匹配否则将生成ValueError

函数接受下列函数:

1
numpy.append(arr, values, axis)

其中:

arr:输入数组

values:要向arr添加的值,比如和arr形状相同(除了要添加的轴)

axis:沿着它完成操作的轴。如果没有提供,两个参数都会被展开。

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

array = np.array([[1, 2, 3], [4, 5, 6]])
print('第一个数组:')
print(array)
print('向数组添加元素:')
print(np.append(array, [7, 8, 9]))
print('沿轴 0 添加元素:')
print(np.append(array, [[7, 8, 9]], axis=0))
print('沿轴 1 添加元素:')
print(np.append(array, [[5, 5, 5], [7, 8, 9]], axis=1))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
第一个数组:
[[1 2 3]
[4 5 6]]
向数组添加元素:
[1 2 3 4 5 6 7 8 9]
沿轴 0 添加元素:
[[1 2 3]
[4 5 6]
[7 8 9]]
沿轴 1 添加元素:
[[1 2 3 5 5 5]
[4 5 6 7 8 9]]
  • numpy.insert()

此函数在给定索引之前,沿给定轴在输入数组中插入值。 如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。

insert()函数接受以下参数:

1
numpy.insert(arr, obj, values, axis)

其中:

arr:输入数组

obj:在其之前插入值的索引

values:要插入的值

axis:沿着它插入的轴,如果未提供,则输入数组会被展开

案例

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组:')
print(array)
print('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print(np.insert(array, 3, [11, 12]))
print('传递了 Axis 参数。 会广播值数组来配输入数组。')
print('沿轴 0 广播:')
print(np.insert(array, 1, [11], axis=0))
print('沿轴 1 广播:')
print(np.insert(array, 1, 11, axis=1))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
第一个数组:
[[1 2]
[3 4]
[5 6]]
未传递 Axis 参数。 在插入之前输入数组会被展开。
[ 1 2 3 11 12 4 5 6]
传递了 Axis 参数。 会广播值数组来配输入数组。
沿轴 0 广播:
[[ 1 2]
[11 11]
[ 3 4]
[ 5 6]]
沿轴 1 广播:
[[ 1 11 2]
[ 3 11 4]
[ 5 11 6]]
  • numpy.delete()

此函数返回从输入数组中删除指定子数组的新数组。 与insert()函数的情况一样,如果未提供轴参数,则输入数组将展开。 该函数接受以下参数:

1
Numpy.delete(arr, obj, axis)

其中:

arr:输入数组

obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组

axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开

案例

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

array = np.arange(12).reshape(3, 4)
print('第一个数组:')
print(array)
print('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print(np.delete(array, 5))
print('删除第二列:')
print(np.delete(array, 1, axis=1))
print('包含从数组中删除的替代值的切片:')
array = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(np.delete(array, np.s_[::2]))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
未传递 Axis 参数。 在插入之前输入数组会被展开。
[ 0 1 2 3 4 6 7 8 9 10 11]
删除第二列:
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
包含从数组中删除的替代值的切片:
[ 2 4 6 8 10]
  • numpy.unique()

此函数返回输入数组中的去重元素数组。 该函数能够返回一个元组,包含去重数组和相关索引的数组。 索引的性质取决于函数调用中返回参数的类型。

1
numpy.unique(arr, return_index, return_inverse, return_counts)

其中:

  • arr:输入数组,如果不是一维数组则会展开
  • return_index:如果为true,返回输入数组中的元素下标
  • return_inverse:如果为true,返回去重数组的下标,它可以用于重构输入数组
  • return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import numpy as np

array = np.array([5, 2, 6, 2, 7, 5, 6, 8, 2, 9])
print('第一个数组:')
print(array)
print('第一个数组的去重值:')
u = np.unique(array)
print(u)
print('去重数组的索引数组:')
u, indices = np.unique(array, return_index=True)
print(indices)
print('我们可以看到每个和原数组下标对应的数值:')
print(array)
print('去重数组的下标:')
u, indices = np.unique(array, return_inverse=True)
print(u)
print('下标为:')
print(indices)
print('使用下标重构原数组:')
print(u[indices])
print('返回去重元素的重复数量:')
u, indices = np.unique(array, return_counts=True)
print(u)
print(indices)

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
第一个数组:
[5 2 6 2 7 5 6 8 2 9]
第一个数组的去重值:
[2 5 6 7 8 9]
去重数组的索引数组:
[1 0 2 4 7 9]
我们可以看到每个和原数组下标对应的数值:
[5 2 6 2 7 5 6 8 2 9]
去重数组的下标:
[2 5 6 7 8 9]
下标为:
[1 0 2 0 3 1 2 4 0 5]
使用下标重构原数组:
[5 2 6 2 7 5 6 8 2 9]
返回去重元素的重复数量:
[2 5 6 7 8 9]
[3 2 2 1 1 1]

11.7、排序

  • numpy.sort()

    对输入数组执行排序,并返回一个数组副本。

    参数 说明
    a 要排序的数组
    axis 沿着指定轴进行排序,如果没有指定 axis,默认在最后一个轴上排序,若 axis=0 表示按列排序,axis=1 表示按行排序
    kind 默认为 quicksort (快速排序)
    order 若数组设置了字段,则 order 表示要排序的字段
1
numpy.sort(a, axis, kind, order)

案例

1
2
3
4
5
6
7
import numpy as np

dt = np.dtype([('name', 'S10'), ('age', 'i4')])
array = np.array([('ggw', 999), ('xpl', 998)], dtype=dt)
print(array) # 输出为 [(b'ggw', 999) (b'xpl', 998)]
# 按年龄字段排序:
print(np.sort(array, order='age')) # 输出为 [(b'xpl', 998) (b'ggw', 999)]
  • numpy.argsort()

    argsort()沿着指定的轴,对输入数组的元素值进行排序,并返回排序后的元素索引数组。示例如下

1
2
3
4
5
6
7
8
9
import numpy as np

array = np.array([90, 29, 89, 12])
print(array) # 输出为 [90 29 89 12]
sortIndex = np.argsort(array)
# 排序结果的索引
print(sortIndex) # 输出为 [3 1 2 0]
# 排序结果
print(array[sortIndex]) # 输出为 [12 29 89 90]

11.8、矩阵乘、点乘

  • numpy.dot()

案例:点乘、矩阵乘

1
2
3
4
5
6
7
8
9
array1 = np.arange(1, 5).reshape(2, 2)
array2 = np.arange(1, 5).reshape(2, 2)
print('原数组')
print(array1)
print(array2)
print('*')
print(array1 * array2)
print('numpy.dot()')
print(array1.dot(array2))

输出为

1
2
3
4
5
6
7
8
9
10
11
原数组
[[1 2]
[3 4]]
[[1 2]
[3 4]]
*
[[ 1 4]
[ 9 16]]
numpy.dot()
[[ 7 10]
[15 22]]

12、NumPy - 统计

12.1、平均值和中位数

  • ndarray.mean()

    获得平均值

    参数: axis,值0、1,分别是轴0、轴1的方向

  • numpy.median()

    中位数(中值)

案例

1
2
3
4
5
import numpy as np

array = np.arange(20).reshape(4, 5)
print(array.mean()) # 输出为 9.5
print(np.median(array)) # 输出为 9.5

12.2、标准差和方差

  • ndarray.std()

    标准差

  • ndarray.var()

    方差

案例

1
2
3
4
5
6
7
8
9
10
import numpy as np
import math

array = np.arange(20).reshape(4, 5)
# 标准差
print(array.std()) # 输出为 5.766281297335398
# 下面将按照传统方法计算 计算结果同上
print(math.sqrt(np.sum((array - array.mean()) ** 2) / array.size))
# 方差
print(array.var()) # 输出为 33.25

12.3、最大值、最小值、和

  • ndarray.max()

    最大值

    参数: axis,值0、1,分别是轴0、轴1的方向

  • ndarray.min()

    最小值

    参数: axis,值0、1,分别是轴0、轴1的方向

  • ndarray.sum()

    参数: axis,值0、1,分别是轴0、轴1的方向

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np

array = np.arange(20).reshape(4, 5)
print('原数组:')
print(array)
# 最大值
print('----------------------')
print(array.max())
print(array.max(axis=0))
print(array.max(axis=1))
# 最小值
print('----------------------')
print(array.min())
print(array.min(axis=0))
print(array.min(axis=1))
# 和
print('----------------------')
print(array.sum())
print(array.sum(axis=0))
print(array.sum(axis=1))

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
原数组:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
----------------------
19
[15 16 17 18 19]
[ 4 9 14 19]
----------------------
0
[0 1 2 3 4]
[ 0 5 10 15]
----------------------
190
[30 34 38 42 46]
[10 35 60 85]

12.4、加权平均值

  • numpy.average()

    加权平均值

1
numpy.average(a, axis=None, weights=None, returned=False)

案例

对比两位学生的考试成绩

姓名 平时测验 期中考试 期末考试
ggw 95 90 80
xpl 80 90 95

学校规定的学科综合成绩的计算方法:

平时测验 期中考试 期末考试
20% 30% 50%
1
2
3
4
5
6
import numpy as np

array = np.array([[95, 90, 80], [80, 90, 95]])
w = [0.2, 0.3, 0.5]
print(np.average(array, axis=1, weights=w)) # 输出为 [86. 90.5]
print(95*0.2 + 90*0.3 + 80*0.5) # 输出为 86.0

12、NumPy - 文件操作

  • loadtxt()

    读取txt文本、csv文件

1
2
3
loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, \
converters=None, skiprows=0, usercols=None, unpack=False, \
ndmin=0, encoding='bytes')
参数 说明
fname 指定文件或者字符串。支持压缩文件,包括gz,bz格式。
dtype 数据类型,默认为float。
comments 字符串或字符串组成的列表。表示注释字符集开始的标志,默认为#。
delimiter 字符串。分隔符。
converters 字典。将特定列的数据转换为字典中对应的函数的浮点型数据。例如将空值转换为0,默认为空。
skiprows 跳过特定行数据。例如跳过前1行(可能是标题或注释)。默认为0。
usercols 元组。用来指定要读取数据的列,第一列为0。例如(1, 3, 5),默认为空。
unpack 布尔型。指定是否转置数组,如果为真则转置,默认为False。
ndmin 整数型。指定返回的数组至少包含特定维度的数组。值域为0、1、2,默认为0。
enconding 编码。确认文件是gbk还是utf-8格式。

返回值:从文件读出的数组

【具体使用说明】

  • np.savez()
1
np.savez(r'./data.npz', data=data, x=x, y=y)

将numpy数组data、x、y存储到文件data.npz中,没有设置关键字参数而是直接传参,则变为’arr_0、arr_1、arr_2’

  • np.load()
1
2
3
data = np.load(r'./data.npz')
data, x, y = data['data'], data['x'], data['y']
# print(data.files) # 查看文件

将文件中的数组加载出来

13、随机函数

NumPy中也有自己的随机函数,包含在random模块中。它能产生特定分布的随机数,如正态分布等。接下来介绍一些常用的随
机数。

  • rand()
    • rand()函数根据给定维度生成[0,1)之间的数据,包含0,不包含1
    • dn表示每个维度
    • 返回值为指定维度的array
1
numpy.random.rand(d0,d1,...,dn)

案例

1
2
3
4
import numpy as np

array = np.random.rand(1, 2)
print(array) # 输出为 [[0.09504265 0.16277635]]
  • randn()
    • randn()函数返回一个或一组样本,具有标准正态分布
    • dn表示每个维度
    • 返回值为指定维度的array

标准正态分布又称为u分布,是以0为均值、以1为标难差的正态分布,记为N (0,1)

1
numpy.random.randn(d0,d1,...,dn)
  • randint()
    • 返回随机整数,范围区间[low, high),包括low,不包括high
    • 参数:low为最小值,high为最大值,size为数组维数大小,dtype为数据类型,默认是int
    • high没有填写时,默认生成的是[0, low)范围
1
numpy.random.randint(low, high=None, size=None, dtype='i')

案例

1
2
3
4
import numpy as np

array = np.random.randint(-5, 6, size=(1,3))
print(array) # 输出为 [[2 5 0]]
  • sample()

    返回半开区间的随机浮点数[0.0, 1.0]

1
numpy.random.sample(size=None)

案例

1
2
3
4
import numpy as np

array = np.random.sample((1, 2))
print(array) # 输出为 [[0.58491274 0.10521267]]
  • seed()
    • 使用相同的seed()值,则每次生成的随机数都相同,使得随机数可以预测
    • 但是,只在调用的时候seed()一下并不能使生成的随机数相同,需要每次调用都seed()一下,表示种子相同,从而生成的随机数
      相同
1
numpy.random.seed()

案例

1
2
3
4
5
6
7
8
import numpy as np

np.random.seed(1)
array1 = np.random.sample((1, 2))
print(array1) # 输出为 [[0.417022 0.72032449]]
np.random.seed(1)
array2 = np.random.sample((1, 2))
print(array2) # 输出为 [[0.417022 0.72032449]]
  • normal()

    作用: 返回一个由size指定形状的数组,数组中的值服从 p=loc,o=scale 的正态分布

    参数 说明
    loc float型或者float型的类数组对象,指定均值(mu)
    scale float型或者float型的类数组对象,指定标准差(sigma)
    size int型或者int型的元组,指定了数组的形状,如果不提供size,且loc和scale为标量(不是类数组对象),则返回一个服从该分布的随机数。
1
numpy.random.normal(loc=0.0, scale=1.0, size=None)

案例

1
2
3
4
import numpy as np

array = np.random.normal(0.0, 1.0, size=(1, 2))
print(array) # 输出为 [[-2.12634551 -0.82277155]]

四、matplotlib

Matplotlib 是Python中类似 MATLAB 的绘图工具,熟悉 MATLAB 也可以很快的上手 Matplotlib。

优点:

  • Matplotlib 提供了一个套面向绘图对象编程的API 接口
  • 依托于Python,借助Python的强大的可拓展性Matplotlib可以在许多不同的环境中被使用
  • 基于Matlab的和基于面向对象的,但是它完全免费(Matlab是商业数学软件)
  • Matplotlib 实现了几乎是完全自主控制的图形定义功能

1、第一个绘图程序

1
2
3
4
5
6
7
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
plt.show()

2、基本方法

2.1、title()

设置图标名称

1
2
3
4
5
6
7
8
9
10
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
# -----------------------------------------------------------------------------
plt.title('y=x^2') # 图标名称为 y=x^2
# -----------------------------------------------------------------------------
plt.show()

修改字体配置(2个问题)

(1)默认不支持中文(字体丢失),报错为:missing from current font.

1
2
3
4
5
6
7
8
9
10
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
# -----------------------------------------------------------------------------
plt.title('y等于x的平方')
# -----------------------------------------------------------------------------
plt.show()

解决办法:

1
2
plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.rcParams['font.sans-serif'] = ['simhei'] # 效果相同,不区分大小写

字体说明

中文字体 说明
SimHei 中文黑体
Kaiti 中文楷体
LiSu 中文隶书
FangSong 中文仿宋
YouYuan 中文幼圆
STSong 华文宋体

(2)当字体设置支持中文后,必须设置负号,否则数值中出现负值时,符号无法显示

解决办法:

1
plt.rcParams['axes.unicode_minus'] = False

正常执行的代码

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
plt.title('y等于x的平方')
# -----------------------------------------------------------------------------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# -----------------------------------------------------------------------------
plt.show()

2.2、xlabel()、ylabel()

设置x轴、y轴的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
plt.title('y等于x的平方')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# -----------------------------------------------------------------------------
plt.xlabel('x 轴')
plt.ylabel('y 轴')
# -----------------------------------------------------------------------------
plt.show()

2.3、补充

(1)样式

参数 说明
fontsize 字体大小
linewidth 线条宽度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
# -----------------------------------------------------------------------------
plt.plot(x, y, linewidth=5) # 设置了线条宽度
plt.title('y等于x的平方', fontsize=16) # 设置了字体大小
# -----------------------------------------------------------------------------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# -----------------------------------------------------------------------------
plt.xlabel('x 轴', fontsize=16) # 设置了字体大小
plt.ylabel('y 轴', fontsize=16) # 设置了字体大小
# -----------------------------------------------------------------------------
plt.show()

(2)一张图多个曲线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y1 = x ** 2
y2 = 10 * x
plt.title('y等于x的平方', fontsize=16)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.xlabel('x 轴', fontsize=16)
plt.ylabel('y 轴', fontsize=16)
# -----------------------------------------------------------------------------
plt.plot(x, y1, linewidth=5)
plt.plot(x, y2, linewidth=5)
# -----------------------------------------------------------------------------
plt.show()

2.4、xticks()、yticks()

设置x轴、y轴的刻度(把坐标轴变成自己想要的样子)

1
plt.xticks(ticks=None, label=None, **kwargs)
参数 说明
ticks 此参数是xtick位置的列表。是一个可选参数。如果将一个空列表作为参数传递,则它将删除所有xticks
label 此参数包含放置在给定刻度线位置的标签。它是一个可选参数
**kwargs 此参数是文本属性,用于控制标签的外观
 rotation :旋转角度;如: rotation=45
 color: 颜色;如: color=“red”

如果ticks参数的值是数值型,那么代表的是他本身,而不是索引(位置)

案例

1
2
3
4
5
6
7
8
9
import numpy as np
import matplotlib.pyplot as plt

date = [f'1月{i}日' for i in range(1, 21)]
salary = np.random.randint(500, 900, size=len(date))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.plot(date, salary)
plt.show()

设置x轴刻度后

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
import matplotlib.pyplot as plt

date = [f'1月{i}日' for i in range(1, 21)]
salary = np.random.randint(500, 900, size=len(date))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# -----------------------------------------------------------------------------
# 日期隔一个显示,倾斜45°
plt.xticks(range(1, len(date), 2), rotation=45)
# -----------------------------------------------------------------------------
plt.plot(date, salary)
plt.show()

2.5、show()

显示所有打开的图形

注意:jupyter notebooks会自动显示图形(即使没调用)

如果在jupyter中也想要出现图形操作菜单,可以使用matplotlib中的魔术方法

1
%matplotlib notebook

如果在jupyter中变回原来的模式

1
%matplotlib inline

2.6、legend()

1
plt.legend([loc])

(1)使用图例前需要在,plot()函数中指定参数label的值

(2)需要先指定,在执行legend()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import matplotlib.pyplot as plt

date = [f'1月{i}日' for i in range(1, 21)]
salary = np.random.randint(500, 900, size=len(date))
expenses = np.random.randint(100, 500, size=len(date))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.xticks(range(1, len(date), 2), rotation=45)
# -----------------------------------------------------------------------------
# 注意, 在使用图例 前 为每个图形设置label参数(plot()在legend()后面执行,将失效)
plt.plot(date, salary, label='收入')
plt.plot(date, expenses, label='支出')
# 图例 默认会使用每个图形的label值作为图例的说明
plt.legend()
# -----------------------------------------------------------------------------
plt.show()

设置图例

(1)默认会选择不遮挡图形的位置来显示图例(loc=best)(位置不定)

(2)指定图例位置

位置 字符串位置值 位置值
默认值,自定寻找合适位置 best 0
右上角 upper right 1
左上角 upper left 2
左下角 lower left 3
右下角 lower right 4
右边中间 right 5
左边中间 center left 6
右边中间 center right 7
中间最下面 lower center 8
中间最上面 upper center 9
正中心 center 10

2.7、text()

显示每条数据的值

1
plt.text(x, y, string, fontsize=15, verticalalignment='top', horizontalalignment='right')
参数 说明
x, y 坐标轴上的值
string 说明文字
fontsize 字体大小
verticalalignment 垂直对齐方式(va),[‘center’ | ‘top’ | ‘bottom’ | ‘baseline’]
horizontalalignment 水平对齐方式(ha),[‘center’ | ‘right’ | ‘left’]

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import matplotlib.pyplot as plt

date = [f'1月{i}日' for i in range(1, 21)]
salary = np.random.randint(500, 900, size=len(date))
expenses = np.random.randint(100, 500, size=len(date))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.xticks(range(1, len(date), 2), rotation=45)
plt.plot(date, salary, label='收入')
plt.plot(date, expenses, label='支出')
plt.legend(loc='upper right')
# -----------------------------------------------------------------------------
# plt.text('1月1日', salary[0], '第一天的收入') # 有效
for x, y1, y2 in zip(date, salary, expenses):
plt.text(x, y1, f'{y1}元', fontsize=8, horizontalalignment='center')
plt.text(x, y2, f'{y2}元', fontsize=8, horizontalalignment='center')
# -----------------------------------------------------------------------------
plt.show()

2.8、plot()线条样式

1
2
plt.plot(x, y, color='red', alpha=0.3, linestyle='-', linewidth=5,\
marker='o', markeredgecolor='r', markersize='20', markeredgewidth=10)

参数说明

(1)x, y:plot(y),x可省略,默认[0,…,N-1]递增,N为y轴元素的个数

(2)color:可以使用颜色的十六进制,也可以使用线条的颜色英文,还可以使用之前的缩写

字符 颜色 英文全称
b 蓝色 blue
g 绿色 green
r 红色 red
c 青色 cyan
m 品红 magenta
y 黄色 yellow
k 黑色 black
w 白色 white

(3)alpha:0.0-1.0,透明度

(4)linestyle:线条样式

字符 描述
- 实线
虚线
-. 点划线
: 虚线

(5)linewidth:折线的宽度

(7)marker:标记点

标记符号 描述
. 点标记
o 圆圈标记
x 'X’标记
D 钻石标记
H 六角标记
s 正方形标记
+ 加号标记

(7)markeredgecolor:标记点的颜色

(8)markersize:标记点的大小

(9)markeredgewidth:标记点的边宽

3、其他元素的可视性

3.1、grid()

操作网格

1
plt.grid(True, linestyle='——', color='gray', linewidth='0,5', axis='x')
参数 说明
True 显示网格
linestyle 线性
color 颜色
linewidth 宽度
axis x, y, both:显示x、显示y、显示x和y的网格

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-np.pi, np.pi, endpoint=True)
c, s = np.cos(x), np.sin(x)
plt.plot(x, c)
plt.plot(x, s)
# -----------------------------------------------------------------------------
plt.grid()
# -----------------------------------------------------------------------------
plt.show()

3.2、gca(),spines

首先观察画布上面的坐标轴

上图中,框选出的四条黑色边界框线在Matplotlib中被称为spines,中文翻译为脊柱,可以理解为这些框线是坐标轴的”支柱“

所有的操作在plt.gca()中完成(gca: get current axes(获取当前区域))

用法在下面的例子中得到说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
# -----------------------------------------------------------------------------
plt.ylim(0, 2500)
# 获取当前坐标轴
ax = plt.gca()
# 通过坐标轴spines,确定top、botom、left、right(分别表示上、下、左、右)
# - 不需要右侧和上面的线条,设置成空颜色
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
# 在这里,position位置参数有三种: data, axes, outward(向外)
# - data: 数值对应的位置
ax.spines['left'].set_position(('data', 0))
# - axes: 0.0-1.0之间的值,坐标轴的比例
# ax.spines['left'].set_position(('axes', 0.5))
# -----------------------------------------------------------------------------
plt.plot(x, y)
plt.show()

4、创建图形对象

  在 Matplotlib 中,面向对象编程的核心思想是创建图形对象(figure obiect)。通过图形对象来调用其它的方法和属性,这样有助于我们更好地处理多个画布。在这个过程中,pyplot 负责生成图形对象,并通过该对象来添加一个或多个axes 对象(即绘图区)
  Matplotib 提供了 matplotlib,figure 图形类模块,它包含了创建图形对象的方法。通过调用 pyplot 模块中 figure() 函数来实例化figure对象。

figure()

创建图形对象

1
plt.figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True, **kwargs)
参数 描述
num 图像编号或名称,数字为编号 ,字符串为名称
figsize 指定figure的宽和高,单位为英寸;
dpi 指定绘图对象的分辨率,即每英寸多少个像素,缺省值为72
facecolor 背景颜色
edgecolor 边框颜色
frameon 是否显示边框

案例

1
2
3
4
5
6
import matplotlib.pyplot as plt

# -----------------------------------------------------------------------------
fig = plt.figure('f1', figsize=(4, 2), dpi=100, facecolor='pink')
# -----------------------------------------------------------------------------
plt.show()

5、绘制多子图

  fiqure是绘制对象(可理解为一个空白的画布),一个figure对象可以包含多个Axes子图,一个Axes是一个绘图区域,不加设置时,Axes为1,且每次绘图其实都是在figure上的Axes上绘图。
  我们是在图形对象上面的Axes区域作画

1、add_axes()

添加区域

  Matplotlib 定义了一个 axes 类(轴域类),该类的对象被称为 axes 对象(即轴域对象),它指定了一个有数值范围限制的绘图区域。在一个给定的画布 (figure) 中可以包含多个 axes 对象,但是同一个axes 对象只能在一个画布中使用。

  2D绘图区域(axes)包含两个轴(axis)对象

语法:

1
add_axes(rect)
  • 该方法用来生成一个axes 轴域对象,对象的位置由参数rect决定
  • rect 是位置参数,接受一个由 4 个元素组成的浮点数列表,形如[left, botom, width, height],它表示添加到画布中的矩形区
    域的左下角坐标(x,y),以及宽度和高度。

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt

# -----------------------------------------------------------------------------
# 画布背景设置成 pink
fig = plt.figure(facecolor='pink')
# ax1 从画布 10%, 10% 的位置开始画,宽高是画布的 80%
ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8])
# - 当前区域是 ax1, plt.plot()在当前区域作画
plt.plot([1, 2, 3, 4, 6], [9, 7, 5, 8, 2])
# ax2 从画布 20%, 20% 的位置开始画,宽高是画布的 50%
ax2 = fig.add_axes([0.2, 0.2, 0.5, 0.5])
# - 当前区域是 ax2, plt.plot()在当前区域作画
plt.plot([1, 2, 3, 4, 6], [9, 7, 5, 8, 2])
ax1.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
ax2.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
# -----------------------------------------------------------------------------
plt.show()

ps:plt.plot()是在当前区域作画

2、subplot()

均等地划分画布

1
fig, ax = plt.subplot(nrows, ncols, index, *args, **kwargs)

返回值:区域画布,区域对象

参数 描述
nrows
ncols
indes 索引
**kwargs title、xlabel、ylabel等

说明:

nrows 与 ncols 表示要划分几行几列的子区域 (nrows*nclos表示子图数量),index 的初始值为1,用来选定具体的某个子区域。
例如:subplot(233)表示在当前画布的右上角创建一个两行三列的绘图区域,同时,选择在第 3 个位置绘制子图。

案例1

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt

fig = plt.figure(facecolor='pink')
# -----------------------------------------------------------------------------
# 切割成 2*2 份
# - 选择第 1 份
ax1 = plt.subplot(221)
# - 选择第 2 份
ax2 = plt.subplot(224)
# -----------------------------------------------------------------------------
ax1.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
ax2.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
plt.show()

案例2

1
2
3
4
5
6
7
8
9
10
import matplotlib.pyplot as plt

fig = plt.figure(facecolor='pink')
# -----------------------------------------------------------------------------
ax1 = plt.subplot(121)
ax2 = plt.subplot(224)
# -----------------------------------------------------------------------------
ax1.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
ax2.plot([1, 2, 3, 4, 6], [2, 3, 5, 8, 9])
plt.show()

6、柱状图

1、bar()

绘制柱状图

1
plt.bar(x, height, width:float=0.8, bottom=None, *, align:str='center', data=None, **kwargs)
参数 描述
x 表示x坐标,数据类型为float类型,一般为np.arange()生成的固定步长列表
height 表示柱状图的高度,也就是y坐标值,数据类型为float类型,一般为一个列表,包含生成柱状图的所有y值
width 表示柱状图的宽度,取值在0-1之间,默认值为0.8
bottom 柱状图的起始位置,也就是y轴的起始坐标,默认值为None
align 柱状图的中心位置,“center”,"lege"边缘,默认值为’center’
color 柱状图颜色,默认为蓝色
alpha 透明度,取值在0~1之间,默认值为1
label 标签,设置后需要调用plt.legend()生成
edgecolor 边框颜色(ec)
linewidth 边框宽度,浮点数或类数组,默认为None (lw)
tick_label 柱子的刻度标签,字符串或字符串列表,默认值为None。
linestyle 线条样式(Is)

案例1

基本柱状图

1
2
3
4
5
6
7
import numpy as np
import matplotlib.pyplot as plt

x = range(5)
y = np.random.randint(2, 8, size=5)
plt.bar(x, y, color='pink')
plt.show()

案例2

测试参数

1
2
3
4
5
6
7
8
import numpy as np
import matplotlib.pyplot as plt

x = range(5)
y = np.random.randint(2, 8, size=5)
plt.bar(x, y, color=['c', 'pink', 'y'], bottom=[1, 2, 1, 4, 3], \
edgecolor='k', linestyle='--', linewidth=2)
plt.show()

2、同位置多柱状图

案例

各个国家的奖牌数

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
32
33
34
35
36
37
38
39
import numpy as np
import matplotlib.pyplot as plt

# 国家
countries = ['挪威', '德国', '中国', '美国', '瑞典']
# 金牌
goldMedal = [16, 12, 9, 8, 8]
# 银牌
silverMedal = [8, 10, 4, 10, 5]
# 铜牌
bronzeMedal = [13, 5, 2, 7, 5]

# 1、将x轴转化为数值
x = np.arange(len(countries))
# 2、设置图形宽度
width = 0.2
# 3、设置图形起始位置
# - 金牌
goldX = x
# - 银牌
silverX = x + width
# - 铜牌
bronzeX = x + 2 * width
# 4、设置 x标签 位置居中,标签变回来,解决乱码问题
plt.xticks(x + width, labels=countries)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 5、显示文本高度
for i in range(len(countries)):
plt.text(goldX[i], goldMedal[i], goldMedal[i], va='bottom', ha='center')
plt.text(silverX[i], silverMedal[i], silverMedal[i], va='bottom', ha='center')
plt.text(bronzeX[i], bronzeMedal[i], bronzeMedal[i], va='bottom', ha='center')

# 6、绘图
plt.bar(goldX, goldMedal, width=width, color='gold')
plt.bar(silverX, silverMedal, width=width, color='silver')
plt.bar(bronzeX, bronzeMedal, width=width, color='saddlebrown')

plt.show()

3、堆叠状图

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
import numpy as np
import matplotlib.pyplot as plt

# 国家
countries = ['挪威', '德国', '中国', '美国', '瑞典']
# 金牌
goldMedal = [16, 12, 9, 8, 8]
# 银牌
silverMedal = [8, 10, 4, 10, 5]
# 铜牌
bronzeMedal = [13, 5, 2, 7, 5]

# 1、设置图形起始绘制位置
# - 铜牌
bronzeBottom = np.zeros(5)
# - 银牌
silverBottom = bronzeBottom + bronzeMedal
# - 金牌
goldBottom = silverBottom + silverMedal
# 2、解决乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 3、绘图
plt.bar(countries, goldMedal, bottom=goldBottom, color='gold')
plt.bar(countries, silverMedal, bottom=silverBottom, color='silver')
plt.bar(countries, bronzeMedal, bottom=bronzeBottom, color='saddlebrown')

plt.show()

4、barh()

绘制水平柱状图,和bar()用法基本一致

区别:width 和 height参数意义互换, bottom变成left

案例

将上面堆叠状图的案例简单修改

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
import numpy as np
import matplotlib.pyplot as plt

# 国家
countries = ['挪威', '德国', '中国', '美国', '瑞典']
# 金牌
goldMedal = [16, 12, 9, 8, 8]
# 银牌
silverMedal = [8, 10, 4, 10, 5]
# 铜牌
bronzeMedal = [13, 5, 2, 7, 5]

# 1、设置图形起始绘制位置
# - 铜牌
bronzeBottom = np.zeros(5)
# - 银牌
silverBottom = bronzeBottom + bronzeMedal
# - 金牌
goldBottom = silverBottom + silverMedal
# 2、解决乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 3、绘图
# -----------------------------------------------------------------------------
plt.barh(countries, goldMedal, height=0.5, left=goldBottom, color='gold')
plt.barh(countries, silverMedal, height=0.5, left=silverBottom, color='silver')
plt.barh(countries, bronzeMedal, height=0.5, left=bronzeBottom, color='saddlebrown')
# -----------------------------------------------------------------------------
plt.show()

7、直方图

柱状图 直方图
柱状图一般用于描述离散型分类数据的对比 直方图一般用于描述连续型数据的分布关系
每根柱子宽度固定,柱子之间会有间距 每根柱子宽度可以不一样,且一般没有间距
横轴变量可以任意排序 横轴变量有一定顺序规则

hist()

1
2
3
4
plt.hist(x, bins=None, range=None, density=None, weights=None, \
cumulative=False, bottom=None, histtype='bar', align='mid', \
orientation='vertical', rwidth=None, log=False, color=None, \
label=None, stacked=False, normed=None, *, data=None, **kwargs)
参数 说明
x 【必选参数】作直方图所要用的数据,必须是一维数组;多维数组可以先进行扁平化再作图。
bins 直方图的柱数,即要分的组数,默认为10。
weights 与x形状相同的权重数组;将x中的每个元素乘以对应权重值再计数;如果normed或density取值为True,则会对权重进行归一化处理。这个参数可用于绘制已合并的数据的直方图。
density 布尔值,可选参数。如果”True”,返回元组的第一个元素将会将计数标准化以形成一个概率密度,也就是说,直方图下的正积(或积分)总和为1。这是通过将计数除以数的数量来实现的观察乘以箱子的宽度而不是除以总数数量的观察。如果叠加也是“真实”的,那么柱状图被规范化为1。(替代normed)
bottom 数组,标量值或None;每个柱子底部相对于y=0的位置。如果是标量值,则每个柱子相对于y=0向上/向下的偏移量相同。如果是数组,则根据数组元素取值移动对应的柱子;即直方图上下便宜距离。
histtype {‘bar’, ‘barstacked’, ‘step’, ‘stepfilled’};'bar’是传统的条形直方图;'barstacked’是堆叠的条形直方图;'step’是未填充的条形直方图,只有外边框;‘stepfilled’是有填充的直方图;当histtvpe取值为’step’或’stepfilled’,rwidth设置失效,即不能指定柱子之间的间隔,默认连接在一起。
align {‘left’, ‘mid’, ‘right’};‘left’:柱子的中心位于bins的左边缘;‘mid’:柱子位于bins左右边缘之间;‘right’:柱子的中心位于bins的右边缘。
color 具体颜色,数组(元素为颜色)或None。
label 字符串 (序列)或None;有多个数据集时,用label参数做标注区分。
normed 是否将得到的直方图向量归一化,即显示占比,默认为0,不归一化;不推荐使用,建议改用density参数。
edgecolor 直方图边框颜色。
alpha 透明度

返回值:

n:数组或数组列表(直方图的值)

bins:数组(返回各个bin区间范围)

patches:列表或列表的列表(返回每个bins里面包含的数据,是一个list)

案例

1
2
3
4
5
6
import numpy as np
import matplotlib.pyplot as plt

x = np.random.randint(140, 180, size=200)
plt.hist(x, bins=10, edgecolor='w', color='pink')
plt.show()

8、饼状图

饼状图用来显示一个数据系列,具体来说,饼状图显示一个数据系列中各项目的占项目总和的百分比。

Matplotlib 提供了一个 pie()函数,该函数可以生成数组中数据的饼状图。您可使用 x/sum(x) 来计算各个扇形区域占饼图总和的
百分比。

pie()

1
plt.pie(x, explode=None, labels=None, colors=None, autopct=None)
参数 描述
x 数组序列,数组元素对应扇形区域的数量大小。
labels 列表字符串序列,为每个扇形区域备注一个标签名字。
colors 为每个扇形区域设置颜色,默认按照颜色周期自动设置。
autopct 格式化字符串"fmt%pct”,使用百分比的格式设置每个扇形区的标签,并将其放置在扇形区内。
pctdistance 设置百分比标签与圆心的距离。
labeldistance 设置各扇形标签 (图例)与圆心的距离。
explode 指定饼图某些部分的突出显示,即呈现爆炸式。
shadow 是否添加饼图的阴影效果。

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt

# 定义饼的标签
label = ['娱乐', '育儿', '饮食', '房贷', '交通', '其他']
# 每个标签所占的数量
x = [200, 500, 1200, 7000, 200, 900]
# 配置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 标题
plt.title('饼图示例:8月份家庭支出')
# %.2f%%显示百分比,保留两位小数
plt.pie(x, labels=label, autopct='%.2f%%', colors=['pink', 'y', 'c'])
plt.show()

9、散点图

散点图也叫XY 图,它将所有的数据以点的形式展现在直角坐标系上,以显示变量之间的相互影响程度,点的位置由变量的数值决定

通过观察散点图上数据点的分布情况,我们可以推断出变量间的相关性。如果变量之间不存在相互关系,那么在散点图上就会表现为随机分布的离散的点,如果存在某种相关性,那么大部分的数据点就会相对密集并以某种趋势星现。

scatter()

1
2
3
plt.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, \
vmin=None, vmax=None, alpha=None, linewidths=None, edgecolors=None, \
plotnonfinite=None, data=None, **kwargs)
参数 描述
x, y 散点的坐标
s 散点的面积
c 散点的颜色(默认值为蓝色,‘b’,其余颜色同plt.plot( ))
marker 散点样式(默认值为实心圆,"o,其余样式同plt.plot( ))
alpha 散点透明度 ([0,1]之间的数,0表示完全透明,1则表示完全不透明)
linewidths 散点的边缘线宽
edgecolors 散点的边缘颜色
cmap Colormap,默认 None,标量或者是一个 colormap 的名字,只有c是一个浮点数数组的时候才使用

案例

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import matplotlib.pyplot as plt

x = np.random.rand(50)
y = np.random.rand(50)
# 生成一个浮点数或者N维浮点数组,取值范围:正态分布的随机样本数
s = (100 * np.random.randn(50))
# 颜色随机
colors = np.random.rand(50)
plt.scatter(x, y, s, c=colors)
plt.show()

10、词云图

WordCloud 是一款python环境下的词云图工具包,同时支持python2和python3把关键词数据转换成直观且有趣的图文模式

pip安装

1
pip install wordcloud

conda安装

1
conda install -c conda-forge wordcloud

【b站视频】

11、保存图片

savefig()

1
2
plt.savefig(fname, dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, \
format=None, transparent=False, bbox_inches=None, pad_inches=0.1, frameon=None, metadata=None)
参数 描述
fname (字符串或者仿路径或仿文件)如果格式已经设置,这将决定输出的格式并将文件按fname来保存。如果格式没有设置,在fname有扩展名的情况下推断按此保存,没有扩展名将按照默认格式存储为“png”格式,并将适当的扩展名添加在fname后面。
dpi 分辨率,每英寸的点数
facecolor (颜色或“auto”,默认值:“auto”) : 图形表面颜色。如果是“auto”,使用当前图形的表面颜色
edgecolor (颜色或“auto”,默认值:“auto”) : 图形边缘颜色。如果是“auto”,使用当前图形的边缘颜色
format 字符串,文件格式,比如“png”,“pdf”,“svg”等,未设置的行为将被记录在fname中
transparent 用于将图片背景设置为透明。图形也会是透明,除非通过关键字参数指定了表面颜色或边缘

案例

1
2
3
4
5
6
7
8
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-50, 51)
y = x ** 2
plt.plot(x, y)
plt.savefig('第一个绘图程序.jpg')
plt.show()






五、pandas

千锋教育

  • Pandas 是基于NumPy的一种工具,该工具是为解决数据分析任务而创建的, Pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • Pandas与出色的 Jupyter工具包和其他库相结合,Python中用于进行数据分析的环境在性能、生产率和协作能力方面都是卓越的。

  • Pandas的主要数据结构是 **Series(**一维数据)与 **DataFrame **(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数案例

  • 处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化,Pandas 是处理数据的理想工具。

1. pandas安装

  • Anaconda环境: 无需安装
  • 普通Python环境: pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple

2. Pandas数据结构

Series

Series是一种类似于一维数组的对象,由下面两个部分组成:

  • values:一组数据(ndarray类型)
  • index:相关的数据索引标签
1)Series的创建

两种创建方式:

  • (1) 由列表或NumPy数组创建
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
import numpy as np
import pandas as pd

list1 = [11, 22, 33, 44]
s = pd.Series(list1)
print("由列表创建:")
print(s)

n = np.array(list1)
s = pd.Series(n)
print("\n由numpy创建:")
print(s)

print("\n查看series的类型对象:") #实际上使用就当做带索引的一维数组就ok了
print(type(s))

print("\nSeries属性: index和values")
print("index:", s.index)
print("values:", s.values)

print("\n修改索引:")
s.index = list("abcd")
print(s.index)
print("通过索引获取值:", s.b, s.c, s['d']) # 修改就是直接赋值
s.index = ["鲁班", "李白", "诸葛亮", "张飞"]
print(s.index)
print("通过索引获取值:", s["鲁班"])
查看输出
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
由列表创建:
0 11
1 22
2 33
3 44
dtype: int64

由numpy创建:
0 11
1 22
2 33
3 44
dtype: int32

查看series的类型对象:
<class 'pandas.core.series.Series'>

Series属性: index和values
index: RangeIndex(start=0, stop=4, step=1)
values: [11 22 33 44]

修改索引:
Index(['a', 'b', 'c', 'd'], dtype='object')
通过索引获取值: 22 33 44
Index(['鲁班', '李白', '诸葛亮', '张飞'], dtype='object')
通过索引获取值: 11

  • (2) 还可以通过字典创建
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
32
33
34
import numpy as np
import pandas as pd

d = {
'a': 11,
'b': 22,
'c': 33,
'd': 44
}
s = pd.Series(d)
print("由 字典 创建:")
print(s)

print("\n修改索引:")
s.index = list("ABCD")
print(s)


# 实例
d = {
'a': np.random.randint(0, 10, size=(2,3)),
'b': np.random.randint(0, 10, size=(2,3)),
'c': np.random.randint(0, 10, size=(2,3)),
'd': np.random.randint(0, 10, size=(2,3))
}
s = pd.Series(d)
print("\n一个实例:")
print(s)


# 创建时同时设置索引
print("\nmore:")
s = pd.Series([1,2,3], index=["张三", '李四', '王五'], name="人物")
print(s)
查看输出
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
由 字典 创建:
a 11
b 22
c 33
d 44
dtype: int64

修改索引:
A 11
B 22
C 33
D 44
dtype: int64

一个实例:
a [[2, 1, 1], [9, 2, 3]]
b [[7, 3, 5], [4, 5, 5]]
c [[4, 7, 8], [9, 9, 7]]
d [[2, 0, 6], [8, 3, 5]]
dtype: object

more:
张三 1
李四 2
王五 3
Name: 人物, dtype: int64

2)Series的索引

可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:

  • (1) 显式索引
  1. 使用index中的元素作为索引值
  2. 使用.loc[] —— (推荐使用,为了和后面作区别)

注意,此时是闭区间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

s = pd.Series({'语文': 150, "数学": 100, "英语": 120, "Python": 99})

# 显式索引:使用索引名字
print("法一:")
print(s['语文'], '\n') # int类型
print(s[['语文', "Python", "数学"]], '\n') # Series类型
print(s[['语文']], '\n') # Series类型

# .loc[ ]
print("法二:")
print(s.loc['语文'], '\n')
print(s.loc[['语文', "Python", "数学"]], '\n')
print(s.loc[['语文']], '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
法一:
150

语文 150
Python 99
数学 100
dtype: int64

语文 150
dtype: int64

法二:
150

语文 150
Python 99
数学 100
dtype: int64

语文 150
dtype: int64


  • (2) 隐式索引
  1. 使用整数作为索引值

  2. 使用.iloc[] ——(推荐

注意,此时是半开区间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

s = pd.Series({'语文': 150, "数学": 100, "英语": 120, "Python": 99})

# 显式索引:使用索引名字
print("法一:")
print(s[0], '\n') # int类型
print(s[[0, 2, 1]], '\n') # Series类型
print(s[[0]], '\n') # Series类型

# .loc[ ]
print("法二:")
print(s.iloc[0], '\n') # int类型
print(s.iloc[[0, 2, 1]], '\n') # Series类型
print(s.iloc[[0]], '\n') # Series类型
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
法一:
150

语文 150
英语 120
数学 100
dtype: int64

语文 150
dtype: int64

法二:
150

语文 150
英语 120
数学 100
dtype: int64

语文 150
dtype: int64

3)Series的切片
  • Series一维数组切片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

s = pd.Series({'语文': 150, "数学": 100, "英语": 120, "Python": 99, "Numpy": 66, "Pandas": 199})

# Series是一维数组

# 隐式切片 : 左闭右开
print("隐式切片:")
print(s[1: 4], '\n')
print(s.iloc[1: 4], '\n')

# 显式切片: 闭区间(左闭右闭)
print("显式切片:")
print(s["数学": "Python"], '\n')
print(s.loc["数学": "Python"], '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
隐式切片:
数学 100
英语 120
Python 99
dtype: int64

数学 100
英语 120
Python 99
dtype: int64

显式切片:
数学 100
英语 120
Python 99
dtype: int64

数学 100
英语 120
Python 99
dtype: int64


4)Series的属性和方法
  • 属性
  1. shape —— 形状
  2. size —— 大小
  3. index —— 索引
  4. values —— 值
  5. dtype —— 元素类型
  6. name —— Series名字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
import pandas as pd

s = pd.Series({'语文': 150, "数学": 100, "英语": 120, "Python": 99, "Numpy": 66, "Pandas": 199})

print("shape —— 形状:")
print(s.shape, '\n')

print("size —— 大小:")
print(s.size, '\n')

print("index —— 索引:")
print(s.index, '\n')

print("values —— 值:")
print(s.values, '\n')

print("dtype —— 元素类型:")
print(s.dtype, '\n')

print("name —— Series名字:")
print(s.name, '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
shape —— 形状:
(6,)

size —— 大小:
6

index —— 索引:
Index(['语文', '数学', '英语', 'Python', 'Numpy', 'Pandas'], dtype='object')

values —— 值:
[150 100 120 99 66 199]

dtype —— 元素类型:
int64

name —— Series名字:
None


  • 查看首尾数据
  1. head() 查看前几条数据,默认5条

  2. tail() 查看后几条数据,默认5条

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import pandas as pd

s = pd.Series({'语文': 150, "数学": 100, "英语": 120, "Python": 99, "Numpy": 66, "Pandas": 199})

# 查看前几条数据,默认5条
print(s.head(), '\n')
print(s.head(2), '\n')

# 查看后几条数据,默认5
print(s.tail(), '\n')
print(s.tail(2), '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
语文        150
数学 100
英语 120
Python 99
Numpy 66
dtype: int64

语文 150
数学 100
dtype: int64

数学 100
英语 120
Python 99
Numpy 66
Pandas 199
dtype: int64

Numpy 66
Pandas 199
dtype: int64


  • 检测缺失数据
  1. pd.isnull()
  2. pd.notnull()
  3. isnull()
  4. notnull()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import pandas as pd

s = pd.Series(["张三", "李四", "王五", np.nan])

print("isnul():")
print(pd.isnull(s), '\n') # 等价于写s.isnull()

# s.notnull()
print("notnul():")
print(pd.notnull(s), '\n') # 等价于写s.notnull()

# 可以通过True,Flase过滤数据
# 保留不为空的数据
print(s[ pd.notnull(s) ])
# 解释:
print("等价于:")
print(s[[True,True,True,False]],'\n')
print(s[~pd.isnull(s)],'\n') # ‘~’取反
查看输出
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
isnul():
0 False
1 False
2 False
3 True
dtype: bool

notnul():
0 True
1 True
2 True
3 False
dtype: bool

0 张三
1 李四
2 王五
dtype: object
等价于:
0 张三
1 李四
2 王五
dtype: object

0 张三
1 李四
2 王五
dtype: object

5)Series的运算
  • (1) 适用于NumPy的数组运算也适用于Series
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import numpy as np
import pandas as pd

s = pd.Series(np.random.randint(10, 100, size=3))
print("原数据:")
print(s, '\n')

print("+")
print(s + 100, '\n')

print("-")
print(s - 100, '\n')

print("*")
print(s * 100, '\n')

print("/")
print(s / 100, '\n')

print("//")
print(s // 10, '\n')

print("**")
print(s ** 2, '\n')
查看输出
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
32
33
34
35
36
37
38
39
40
41
42
原数据:
0 55
1 98
2 65
dtype: int32

+
0 155
1 198
2 165
dtype: int32

-
0 -45
1 -2
2 -35
dtype: int32

*
0 5500
1 9800
2 6500
dtype: int32

/
0 0.55
1 0.98
2 0.65
dtype: float64

//
0 5
1 9
2 6
dtype: int32

**
0 3025
1 9604
2 4225
dtype: int32


  • (2) Series之间的运算
  1. 在运算中自动对齐索引的数据
  2. 如果索引不对应,则补NaN
  3. Series没有广播机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import pandas as pd

s1 = pd.Series([10, 20, 30])
s2 = pd.Series([10, 20, 30])
print(s1 + s2, '\n')

# 按索引进行匹配
s1 = pd.Series([10, 20, 30], [1, 2, 3])
s2 = pd.Series([10, 20, 30], [3, 2, 1])
print(s1 + s2, '\n')

# 没有的位置记为nan再进行运算
s1 = pd.Series([10, 20, 30])
s2 = pd.Series([10, 20, 30, 40])
print(s1 + s2, '\n')

# 不想要是nan,可以用add()来指定默认值
print(s1.add(s2, fill_value=1))
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0    20
1 40
2 60
dtype: int64

1 40
2 40
3 40
dtype: int64

0 20.0
1 40.0
2 60.0
3 NaN
dtype: float64

0 20.0
1 40.0
2 60.0
3 41.0
dtype: float64


DataFrame

前期提要:Series可以看做是一个有序的字典结构

DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

  • 行索引:index
  • 列索引:columns
  • 值:values(numpy的二维数组)

1)DataFrame的创建

最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。

此外,DataFrame会自动加上每一行的索引(和Series一样)。

同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN

1
2
3
4
5
6
7
8
9
10
import numpy as np
import pandas as pd

d = {
'name' : ["鲁班", '陈咬金', "猪八戒"],
'age' : [7, 9, 8],
'sex': ['男', '女', '男']
}
df = pd.DataFrame(d)
print(df)
查看输出
1
2
3
4
  name  age sex
0 鲁班 7 男
1 陈咬金 9 女
2 猪八戒 8 男


  • DataFrame属性和方法
  1. values —— 值
  2. columns —— 列索引
  3. index —— 行索引(可以直接赋值修改)
  4. shape —— 形状
  5. head() —— 查看前几行数据 (默认5条)
  6. tail() —— 查看后几行数据 (默认5条)
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
import numpy as np
import pandas as pd

d = {
'name' : ["鲁班", '陈咬金', "猪八戒"],
'age' : [7, 9, 8],
'sex': ['男', '女', '男']
}
df = pd.DataFrame(d)

print("values —— 值")
print(df.values, '\n')

print("columns —— 列索引")
print(df.columns, '\n')

print("index —— 行索引")
print(df.index, '\n')

print("shape —— 形状")
print(df.shape, '\n')

print("head() —— 查看前几行数据")
print(df.head(), '\n')

print("tail() —— 查看后几行数据")
print(df.tail(), '\n')
查看输出
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
values —— 值
[['鲁班' 7 '男']
['陈咬金' 9 '女']
['猪八戒' 8 '男']]

columns —— 列索引
Index(['name', 'age', 'sex'], dtype='object')

index —— 行索引
RangeIndex(start=0, stop=3, step=1)

shape —— 形状
(3, 3)

head() —— 查看前几行数据
name age sex
0 鲁班 7 男
1 陈咬金 9 女
2 猪八戒 8 男

tail() —— 查看后几行数据
name age sex
0 鲁班 7 男
1 陈咬金 9 女
2 猪八戒 8 男


  • 创建DataFrame的其他方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd

d = {
'name' : ["鲁班", '陈咬金', "猪八戒"],
'age' : [7, 9, 8],
'sex': ['男', '女', '男']
}
df = pd.DataFrame(d, list('abc'))
print(df, '\n')

df = pd.DataFrame(
data=np.random.randint(10, 100, size=(4,6)),
index=["小明", "小红", "小欢", "小白"],
columns=["语文", "数学", "英语", "物理", "化学", "生物"]
)
print(df)
查看输出
1
2
3
4
5
6
7
8
9
10
  name  age sex
a 鲁班 7 男
b 陈咬金 9 女
c 猪八戒 8 男

语文 数学 英语 物理 化学 生物
小明 75 64 83 10 45 43
小红 47 26 49 28 92 93
小欢 68 86 30 87 50 88
小白 69 40 47 96 18 67

2)DataFrame的索引
  • (1) 对列进行索引
  1. 通过类似字典的方式

  2. 通过属性的方式

可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
import pandas as pd

df = pd.DataFrame(
data=np.random.randint(10, 100, size=(4,6)),
index=["小明", "小红", "小欢", "小白"],
columns=["语文", "数学", "英语", "物理", "化学", "生物"]
)

# 得到的类型是Series
print(df['语文'], '\n')

# 得到的类型是DataFrame
print(df[['语文', '化学']], '\n')
print(df[['语文']], '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
小明    73
小红 14
小欢 44
小白 78
Name: 语文, dtype: int32

语文 化学
小明 73 84
小红 14 58
小欢 44 56
小白 78 86

语文
小明 73
小红 14
小欢 44
小白 78


  • (2) 对行进行索引
  1. 使用.loc[ ]加index来进行行索引
  2. 使用.iloc[ ]加整数来进行行索引

同样返回一个Series,index为原来的columns。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd

df = pd.DataFrame(
data=np.random.randint(10, 100, size=(4,6)),
index=["小明", "小红", "小欢", "小白"],
columns=["语文", "数学", "英语", "物理", "化学", "生物"]
)

# DataFrame默认取列索引, 所以采用下面的方式取
print(df.loc['小明'], '\n') # Series
print(df.iloc[0], '\n')

print(df.loc[['小明', '小欢']], '\n') # DataFrame
print(df.loc[['小明']], '\n')
print(df.iloc[[0, 2]], '\n') # DataFrame
print(df.iloc[[0]], '\n')
查看输出
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
语文    29
数学 90
英语 56
物理 90
化学 33
生物 36
Name: 小明, dtype: int32

语文 29
数学 90
英语 56
物理 90
化学 33
生物 36
Name: 小明, dtype: int32

语文 数学 英语 物理 化学 生物
小明 29 90 56 90 33 36
小欢 74 56 97 73 93 94

语文 数学 英语 物理 化学 生物
小明 29 90 56 90 33 36

语文 数学 英语 物理 化学 生物
小明 29 90 56 90 33 36
小欢 74 56 97 73 93 94

语文 数学 英语 物理 化学 生物
小明 29 90 56 90 33 36


  • (3) 对元素索引的方法
  1. 使用列索引

  2. 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)

  3. 使用values属性(二维numpy数组)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import pandas as pd

df = pd.DataFrame(
data=np.random.randint(0, 100, size=(4, 6)),
index=['小明', "小红", '小绿', '小黄'],
columns=['语文', '数学', '英语', 'Python', 'Numpy', 'Pandas']
)

print("原表:")
print(df)

# 先取列,再取行
print(df['语文'][1])
print(df['语文']['小明'])

# 先取行,再取列
print(df.iloc[1]['语文'])
print(df.loc['小明', '语文'])
查看输出
1
2
3
4
5
6
7
8
9
10
原表:
语文 数学 英语 Python Numpy Pandas
小明 7 88 51 10 81 50
小红 82 51 94 76 6 98
小绿 92 22 88 1 35 94
小黄 86 87 63 65 18 20
82
7
82
7

3)DataFrame 的切片

【注意】 直接用中括号时:

  • 索引表示的是列索引
  • 切片表示的是行切片
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
32
33
34
35
import numpy as np
import pandas as pd

df = pd.DataFrame(
data=np.random.randint(0, 100, size=(4, 6)),
index=['小明', "小红", '小绿', '小黄'],
columns=['语文', '数学', '英语', 'Python', 'Numpy', 'Pandas']
)
print("原表:")
print(df, '\n')
# 索引: 优先使用列索引, 先取行就需要写loc或iloc
# 切片: 优先按行切片, 和Numpy操作类似

# 行: 行名, 行数字索引
# 列: 列名

# 行切片
print("行切片:")
print(df[1 : 3], '\n') # 左闭右开
print(df['小明' : "小绿"], '\n') # 左闭右开

print(df.iloc[1 : 3], '\n') # 左闭右开
print(df.loc['小明' : "小绿"], '\n') # 左闭右开

# 列切片: 需要使用loc或iloc
print("列切片:")
print(df.iloc[:, 1:3], '\n')
print(df.loc[:, "数学": "Python"], '\n')

# 练习1,同时切片
print("练习:")
print(df.loc["小明":"小绿", "数学":"Python"], '\n')
print(df.iloc[:3, 1:4], '\n')
# 练习2, 不连续取
print(df.loc[["小明", "小黄"], ["语文", "Pandas"]])
查看输出
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
原表:
语文 数学 英语 Python Numpy Pandas
小明 43 24 93 60 28 80
小红 60 22 53 85 74 8
小绿 39 23 75 63 84 14
小黄 1 82 0 86 60 47

行切片:
语文 数学 英语 Python Numpy Pandas
小红 60 22 53 85 74 8
小绿 39 23 75 63 84 14

语文 数学 英语 Python Numpy Pandas
小明 43 24 93 60 28 80
小红 60 22 53 85 74 8
小绿 39 23 75 63 84 14

语文 数学 英语 Python Numpy Pandas
小红 60 22 53 85 74 8
小绿 39 23 75 63 84 14

语文 数学 英语 Python Numpy Pandas
小明 43 24 93 60 28 80
小红 60 22 53 85 74 8
小绿 39 23 75 63 84 14

列切片:
数学 英语
小明 24 93
小红 22 53
小绿 23 75
小黄 82 0

数学 英语 Python
小明 24 93 60
小红 22 53 85
小绿 23 75 63
小黄 82 0 86

练习:
数学 英语 Python
小明 24 93 60
小红 22 53 85
小绿 23 75 63

数学 英语 Python
小明 24 93 60
小红 22 53 85
小绿 23 75 63

语文 Pandas
小明 43 80
小黄 1 47

4)DataFrame的运算
  • (1)DataFrame与标量之间的运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

df = pd.DataFrame(
data=np.random.randint(0, 100, size=(4, 6)),
index=['小明', "小红", '小绿', '小黄'],
columns=['语文', '数学', '英语', 'Python', 'Numpy', 'Pandas']
)
print("原表:")
print(df, '\n')

print(df + 100, '\n')
print(df - 100, '\n')
print(df / 10, '\n')
print(df % 10, '\n')
print(df ** 2, '\n')
查看输出
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
32
33
34
35
36
原表:
语文 数学 英语 Python Numpy Pandas
小明 81 3 84 78 28 0
小红 94 82 63 15 7 4
小绿 32 88 8 74 37 62
小黄 57 21 34 38 7 98

语文 数学 英语 Python Numpy Pandas
小明 181 103 184 178 128 100
小红 194 182 163 115 107 104
小绿 132 188 108 174 137 162
小黄 157 121 134 138 107 198

语文 数学 英语 Python Numpy Pandas
小明 -19 -97 -16 -22 -72 -100
小红 -6 -18 -37 -85 -93 -96
小绿 -68 -12 -92 -26 -63 -38
小黄 -43 -79 -66 -62 -93 -2

语文 数学 英语 Python Numpy Pandas
小明 8.1 0.3 8.4 7.8 2.8 0.0
小红 9.4 8.2 6.3 1.5 0.7 0.4
小绿 3.2 8.8 0.8 7.4 3.7 6.2
小黄 5.7 2.1 3.4 3.8 0.7 9.8

语文 数学 英语 Python Numpy Pandas
小明 1 3 4 8 8 0
小红 4 2 3 5 7 4
小绿 2 8 8 4 7 2
小黄 7 1 4 8 7 8

语文 数学 英语 Python Numpy Pandas
小明 6561 9 7056 6084 784 0
小红 8836 6724 3969 225 49 16
小绿 1024 7744 64 5476 1369 3844
小黄 3249 441 1156 1444 49 9604

  • (2) DataFrame之间的运算
  1. 在运算中自动对齐索引的数据

  2. 如果索引不对应,则补NaN

  3. DataFrame没有广播机制

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
import numpy as np
import pandas as pd

# 创建DataFrame df1 不同人员的各科目成绩,月考一
df1 = pd.DataFrame(
data={
'Python': [100, 90, 80],
'Java': [80, 70, 60],
'PHP': [60, 50, 40]
},
index=['张飞', "吕布", '关羽']
)

# 创建DataFrame df2 不同人员的各科目成绩,月考二
df2 = pd.DataFrame(
data={
'Python': [100, 90, 80, 70],
'Java': [80, 70, 60, 50],
'PHP': [60, 50, 40, 30],
'Go': [40, 30, 20, 10]
},
index=['张飞', "吕布", '关羽', "刘备"]
)

# DataFrame之间的运算
print(df1 + df2, '\n')

# 自动填充, 再相加(除法就用divide(),其他一样)
print(df1.add(df2, fill_value=1000), '\n')
查看输出
1
2
3
4
5
6
7
8
9
10
11
12
    Go   Java    PHP  Python
关羽 NaN 120.0 80.0 160.0
刘备 NaN NaN NaN NaN
吕布 NaN 140.0 100.0 180.0
张飞 NaN 160.0 120.0 200.0

Go Java PHP Python
关羽 1020.0 120.0 80.0 160.0
刘备 1010.0 1050.0 1030.0 1070.0
吕布 1030.0 140.0 100.0 180.0
张飞 1040.0 160.0 120.0 200.0


  • (3)Series与DataFrame之间的运算
  1. 使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)

  2. 使用pandas操作函数:
    axis=0:以列为单位操作(参数必须是列),对所有列都有效。
    axis=1:以行为单位操作(参数必须是行),对所有行都有效。

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
import numpy as np
import pandas as pd

# 创建DataFrame df1 不同人员的各科目成绩,月考一
# 创建DataFrame df1 不同人员的各科目成绩,月考一
df1 = pd.DataFrame(
data={
'Python': [100, 90, 80],
'Java': [80, 70, 60],
'PHP': [60, 50, 40]
},
index=['张飞', "吕布", '关羽']
)

s = pd.Series([100, 10, 1], index=df1.columns)

# 直接相加
print(df1 + s, '\n')

# 使用add函数
print(df1.add(s), '\n') # 列
print(df1.add(s, axis='columns'), '\n') # 列
print(df1.add(s, axis=1), '\n') # 列

s = pd.Series([100, 10, 1], index=df1.index)
print(df1.add(s, axis='index'), '\n') # 行
print(df1.add(s, axis=0), '\n') # 行
查看输出
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
    Python  Java  PHP
张飞 200 90 61
吕布 190 80 51
关羽 180 70 41

Python Java PHP
张飞 200 90 61
吕布 190 80 51
关羽 180 70 41

Python Java PHP
张飞 200 90 61
吕布 190 80 51
关羽 180 70 41

Python Java PHP
张飞 200 90 61
吕布 190 80 51
关羽 180 70 41

Python Java PHP
张飞 200 180 160
吕布 100 80 60
关羽 81 61 41

Python Java PHP
张飞 200 180 160
吕布 100 80 60
关羽 81 61 41







3. Pandas层次化索引

3.1. 创建多层行索引

  • 1) 隐式构造
  1. 最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd

data = np.random.randint(0, 100, size=(6, 6))

index = [
['1班', '1班', '1班', '2班', '2班', '2班'],
['张三', '李四', '王五', '赵六', '田七', '孙八']
]

columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
print(df)
查看输出
1
2
3
4
5
6
7
8
       期中          期末        
语文 数学 英语 语文 数学 英语
1班 张三 5 48 31 55 77 80
李四 49 31 69 47 53 87
王五 9 36 93 97 17 34
2班 赵六 12 76 5 36 45 90
田七 50 10 1 89 45 16
孙八 30 1 25 5 30 22
  1. Series也可以创建多层索引
1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import pandas as pd

data = np.random.randint(0, 100, size=6)

index = [
['1班', '1班', '1班', '2班', '2班', '2班'],
['张三', '李四', '王五', '赵六', '田七', '孙八']
]

s = pd.Series(data=data, index=index)
print(s)
查看输出
1
2
3
4
5
6
7
1班  张三    33
李四 75
王五 3
2班 赵六 46
田七 28
孙八 99
dtype: int32

  • 2) 显示构造pd.MultiIndex
  1. 使用数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd

data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_arrays( [
['1班', '1班', '1班', '2班', '2班', '2班'],
['张三', '李四', '王五', '赵六', '田七', '孙八']
] )

columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
print(df)
查看输出
1
2
3
4
5
6
7
8
       期中          期末        
语文 数学 英语 语文 数学 英语
1班 张三 15 18 8 89 60 66
李四 82 16 91 80 18 73
王五 37 60 32 87 12 74
2班 赵六 38 31 34 84 74 53
田七 17 11 99 74 82 47
孙八 5 57 54 58 30 17
  1. 使用tuple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import pandas as pd

data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_tuples(
(
('1班', '张三'), ('1班', '李四'), ('1班', '王五'),
('2班', '赵六'), ('2班', '田七'), ('2班', '孙八'),
)
)

columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
print(df)
查看输出
1
2
3
4
5
6
7
8
       期中          期末        
语文 数学 英语 语文 数学 英语
1班 张三 16 45 36 67 48 13
李四 72 29 72 8 81 33
王五 56 98 69 93 93 55
2班 赵六 24 64 30 1 76 88
田七 75 28 16 62 20 14
孙八 33 53 96 32 32 75
  1. 使用product

笛卡尔积:{a, b} {c, d} => {a, c} {a, d} {b, c} {b, d}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
import pandas as pd

data = np.random.randint(0, 100, size=(6, 6))

# 笛卡尔积:{a, b} {c, d} => {a,c}, {a,d}, {b,c}, {b,d}
index = pd.MultiIndex.from_product(
[
['1班', '2班'],
['张三', '李四', '王五']
]
)

columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
print(df)
查看输出
1
2
3
4
5
6
7
8
       期中          期末        
语文 数学 英语 语文 数学 英语
1班 张三 80 82 69 56 95 71
李四 87 9 69 15 48 19
王五 72 80 56 18 37 60
2班 张三 89 24 86 42 88 24
李四 39 77 83 35 97 96
王五 67 43 48 52 48 79

3.2. 创建多层列索引(同行索引)

除了行索引index,列索引columns也能用同样的方法创建多层索引


3.3. 多层索引对象的索引与切片操作

  • 1)Series的操作

【重要】对于Series来说,直接中括号[]与使用.loc()完全一样

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import numpy as np
import pandas as pd

# (1) 索引
data = np.random.randint(0, 100, size=6)

index = [
['1班', '1班', '1班', '2班', '2班', '2班'],
['张三', '李四', '王五', '赵六', '田七', '孙八']
]

s = pd.Series(data=data, index=index)
print("原表:")
print(s, '\n')

# 显式索引
print("s['1班']:")
print(s['1班'], '\n')
print("s.loc['1班']:")
print(s.loc['1班'], '\n')

print("s.loc[['1班']]:")
print(s.loc[['1班']], '\n')
print("s.loc[['1班', '2班']]:")
print(s.loc[['1班', '2班']], '\n')

print("s['1班']['张三']:")
print(s['1班']['张三'], '\n')
print("s.loc['1班']['张三']:")
print(s.loc['1班']['张三'], '\n')
print("s.loc['1班','张三']:")
print(s.loc['1班','张三'], '\n')
print("s['1班', '张三']:")
print(s['1班', '张三'], '\n')

#隐式索引
print("s[1]:")
print(s[1], '\n')
print("s.iloc[1]:")
print(s.iloc[1], '\n')
print("s.iloc[[3, 2]]:")
print(s.iloc[[3, 2]], '\n')


# (2) 切片
# 显式切片
print("s['1班': '1班']:")
print(s['1班': '1班'], '\n')
print("s.loc['1班': '2班']:")
print(s.loc['1班': '2班'], '\n')
# s.loc['李四': '田七'] # 没有结果
# s.loc[('1班', '李四'): ('2班', '田七')] # 报错, 显式切片只对最外层索引有效

# 跨班建议使用隐式切片
print("s[1: 4]:")
print(s[1: 4], '\n')
print("s.iloc[1: 5]:")
print(s.iloc[1: 5], '\n')
查看输出
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
原表:
1班 张三 85
李四 50
王五 44
2班 赵六 81
田七 3
孙八 28
dtype: int32

s['1班']:
张三 85
李四 50
王五 44
dtype: int32

s.loc['1班']:
张三 85
李四 50
王五 44
dtype: int32

s.loc[['1班']]:
1班 张三 85
李四 50
王五 44
dtype: int32

s.loc[['1班', '2班']]:
1班 张三 85
李四 50
王五 44
2班 赵六 81
田七 3
孙八 28
dtype: int32

s['1班']['张三']:
85

s.loc['1班']['张三']:
85

s.loc['1班','张三']:
85

s['1班', '张三']:
85

s[1]:
50

s.iloc[1]:
50

s.iloc[[3, 2]]:
2班 赵六 81
1班 王五 44
dtype: int32

s['1班': '1班']:
1班 张三 85
李四 50
王五 44
dtype: int32

s.loc['1班': '2班']:
1班 张三 85
李四 50
王五 44
2班 赵六 81
田七 3
孙八 28
dtype: int32

s[1: 4]:
1班 李四 50
王五 44
2班 赵六 81
dtype: int32

s.iloc[1: 5]:
1班 李四 50
王五 44
2班 赵六 81
田七 3
dtype: int32

2)DataFrame的操作
  • 可以直接使用列名称来进行列索引
  • 使用行索引需要用iloc(),loc()等函数
  • 无法直接对二级索引进行索引
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_product(
[
['1班', '2班'],
['张三', '李四', '王五']
]
)
columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]
df = pd.DataFrame(data=data, index=index, columns=columns)


# 获取元素
df['期中']['数学'][1]

df.iloc[1, 3] # 第1行,第3列(索引) 42
df.loc[('1班', '李四'), ('期末', '语文')] # 42

# 列索引
df['期中']
df['期中']['数学']
df['期中', '数学']
# df[('期中', '数学')]
# df.期中.数学

df.iloc[:, 2]
df.iloc[:, [1,2,3]]

# 行索引
df.loc['1班']
df.loc['1班'].loc['张三']
df.loc['1班', '张三']
df.loc[('1班', '张三')]

df.iloc[1]
df.iloc[[1]]
df.iloc[[1,2,3]]

# 切片
# 行切片
df.iloc[1:5]
df.loc['1班' : '2班']
df.loc[('1班', '李四') : ('2班', '李四')]

# 列切片
df.iloc[:, 1: 5]
df.loc[:, '期中': '期末']
# df.loc[:, ('期中', '数学'): ('期末', '数学')] # 报错

3.4. 索引的堆叠(stack)

  • stack()
  • unstack()

【小技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data = np.random.randint(0, 100, size=(6, 6))
index = pd.MultiIndex.from_product(
[
['1班', '2班'],
['张三', '李四', '王五']
]
)
columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]
df = pd.DataFrame(data=data, index=index, columns=columns)

# stack: 列索引变成行索引
df.stack() # 默认level=-1 (倒数第一层),将最里层的列索引 变成行索引
df.stack(level=1)

df.stack(level=0) # 将最外层的列索引 变成行索引

【小技巧】使用unstack()的时候,level等于哪一个,哪一个就消失,出现在列里。

1
2
3
4
5
# unstack : 将行索引 变成 列索引
df.unstack()
df.unstack(level=1)

df.unstack(level=0)

使用fill_value填充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data = np.random.randint(0, 100, size=(6, 6))
index = pd.MultiIndex.from_tuples(
(
('1班', '张三'), ('1班', '李四'), ('1班', '王五'),
('2班', '赵六'), ('2班', '田七'), ('2班', '孙八'),
)
)
columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]
df2 = pd.DataFrame(data=data, index=index, columns=columns)

df2.unstack()
df2.unstack(fill_value=0)

3.5. 聚合操作

【注意】

  • 需要指定axis
  • 【小技巧】和unstack()相反,聚合的时候,axis等于哪一个,哪一个就保留。
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
data = np.random.randint(0, 100, size=(6, 6))
index = pd.MultiIndex.from_tuples(
(
('1班', '张三'), ('1班', '李四'), ('1班', '王五'),
('2班', '赵六'), ('2班', '田七'), ('2班', '孙八'),
)
)
columns = [
['期中', '期中', '期中', '期末', '期末', '期末'],
['语文', '数学', '英语', '语文', '数学', '英语']
]
df2 = pd.DataFrame(data=data, index=index, columns=columns)


# DataFrame聚合操作:求和,平均值,最大值,最小值....
df3 = df.loc['1班', '期中']

# axis : 0表式行index, 1表式列columns
df3.sum()
df3.sum(axis=0) # 对同一列的多行进行求和
df3.sum(axis=1) # 对同一行的多列进行求和


# 多层索引聚合操作
df.sum() # 默认是对同一列的多行求和
df.sum(axis=1) # 对同一行的多列求和
df.sum(axis=0, level=0) # 表式 行 索引中的最外层
df.sum(axis=1, level=0) # 表式 列 索引中的最外层
df.sum(axis=0, level=1) # 表式 行 索引中的最里层
df.sum(axis=1, level=1) # 表式 列 索引中的最里层

4. Pandas数据合并

  • pd.concat
  • pd.append
  • pd.merge

为了方便,我们首先定义一个生成DataFrame的函数:

1
2
3
4
5
6
7
def make_df(indexs, columns):    
data = [[str(j)+str(i) for j in columns] for i in indexs]
df = pd.DataFrame(data=data, index=indexs, columns=columns)
return df

# 调用
# make_df([1, 2, 3, 4], list('ABCD'))
1. 使用pd.concat()级联

Pandas使用pd.concat函数,与NumPy中的concatenate函数类似,只是多了一些参数:

1) 简单级联
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
df1 = make_df([1, 2], ['A', 'B'])
df2 = make_df([3, 4], ['A', 'B'])
display(df1, df2)

# 上下合并,垂直合并
pd.concat([df1, df2])

# 左右合并,水平合并
pd.concat([df1, df2], axis=1)

# 忽略行索引,重置行索引
pd.concat([df1, df2], ignore_index=True)

# 使用多层索引 keys
pd.concat([df1, df2], keys=['x', 'y'])
# pd.concat([df1, df2], keys=['x', 'y'], axis=1)
2) 不匹配级联

不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

1
2
3
4
5
6
7
8
9
10
11
12
13
df3 = make_df([1, 2, 3, 4], ['A', 'B', 'C', 'D'])
df4 = make_df([2, 3, 4, 5], ['B', 'C', 'D', 'E'])
display(df3, df4)

# 对应索引没有值的会自动用NaN填充
pd.concat([df3, df4])

# 外连接:补NaN(默认模式), 默认值outer,类似并集, 所有数据都会显示
pd.concat([df3, df4])
pd.concat([df3, df4], join='outer')

# 内连接:只连接匹配的项, 交集, 只显示共同的列或行
pd.concat([df3, df4], join='inner')
2. 使用append()函数添加

由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加

1
2
3
4
5
df3 = make_df([1, 2, 3, 4], ['A', 'B', 'C', 'D'])
df4 = make_df([2, 3, 4, 5], ['B', 'C', 'D', 'E'])
display(df3, df4)

df3.append(df4, sort=True)
3.使用merge()合并
  • 类似MySQL中表和表之间的合并
  • merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并
  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
  • 每一列元素的顺序不要求一致
1) 一对一合并
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 3],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 3, 4],
'sex': ['男', '女', '女'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

# 合并
# pd.merge(df1, df2)
df1.merge(df2)
2) 多对一合并
1
2
3
4
5
6
7
8
9
10
11
12
13
14
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 2],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 3, 4],
'sex': ['男', '女', '女'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

# 合并
df1.merge(df2)
3) 多对多合并
1
2
3
4
5
6
7
8
9
10
11
12
13
14
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 2],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 2, 4],
'sex': ['男', '女', '女'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

# 合并
df1.merge(df2)
4) key的规范化
  • 使用on=显式指定哪一列为key,当有多个key相同时使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 3],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 3, 4],
'name': ['李四', '王五', '赵六'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

# 如果有多列名称相同, 则需要指定一列作为连接的字段
df1.merge(df2, on='id')
df1.merge(df2, on='name')
  • 使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不想等时使用
1
2
# 如果没有相同的列名,则需要使用left_on和right_on来分别指定2个表的列作为连接的字段
df1.merge(df2, left_on='id', right_on='id2')
  • 当左边的列和右边的index相同的时候,使用right_index=True
1
df1.merge(df2, left_index=True, right_on='id2')
5) 内合并与外合并
  • 内合并:只保留两者都有的key(默认模式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 3],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 3, 4],
'sex': ['男', '女', '女'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

# 内连接: inner join
df1.merge(df2)
df1.merge(df2, how='inner')
  • 外合并 how=‘outer’:补NaN
1
2
# 外连接: 
df1.merge(df2, how='outer')
  • 左合并、右合并:how=‘left’,how=‘right’
1
2
3
4
5
# 左连接: 
df1.merge(df2, how='left')

# 右连接:
df1.merge(df2, how='right')
6) 添加后缀
  • 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名
  • 可以使用suffixes=自己指定后缀
1
2
3
4
5
6
7
8
9
10
11
12
13
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五'],
'id' : [1, 2, 3],
'age': [22, 33, 44]
})
df2 = pd.DataFrame({
'id' : [2, 3, 4],
'name': ['李四', '王五', '赵六'],
'job': ['saler', 'CTO', 'Programer']
})
display(df1, df2)

df1.merge(df2, on='id', suffixes=['_表1', '_表2'])
merge合并总结:
  • 合并有三种现象: 一对一, 多对一, 多对多.
  • 合并默认会找相同的列名进行合并, 如果有多个列名相同,用on来指定.
  • 如果没有列名相同,但是数据又相同,可以通过left_on, right_on来分别指定要合并的列.
  • 如果想和index合并, 使用left_index, right_index来指定.
  • 如果多个列相同,合并之后可以通过suffixes来区分.
  • 还可以通过how来控制合并的结果, 默认是内合并, 还有外合并outer, 左合并left, 右合并right.

六、Pandas缺失值处理

有两种缺失值(空值):

  • None
  • np.nan
1. None
  • None是Python自带的,是Python中的空对象。None不能参与到任何计算中。

  • object类型的运算要比int类型的运算慢得多

1
2
3
4
5
6
# 计算不同数据类型求和时间
%timeit np.arange(1e5, dtype=object).sum()
# 6.1 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.arange(1e5, dtype=np.int32).sum()
# 134 µs ± 7.16 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
2. np.nan(NaN)
  • np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
1
2
type(np.nan)
# float
  • 但可以使用np.nan*()函数来计算nan,此时会过滤掉nan。
1
2
3
4
5
6
n = np.array([1, 2, 3, np.nan, 5, 6])

# np.sum(n) # nan
np.nansum(n)

np.nan + 10
3. pandas中的None与NaN
1) pandas中None与np.nan都视作np.nan
  • 创建DataFrame
1
2
3
4
5
6
7
8
9
10
11
data = np.random.randint(0 ,100, size=(5, 5))
df = pd.DataFrame(data=data, columns=list('ABCDE'))

# 修改数据,增加2种nan
df.loc[2, 'B'] = np.nan
df.loc[3, 'C'] = None
display(df)

# 查看结果
df.loc[2, 'B'] # nan
df.loc[3, 'C'] # nan
2) pandas中None与np.nan的操作
  • isnull()
  • notnull()
  • all()
  • any()
  • dropna(): 过滤丢失数据
  • fillna(): 填充丢失数据

(1)判断函数

  • isnull()
  • notnull()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# isnull
df.isnull()

# notnull
df.notnull()

# all(): 必须全部为True才为True, 类似and
# any(): 只要有一个为True即为True, 类似or

df.isnull().any() # 常用, 尽可能找到所有的空值
# df.isnull().all()

df.notnull().all() # 常用,尽可能找到所有的空值
# df.notnull().any()

df.isnull().any(axis=1) # axis=1 表式列,判断一行中的每一列数据进行判断
df.notnull().all(axis=1)
  • 使用bool值索引过滤数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 行过滤
# 将df中有空的列过滤掉
cond = df.isnull().any(axis=1)
# display(cond, ~cond)
# ~ 取反
df[~cond]

cond = df.notnull().all(axis=1)
# cond
df[cond]

# 列过滤
cond = df.notnull().all()
# cond
df.loc[:, cond]

cond = df.isnull().any()
# cond
df.loc[:, ~cond]

(2) 过滤函数

  • dropna()

可以选择过滤的是行还是列(默认为行)

1
2
df.dropna()  # 默认是删除有空的行
df.dropna(axis=1) # 删除有空的列

也可以选择过滤的方式 how = ‘all’

1
2
df.dropna(how='any')  # 默认值,默认有空就会删除
df.dropna(how='all', axis=1) # 所有的值都为空(整行或整列为空),才删除

inplace=True 修改原数据

1
2
3
4
5
df2 = df.copy()

# inplace=True: 表式修改原数据
df2.dropna(inplace=True)
df2

(3) 填充函数 Series/DataFrame

  • fillna()
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
# 填充
df.fillna(value=100)

df2 = df.copy()
df2.loc[1, 'B'] = np.nan
df2.loc[4, 'C'] = None
display(df2)

# limit: 限制对应维度上填充的次数
df2.fillna(value=100, limit=1, inplace=True)

# 可以选择前向填充还是后向填充
# method : {'backfill', 'bfill', 'pad', 'ffill', None}, default None
# Method to use for filling holes in reindexed Series
# pad/ffill: propagate last valid observation forward to next valid
# backfill/bfill: use next valid observation to fill gap.

df.fillna(method='ffill') # 用上面数据来填充自己
# df.fillna(method='pad')

df.fillna(method='bfill') # 用下面数据来填充自己
# df.fillna(method='backfill')

df.fillna(method='ffill', axis=1) # 用左边数据来填充自己

df.fillna(method='bfill', axis=1) # 用右边数据来填充自己

七、Pandas处理重复值和异常值

1
2
3
4
5
6
def make_df(indexs, columns):    
data = [[str(j)+str(i) for j in columns] for i in indexs]
df = pd.DataFrame(data=data, index=indexs, columns=columns)
return df

# make_df([1, 2, 3, 4], ['A', 'B', 'C', 'D'])
1. 删除重复行
  • 使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象
  • 每个元素对应一行,如果该行不是第一次出现,则元素为True
1
2
3
4
5
6
7
8
9
10
11
12
13
# 让第一行和第二行重复
df.loc[1] = df.loc[2]

# 判断是否和前面的行重复了
df.duplicated()

# df.duplicated(keep='first') # 保留第一行
# df.duplicated(keep='last') # 保留最后一行
# df.duplicated(keep=False) # 标记所有重复行

df.loc[1, 'D'] = 'DDD'
# subset: 子集, 只需要子集相同就可以判断重复
df.duplicated(subset=['A', 'B', 'C'])

使用drop_duplicates()函数删除重复的行

1
2
df.drop_duplicates(subset=['A', 'B', 'C'])
df.drop_duplicates(subset=['A', 'B', 'C'], keep='last')
2. 映射

映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定

包含三种操作:

  • replace()函数:替换元素
  • map()函数:处理某一单独的列, 最重要
  • rename()函数:替换索引
1) replace()函数:替换元素

使用replace()函数,对values进行替换操作

1
2
3
4
5
6
7
8
index = ['鲁班', '张三丰', '张无忌', '杜甫', '李白']
columns = ['Python', 'Java', 'H5', 'Pandas']
data = np.random.randint(0, 100, size=(5, 4))

df = pd.DataFrame(data=data, index=index, columns=columns)

# replace还经常用来替换NaN元素
df.replace({1: 100})
2) map()函数: 适合处理某一单独的列
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
df2 = df.copy()
df2

# map是Series调用,不能使用DataFrame调用
df2['Python'].map({12: 100, 11: 90})

# map()函数中可以使用lambda函数
# 新建一列
df2['NumPy'] = df2['Python'].map(lambda x: x+100)
df2

# 新增一列:判断java成绩是否及格
df2['是否及格'] = df2['Java'].map(lambda n: "及格" if n>=60 else "不及格")
df2

# 新增一列:判断Java成绩的等级(>=80优秀,>=60及格,<60不及格)
def fn(n):
if n >= 80:
return '优秀'
elif n >= 60:
return '及格'
return '不及格'

df2['等级'] = df2['Java'].map(fn)
df2
3) rename()函数:替换索引
1
2
3
4
5
6
7
8
9
df3 = df.copy()
df3

# 更改索引名称
df3.rename({'鲁班': "Mr Lu"}) # 默认更改行索引
df3.rename({'Python': 'PYTHON'}, axis=1) # 更改列索引

df3.rename(index={'鲁班': "Mr Lu"}) # 更改行索引
df3.rename(columns={'Python': 'PYTHON'}) # 更改列索引
4) apply()函数:既支持 Series,也支持 DataFrame
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
df = pd.DataFrame(data=np.random.randint(0, 10, size=(5,3)),
index=list('ABCDE'),
columns=['Python', 'NumPy', 'Pandas'])

# 用于Series,其中x是Series中元素
df['Python'].apply(lambda x:True if x >5 else False)

# 用于DataFrame,其中的x是DataFrame中列或者行,是Series
df.apply(lambda x : x.median(), axis=0) # 列的中位数
df.apply(lambda x : x.median(), axis=1) # 行的中位数

# 自定义方法
def convert(x):
return (np.round(x.mean(), 1), x.count())
df.apply(convert, axis=1) # 行平均值,计数

# applymap: DataFrame专有, 其中的x是DataFrame中每个元素
df.applymap(lambda x : x + 100) # 计算DataFrame中每个元素
5) transform()函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
df = pd.DataFrame(data=np.random.randint(0, 10, size=(10,3)),
index=list('ABCDEFHIJK'),
columns=['Python', 'NumPy', 'Pandas'])

# 1、一列执行多项计算
df['Python'].transform([np.sqrt, np.exp]) # Series处理

# 2、多列执行不同计算
def convert(x):
if x.mean() > 5:
x *= 10
else:
x *= -10
return x

df.transform({'Python':convert,'NumPy':np.max,'Pandas':np.min})
3. 异常值检测和过滤
  • describe(): 查看每一列的描述性统计量
1
2
3
4
# 查看每一列的描述性统计
df.describe()
df.describe([0.3, 0.4, 0.5, 0.9, 0.99]) # 指定百分位数
df.describe([0.3, 0.4, 0.5, 0.9, 0.99]).T # 转置,行和列转换,在列比较多的情况下使用
  • df.std() : 可以求得DataFrame对象每一列的标准差
1
df.std()
  • df.drop(): 删除特定索引
1
2
3
4
5
6
7
8
9
10
df4 = df.copy()
df4

df4.drop('鲁班') # 默认删除行
df4.drop('Java', axis=1) # 删除列

df4.drop(index='鲁班') # 删除行
df4.drop(columns='H5') # 删除列

df4.drop(columns=['Java', 'Pandas']) # 同时删除多列
  • unique() : 唯一,去重
1
2
3
4
5
6
7
8
9
index = ['鲁班', '张三丰', '张无忌', '杜甫', '李白']
columns = ['Python', 'Java', 'H5', 'Pandas']
data = np.random.randint(0, 10, size=(5, 4))

df = pd.DataFrame(data=data, index=index, columns=columns)
df

# unique() : 要用于Series, 不能用于DataFrame
df['Python'].unique()
  • query() : 按条件查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ==, >, <, 
# in
# and &
# or |

df.query('Python == 5')
df.query('Python > 5')

df.query('Python==5 and Java==5')
df.query('Python==5 & Java==5')
df.query('Python==5 or Java==6')
df.query('Python==5 | Java==6')

# 使用变量
n = 5
df.query('Python > @n') # @n 使用变量
df.query('Python in [3, 4, 5, 6]')
m = [3, 4, 5, 6]
df.query('Python in @m')
  • df.sort_values(): 根据值排序

  • df.sort_index(): 根据索引排序

1
2
3
4
5
6
7
8
9
10
11
12
13
index = ['鲁班', '张三丰', '张无忌', '杜甫', '李白']
columns = ['Python', 'Java', 'H5', 'Pandas']
data = np.random.randint(0, 100, size=(5, 4))

df = pd.DataFrame(data=data, index=index, columns=columns)
df

df.sort_values('Python') # 默认按照列名排序,默认升序
df.sort_values('Python', ascending=False) # 降序
df.sort_values('鲁班', axis=1)

# 按照行索引或列索引排序
df.sort_index(ascending=True, axis=1)
1
df.info()

练习:

新建一个形状为10000*3的标准正态分布的DataFrame,去除掉所有满足以下情况的行:

  • 其中任一元素绝对值大于3倍标准差
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
df = pd.DataFrame(np.random.randn(10000, 3))
df.head()

# 标准差
df.std()
# 绝对值
df.abs()

# cond: 找到大于3倍标准差的值
cond = df.abs() > df.std() * 3
# cond.sum()
cond

# 找到有True(大于3倍标准差的值)的行
cond2 = cond.any(axis=1)
cond2

# 去除大于3倍标准差的值,取不满足大于3倍标准差的值
df.loc[~cond2]
4. 抽样
  • 使用.take()函数排序

  • 可以借助np.random.permutation()函数随机排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用前面的df2
df2.take([4, 1, 2, 3, 0]) # 行排列
df2.take([1, 0, 2, 3, 4, 5, 6], axis=1) # 列排列

# 随机排序
np.random.permutation([0, 1, 2, 3, 4, 5])

# 无放回抽样:依次拿取,没有重复值
df2.take(np.random.permutation([0, 1, 2, 3, 4]))

# 有放回抽样: 可能出现重复值
# 当DataFrame规模足够大时,直接使用np.random.randint()函数,就配合take()函数实现随机抽样
np.random.randint(0, 10, size=10)
df2.take(np.random.randint(0, 5, size=5))

八、Pandas数学函数

  • 聚合函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
df = pd.DataFrame(data=np.random.randint(0,100,size = (20,3)))

df.count() # 非空值的数量
df.max() # 最大值,axis=0/1
df.min() # 最小值, axis=0/1
df.median() # 中位数
df.sum() # 求和
df.mean(axis=1) # 每一行的平均值

df[0].value_counts() # 统计元素出现次数
df.cumsum() # 累加
df.cumprod() # 累乘

# 方差: 当数据分布比较分散(即数据在平均数附近波动较大)时,各个数据与平均数的差的平方和较大,方差就较大;当数据分布比较集中时,各个数据与平均数的差的平方和较小。因此方差越大,数据的波动越大;方差越小,数据的波动就越小
df.var() # 方差

# 标准差 = 方差的算术平方根
df.std() # 标准差
  • 其他数学函数
    • 协方差
      - 两组数值中每对变量的偏差乘积的平均值
      - 协方差>0 : 表式两组变量正相关
      - 如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值时另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值;
      - 协方差<0 : 表式两组变量负相关
      - 如果两个变量的变化趋势相反,即其中一个变量大于自身的期望值时另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。
      - 协方差=0 : 表式两组变量不相关
      • 相关系数
        • 相关系数r = X与Y的协方差 / (X的标准差 * Y的标准差)
        • 相关系数值的范围在-1和+1之间
        • r>0为正相关,r<0为负相关。r=0表示不相关
        • r 的绝对值越大,相关程度越高
        • 两个变量之间的相关程度,一般划分为四级:
          • 如两者呈正相关,r呈正值,r=1时为完全正相关;
          • 如两者呈负相关则r呈负值,而r=-1时为完全负相关,完全正相关或负相关时,所有图点都在直线回归线上;点分布在直线回归线上下越离散,r的绝对值越小。
          • 相关系数的绝对值越接近1,相关越密切;越接近于0,相关越不密切。
          • 当r=0时,说明X和Y两个变量之间无直线关系。
          • 通常|r|大于0.8时,认为两个变量有很强的线性相关性。
1
2
3
4
5
6
7
8
9
# 协方差
# 两组数值中每对变量的偏差乘积的平均值

df.cov()
df[0].cov(df[1]) # 第0列 和 第1列的协方差

# 相关系数 = X与Y的协方差 / (X的标准差 * Y的标准差)
df.corr() # 所有属性相关性系数
df.corrwith(df[2]) # 单一属性相关性系数

协方差: Cov(X,Y)=1n(XiX)(YiY)n1Cov(X,Y) = \frac{\sum\limits_1^n(X_i - \overline{X})(Y_i - \overline{Y})}{n-1}

相关性系数:r(X,Y)=Cov(X,Y)Var[X]Var[Y]r(X,Y) = \frac{Cov(X,Y)}{\sqrt{Var[X]*Var[Y]}}

九、 数据分组聚合

数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

分组

数据聚合处理:

  • 分组:先把数据分为几组
  • 用函数处理:为不同组的数据应用不同的函数以转换数据
  • 合并:把不同组得到的结果合并起来

数据分类处理的核心: groupby()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建DataFrame
df = pd.DataFrame(
{
'color': ['green', 'green', 'yellow', 'blue', 'blue', 'yellow', 'yellow'],
'price': [4, 5, 3, 2, 7, 8, 9]
}
)
df

# 使用.groups属性查看各行的分组情况:
# 根据color进行分组
df.groupby(by='color')
df.groupby(by='color').groups

# 分组 + 聚合
df.groupby(by='color').sum()
分组聚合练习:

假设菜市场张大妈在卖菜,有以下属性:

  • 菜品(item):萝卜,白菜,辣椒,冬瓜

  • 颜色(color):白,青,红

  • 重量(weight)

  • 价格(price)

  1. 要求以属性作为列索引,新建一个ddd
  2. 对ddd进行聚合操作,求出颜色为白色的价格总和
  3. 对ddd进行聚合操作,求出萝卜的所有重量以及平均价格
  4. 使用merge合并总重量及平均价格
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ddd = pd.DataFrame(
data={
"item": ["萝卜","白菜","辣椒","冬瓜","萝卜","白菜","辣椒","冬瓜"],
'color':["白","青","红","白","青","红","白","青"],
'weight': [10,20,10,10,30,40,50,60],
'price': [0.99, 1.99, 2.99, 3.99, 4, 5, 6,7]
}
)
ddd

# 2. 对ddd进行聚合操作,求出颜色为白色的价格总和
ddd.groupby('color')['price'].sum() # Series
ddd.groupby('color')[['price']].sum() # DataFrame
ddd.groupby('color')[['price']].sum() .loc[['白']]

# 3. 对ddd进行聚合操作,求出萝卜的所有重量以及平均价格
df1 = ddd.groupby('item')[['weight']].sum()
df2= ddd.groupby('item')[['price']].mean()

# 4.使用merge合并总重量及平均价格
# display(df1, df2)
df1.merge(df2, left_index=True, right_index=True)

十、Pandas加载数据

csv数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
data = np.random.randint(0,50,size=(10,5))
df = pd.DataFrame(data=data, columns=['Python','Java','Go','C','JS'])


# 保存到csv
df.to_csv('data.csv',
sep=',', # 文本分隔符,默认是逗号
header=True, # 是否保存列索引
# 是否保存行索引,保存行索引,文件被加载时,默认行索引会作为一列
index=True)

# 加载csv数据
pd.read_csv('data.csv',
sep=',', # 默认是逗号
header=[0], # 指定列索引
index_col=0) # 指定行索引

pd.read_table('data.csv', # 和read_csv类似,读取限定分隔符的文本文件
sep=',',
header=[0], # 指定列索引
index_col=0 # 指定行索引
)
excel数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data = np.random.randint(0, 50, size=(10,5))
df = pd.pDataFrame(data=data, columns=['Python','Java','Go','C','JS'])

# 保存到excel文件
df.to_excel('data.xls',
sheet_name='sheet1',# Excel中工作表的名字
header=True, # 是否保存列索引
index=False) # 是否保存行索引

# 读取excel
pd.read_excel('data.xls',
sheet_name=0, # 读取哪一个Excel中工作表,默认第一个, 也可以写工作表名称
header=0, # 使用第一行数据作为列索引
names=list('ABCDE'), # 替换行索引
index_col=1) # 指定行索引,B作为行索引
MySQL数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sqlalchemy import create_engine

data = np.random.randint(0,150,size=(150,3))
df = pd.DataFrame(data=data, columns=['Python','Pandas','PyTorch'])

# 数据库连接
# root: MySQL用户名
# 123456: MySQL密码
# localhost: 本机
# db: 数据库名(提前创建)
conn = create_engine('mysql+pymysql://root:123456@localhost/db')

# 保存到MySQL
df.to_sql('score', # 表名(会自动创建表)
conn, # 数据库连接
index=False, # 是否保存行索引
if_exists='append') # 如果表名存在,追加数据

# 从MySQL中加载数据
pd.read_sql('select * from score', # sql查询语句
conn, # 数据库连接
index_col='Python') # 指定行索引名

十一、Pandas分箱操作

  • 分箱操作就是将连续型数据离散化。
  • 分箱操作分为等距分箱和等频分箱。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data = np.random.randint(0,150,size=(150,3))
df = pd.DataFrame(data=data, columns=['Python','Pandas','PyTorch'])

# 对Python列进行分箱
df.Python.values

# 1、等宽分箱
pd.cut(df.Python, bins=4)

# 指定宽度分箱
pd.cut(df.Python, # 分箱数据
bins=[0, 30, 60, 80, 100], # 分箱断点
right=False, # 左闭右开
labels=['D','C','B','A']) # 分箱后分类标签

# 2、等频分箱
pd.qcut(df.Python, # 分箱数据
q=4, # 4等份
labels=['差', '中', '良', '优']) # 分箱后分类标签

十二、Pandas绘图

  • Series和DataFrame都有一个用于生成各类图表的plot方法
  • Pandas的绘图是基于Matplotlib, 可以快速实现基本图形的绘制,复杂的图形还是需要用Matplotlib

常见可视化图形:

  • 折线图
  • 条形图/柱形图
  • 饼图
  • 散点图
  • 箱型图
  • 面积图
  • 直方图
1、折线图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 折线图
# Series画图
s = pd.Series([100, 200, 300, 200, 150, 400, 250])
s.plot()

# sin曲线:正弦曲线
x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)
s = pd.Series(data=y, index=x)
s.plot()

# DataFrame画图
data = np.random.randint(50, 100, size=(5, 6))
index = ['1st', '2nd', '3th', '4th', '5th']
columns = ['Jeff', 'Jack', 'Rose', 'Lucy', 'Lily', 'Bob']
df = pd.DataFrame(data=data, index=index, columns=columns)
df.plot() # 一列一根线
2、条形图/柱形图
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
32
33
# 条形图/柱形图
df = pd.DataFrame(data=np.random.rand(10,4))
df.plot.bar(stacked=True) # stacked 是否堆叠

# Series画图
# 可以使用plot中的kind属性来绘制不同图形
s = pd.Series(data=[100, 110, 130, 200])
s.index = ['Jeff', "千锋", 'Python', 'Rose']
s.plot(kind='bar') # 柱状图
# 或
s.plot(kind='barh') # 条形图
# kind:
# - 'line' : line plot (default)
# - 'bar' : vertical bar plot
# - 'barh' : horizontal bar plot
# - 'hist' : histogram
# - 'box' : boxplot
# - 'kde' : Kernel Density Estimation plot
# - 'density' : same as 'kde'
# - 'area' : area plot
# - 'pie' : pie plot
# - 'scatter' : scatter plot
# - 'hexbin' : hexbin plot.

# DataFrame画图
data = np.random.randint(0, 100, size=(4, 3))
index = list('ABCD')
columns = ['Python', 'C', 'Java']

df = pd.DataFrame(data=data, index=index, columns=columns)
df.plot(kind='bar')
# 或
df.plot(kind='barh')
3、饼图
1
2
3
4
5
6
7
8
# 饼图
df = pd.DataFrame(data=np.random.rand(4,2),
index=list('ABCD'),
columns=['Python','Java'])

# subplots=True 子图:同时画多个图
# autopct='%.1f%%' 显示占比,保留1位小数
df.plot.pie(subplots=True, figsize=(8,8), autopct='%.1f%%')
4、散点图
  • 散点图是观察两个一维数据数列之间的关系的有效方法,DataFrame对象可用
1
2
3
4
5
6
7
8
9
10
11
# 散点图
data = np.random.normal(size=(1000, 2))
df = pd.DataFrame(data=data, columns=list('AB'))
df.head()

# scatter: 散点图
# x='A' :使用A列作为x轴
# y='B' :使用B列作为y轴
df.plot(kind='scatter', x='A', y='B')
# 或
df.plot.scatter(x='A', y='B') # A和B关系绘制
5、面积图
1
2
3
# 面积图
df = pd.DataFrame(data=np.random.rand(10, 4), columns=list('ABCD'))
df.plot.area(stacked=True) # stacked 是否堆叠
6、箱型图
1
2
3
4
5
# 箱型图
df = pd.DataFrame(data=np.random.rand(10, 5), columns=list('ABCDE'))
df.plot.box()
# 或
df.plot(kind='box')
7、直方图
1
2
3
4
5
6
7
8
9
# 直方图
df = pd.DataFrame({'A': np.random.randn(1000) + 1,
'B': np.random.randn(1000),
'C': np.random.randn(1000) - 1})
df.plot.hist(alpha=0.5) # 带透明度直方图
df.plot.hist(stacked=True) # 堆叠图
# 或
df['A'].plot(kind='hist')
df.plot(kind='hist')