第2章 NumPy入门(2.1-2.2)
根据<<数据科学手册>> Python Data Science Handbook一书整理.
本章将详细介绍NumPy(Numerical Python的简称)提供了高效存储和操作密集数据缓存的借口.在某些方面,NumPy数组和Python内置的列表类型非常相似.但是随着数组在维度上变大,NumPy数组提供了更加高效的存储和数据操作.NumPy数组几乎是整个Python数据科学工具生态系统的核心.因此不管你对数据科学的哪个方面感兴趣,花点时间学习如何有效使用NumPy都是非常值得的.
2.1 理解Python中的数据类型
2.1.5 创建几个数组
import numpy as np
创建一个长度为10的数组, 数组的值都是0
-是zeros, 不是zero
-此函数有啥作用?
np.zeros(10, dtype=int)
创建一个3 * 5的浮点型数组, 数组的值都是1
3 * 5 表示3行*5列, 输入代码是圆括号本身是成对出现的, 如果手动添加或者剪切, 可能会导致错误
np.ones((3,5),dtype=int)
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
创建一个3 * 5的浮点型数组, 数组的值都是3.14
np.full((3,5), 3.14)
array([[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14]])
zeros,ones,full都是np下的函数, 可以创建数组.
-第一个参数告诉数组是多长, 或者是 n*k的数组
-第二个参数,数值类型或者数值
np.zeros(10,dtype=str)
array(['', '', '', '', '', '', '', '', '', ''], dtype='<U1')
np.ones((3,3),dtype=int)
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
np.full(9,520)
array([520, 520, 520, 520, 520, 520, 520, 520, 520])
创建一个线性序列, 从0开始,20结束,步长2
-和内置的range()函数类似
np.arange(0,20,2)
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
创建一个5个元素的数组,这5个数均匀分配到0-1中
-分位数吗?
np.linspace(0,1,5)
array([0. , 0.25, 0.5 , 0.75, 1. ])
np.linspace(4,20,5)
array([ 4., 8., 12., 16., 20.]
创建一个3*3,在0-1均匀分布的随机数组成的数组
-重点是0-1
-均匀分布是什么意思
np.random.random((3,3))
array([[0.39362852, 0.25206974, 0.88385296],
[0.36547614, 0.34461809, 0.7989048 ],
[0.7369659 , 0.21725593, 0.92850852]])
np.random.random((3*3))
array([0.28620252, 0.18814101, 0.51808316, 0.09341987, 0.78624051,
0.89402738, 0.23804843, 0.04750264, 0.99956259])
np.random.random(5)
array([0.76369557, 0.88767111, 0.93486428, 0.54337144, 0.60357903])
创建一个3*3的,均值为0,标准差为1的
-正太分布数组
np.random.normal(0,1,(3,3))
array([[ 0.90030434, -1.50711765, 0.97764385],
[-0.31173987, -0.84110574, -0.10047986],
[-0.43478952, 1.50298937, 0.73763183]])
np.random.normal(1.5,0.4,100) #生成均值为1.5,标准差为0.4的100个数字.怎么只显示2位小数
array([1.22261068, 1.58441532, 1.88802132, 0.61486983, 1.87470827,
2.25946452, 1.03590926, 1.33094771, 1.4062705 , 1.11332783,
1.40300437, 1.56448717, 1.84108864, 1.889423 , 0.77694291,
0.68180117, 1.30913434, 1.86453287, 1.47528384, 1.57611792,
1.18340949, 1.52063669, 1.59611354, 1.42870295, 1.74599812,
0.87469452, 0.74602807, 1.12764331, 1.25820621, 1.7901757 ,
1.63144372, 1.53547336, 1.69190459, 1.56495873, 1.92058924,
1.32189662, 1.81971028, 1.46019658, 2.35699722, 1.96548058,
2.65711447, 0.89155833, 1.90166715, 1.88020944, 1.49726831,
1.55377297, 1.25409672, 0.94901106, 0.94586283, 1.67326062,
1.37021414, 1.63778177, 1.61532023, 1.01930684, 1.73838839,
2.39846604, 1.1897899 , 0.98619697, 1.41209562, 1.66616348,
1.67276465, 1.6177355 , 1.17221527, 1.81797366, 1.71753876,
1.59004372, 2.19224441, 1.54545624, 1.62140601, 2.05344465,
1.64692645, 1.51883407, 1.83548018, 1.29491494, 1.71556491,
1.04304926, 1.04311419, 2.25142503, 1.65532576, 1.25867277,
0.98532785, 0.76105179, 0.7609183 , 1.84616896, 1.95658462,
2.37700902, 1.62810267, 1.62762617, 1.66713729, 1.87285054,
1.88304677, 1.32029194, 1.2275771 , 1.38059868, 0.73470536,
2.19813629, 1.96004672, 1.98630112, 1.74666125, 1.18260392])
创建一个3*3的,0-10区间的随机数组成的数组
np.random.randint(0,10,(3,3))
array([4, 3, 4, 4, 8, 4])
np.random.randint(90,100,(2,2))
array([[94, 90],
[92, 99]])
创建一个3*3的单位矩阵
np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
创建一个由3个整数组成的未初始化的数组
-数组的值是内存空间的任意值?
np.empty(3)
array([1., 1., 1.])
2.1.6 NumPy中标准数据类型
NumPy数组包含同一类型的值. NumPy是在C语言基础上开发的.
在构建数组时,可以用一个字符串参数指定数据类型
-NumPy中数据类型比Python中数据类型多,不加引号可能会报错
np.zeros(10, dtype='int16')
np.zeros(10,dtype=np.int16)
np.zeros(10,dtype=int)
np.zeros(10,dtype=int16) # int16是NumPy中数据类型,报错
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-38-ff102d8e3e0a> in <module>()
2 np.zeros(10,dtype=np.int16)
3 np.zeros(10,dtype=int)
----> 4 np.zeros(10,dtype=int16)
NameError: name 'int16' is not defined
NumPy中数据类型
-bool_ : 布尔值
-int_ : 默认整型
-intc : 同C语言中int相同
-intp : 用作索引的整型
-int8 : 字节,范围从-128到127
-int16 :
-int32 :
-int64 :
-uint8 :
-uint16 :
-uint32 :
-uint64 :
-float_ :
-float16 :
-loat32 :
-float64 :
-complex_ :
-complex64 :
-complex128 :
2.2 NumPy数组基础
Python中数据操作几乎等同于NumPy中数组操作.Pandas工具也是构建在NumPy数组的基础之上的.
-数组的属性(大小,形状,存储大小,数据类型)
-数组的索引(获取或者设置各个元素的值)
-数组的切分
-数组的变形
-数组的拼接与分裂
2.2.1 数组的属性
import numpy as np
np.random.seed(0) #设置随机数种子值,
x1 = np.random.randint(10,size=6) # 还可以写成 np.random.randint(0,10,6)
np.random.randint(0,10,6)
x2 = np.random.randint(10,size=(3,4))
x3 = np.random.randint(10,size=(3,4,5))
print(x3)
[[[4 3 0 3 5]
[0 2 3 8 1]
[3 3 3 7 0]
[1 9 9 0 4]]
[[7 3 2 7 2]
[0 0 4 5 5]
[6 8 4 1 4]
[9 8 1 1 7]]
[[9 9 3 6 7]
[2 0 3 5 9]
[4 4 6 4 4]
[3 4 4 8 4]]]
每个数组都有数组的ndim(数组的维度),shape(数组每个维度的大小),size(数组的总大小)和dtype(数组的数据类型)
其他: itemsize(每个元素字节大小), nbytes(总字节大小). 什么东东?
print('x3的维度是:',x3.ndim)
print('x3的每个维度大小是:',x3.shape) # 每个维度的大小是从外向内数?
print('x3的总大小是:',x3.size)
print('x3的数据类型是:',x3.dtype)
print('x3的字节大小是:',x3.itemsize,"bytes")
print('x3的总字节大小是:',x3.nbytes,'bytes')
x3的维度是: 3
x3的每个维度大小是: (3, 4, 5)
x3的总大小是: 60
x3的数据类型是: int32
x3的字节大小是: 4 bytes
x3的总字节大小是: 240 bytes
2.2.2 数组的索引: 获取单个元素
一维数组
np.random.seed(0)
x1 = np.random.randint(10,size=6) # 这样生成的6位随机数居然和书本上的一样
print(x1)
print(x1[0]) #第一位
print(x1[4])
print(x1[-1]) #最后一位
[5 0 3 3 7 9]
5
7
9
二维数组
print(x2)
print(x2[0,0])
print(x2[2,2])
print(x2[2,-1])
[[8 8 1 6]
[7 7 8 1]
[5 9 8 9]]
8
8
9
修改某个值数据. 数组是有数据类型的, 如果加入的数值类型不一样, 会自动变换
x2[0,0] = "100" #如果是字符型字符串则报错
x2[2,2] = 3.14
x2
array([[100, 8, 1, 6],
[ 7, 7, 8, 1],
[ 5, 9, 3, 9]])
三维数组
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
print(x3[0,0,0])
print(x3[1,2,1]) # 二维 ,第3行,第2列
x3[1,2,1]=1000
print(x3)
4
8
[[[ 4 3 0 3 5]
[ 0 2 3 8 1]
[ 3 3 3 7 0]
[ 1 9 9 0 4]]
[[ 7 3 2 7 2]
[ 0 0 4 5 5]
[ 6 1000 4 1 4]
[ 9 8 1 1 7]]
[[ 9 9 3 6 7]
[ 2 0 3 5 9]
[ 4 4 6 4 4]
[ 3 4 4 8 4]]]
2.2.3 数组的切片: 获取子数组
NumPy中切片语法和Python中列表的切片语法相同, 用冒号(:)分开.
x[start:stop:step]
如果以上三个参数都没有设置,则使用默认值 start=0, stop=维度的大小, 和step=1
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[:5] # 前5个
array([0, 1, 2, 3, 4])
x[5:]
array([5, 6, 7, 8, 9])
x[4:7]
array([4, 5, 6])
每隔一个数字
x[::2]
array([0, 2, 4, 6, 8])
x[1::2]
array([1, 3, 5, 7, 9])
一维数组逆序
x[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
二维数组
x2
array([[8, 8, 1, 6],
[7, 7, 8, 1],
[5, 9, 8, 9]])
x2[:2,:3]
array([[100, 8, 1],
[ 7, 7, 8]])
看见冒号(?,表示数组切片
x2[:,::2] # 所有行, 每隔一列
array([[8, 1],
[7, 8],
[5, 8]])
x2[::-1,::-1] # 颠倒顺序
array([[9, 8, 9, 5],
[1, 8, 7, 7],
[6, 1, 8, 8]])
三维数组
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
x3[::-1,::-1,::-1]
array([[[ 4, 8, 4, 4, 3],
[ 4, 4, 6, 4, 4],
[ 9, 5, 3, 0, 2],
[ 7, 6, 3, 9, 9]],
[[ 7, 1, 1, 8, 9],
[ 4, 1, 4, 1000, 6],
[ 5, 5, 4, 0, 0],
[ 2, 7, 2, 3, 7]],
[[ 4, 0, 9, 9, 1],
[ 0, 7, 3, 3, 3],
[ 1, 8, 3, 2, 0],
[ 5, 3, 0, 3, 4]]])
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
x3[::,0,::] # 第一维度全选, 第二维度选第1行,第三维度全选
array([[4, 3, 0, 3, 5],
[7, 3, 2, 7, 2],
[9, 9, 3, 6, 7]])
x3[::2,::2,::2]
array([[[4, 0, 5],
[3, 3, 0]],
[[9, 3, 7],
[4, 6, 4]]])
获取数组的单行或者单列
x2
array([[8, 8, 1, 6],
[7, 7, 8, 1],
[5, 9, 8, 9]])
x2[:,0] # 第1列
array([8, 7, 5])
x2[:,2] # 第3列
array([1, 8, 8])
x2[0,:] # 第1行
x2[0] #获取行时简写表示方法, 对列不适用
array([8, 8, 1, 6])
x2[1,:]
array([7, 7, 8, 1])
NumPy数组切片和Python列表切片的不同之处: NumPy数组切片返回的是数组的试图,而不是数值数据的副本. 在Pythong列表中,切片是值得副本.
-副本 : 可以理解为复制了一份和原来的不一样了.
-视图 : 可以理解为超链接,修改还是改的原来的路径(文件)
-好处是,当处理大量的数据集时, 只需要修改切片即可修改原数据
print(x2)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
从中抽取一个2*2的子数组
x2_sub = x2[::2,::2]
print(x2_sub)
[[100 1]
[ 5 8]]
x2_sub[0,0] = 100
x2
array([[100, 8, 1, 6],
[ 7, 7, 8, 1],
[ 5, 9, 8, 9]])
数组切片只能形成数组的视图, 那如果要新建副本,用copy()方法
x2_sub = x2[::2,::2].copy()
print(x2)
print('*'*20)
print(x2_sub)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
********************
[[100 1]
[ 5 8]]
x2_sub[1,1] = 99
print(x2)
print("*"*20)
print(x2_sub)
print('*'*20)
print(x2)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
********************
[[100 1]
[ 5 99]]
********************
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
2.2.4 数组的变形
最常用的方法是用reshape()方法实现.
例如:期望将数字1-9,放入3*3的矩阵中,可采用如下方法:
-reshape() 数组的属性
-newaxis() np的属性
np.arange(1,10).reshape(3*3) #错
np.arange(1,10).reshape(3,3)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
原始数组的大小必须和变形后数组大小一致. reshape返回原数组的一个视图
大小不一致的情况
a1 = ([1,2,3,4,5,6,7,8])
np.a1.reshape(3,3) # 表示方法错. np没有a1属性
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-48-75353fe7632b> in <module>()
1 a1 = ([1,2,3,4,5,6,7,8,9])
----> 2 np.a1.reshape(3,3)
AttributeError: module 'numpy' has no attribute 'a1'
a1 = array([1,2,3,4,5,6,7,8]) # 数组array 前面必须带np
a1.reshape((3,3))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-52-202d01b8f390> in <module>()
----> 1 a1 = array([1,2,3,4,5,6,7,8])
2 a1.reshape((3,3)) # 表示方法错
NameError: name 'array' is not defined
a1 = np.array([1,2,3,4,5,6,7,8,9])
a1.reshape((3,3))
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
np.array([1,2,3,4,5,6,7,8]).reshape(3,3) # 少了不行
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-49-1a37bef6142d> in <module>()
----> 1 np.array([1,2,3,4,5,6,7,8]).reshape(3,3)
ValueError: cannot reshape array of size 8 into shape (3,3)
np.array([1,2,3,4,5,6,7,8,9,10]).reshape(3,3) # 多了也不行
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-50-0a4d36c4b6a6> in <module>()
----> 1 np.array([1,2,3,4,5,6,7,8,9,10]).reshape(3,3)
ValueError: cannot reshape array of size 10 into shape (3,3)
x = np.array([1,2,3]) #一维数组
x.reshape(1,3) # 变成1行3列的二维数组
array([[1, 2, 3]])
x[np.newaxis,:]
array([[1, 2, 3]])
x.reshape(3,1)
array([[1],
[2],
[3]])
x[:,np.newaxis] # newaxis 属于关键字
array([[1],
[2],
[3]])
2.2.5 数组的拼接和分裂
多个数组合并成一个或者一个数组拆分成多个
-np.concatenate():将数组元组和数组列表作为第一个参数
-np.vstack()
-np.hstack()
x = np.array([1,2,3])
y = np.array([3,2,1])
x_y = np.concatenate([x,y])
print(x_y)
print(x_y.ndim)
[1 2 3 3 2 1]
1
z = [99,99,99] # 不用 np.array([99,99,99])
np.concatenate([x,y,z])
array([ 1, 2, 3, 3, 2, 1, 99, 99, 99])
x1 = [99,99,99] # 这是一个列表
x2 = np.array([99,99,99])
print(x1 == x2)
print(x1 is x2)
[ True True True]
False
二维数组的拼接
#沿着第一个轴拼接? 沿着第一个轴拼接,为什么是纵向
import numpy as np
x1 = np.array([[1,2,3],
[4,5,6]])
np.concatenate([x1,x1]) # 中括号不能少
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
# 沿着第二个轴拼接, 沿着水平方向
np.concatenate([x1,x1],axis=1) # 注意中括号和圆括号的位置
array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
沿着固定维度处理数组时, 使用
np.vstack(垂直栈)
np.hstack(水平栈)函数更简洁 ??
x1 = np.array([1,2,3])
x2 = np.array([[9,8,7],
[2,5,9]])
#垂直栈数组
np.vstack([x1,x2])
array([[1, 2, 3],
[9, 8, 7],
[2, 5, 9]])
#水平栈数组
x3 = np.array([[99],
[99]])
np.hstack([x3,x2])
array([[99, 9, 8, 7],
[99, 2, 5, 9]])
数组的分裂
-np.split()
-np.hsplit()
-np.vsplit()
x = [1,2,3,99,99,3,2,1] # 这不是一个序列码
x1,x2,x3 = np.split(x,(3,5)) # 注意 x 和[3,5]的位置与括号,也可以用(3,5)
print(x1,x2,x3)
[1 2 3] [99 99] [3 2 1]
x1 = np.arange(16).reshape(4,4)
up,low = np.vsplit(x1,2) # [2]也可以写成(2),也可以不加括号 ?
print(up)
print('*'*20)
print(low)
print('*'*20)
print(x1)
[[0 1 2 3]
[4 5 6 7]]
********************
[[ 8 9 10 11]
[12 13 14 15]]
********************
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
left,right = np.hsplit(x1,[2]) # 为什么此处的中括号必须
print(left)
print('*'*20)
print(right)
[1 2]
********************
[3]