numpy是numerical Python的简称,是Python科学计算的核心包,其强大的科学计算能力在很多高级包中得到应用,pandas就是基于numpy的一种工具包。
numpy主要特点:
- 使用向量化操作以简化数据处理,包括取子集,过滤,和变形等
- 高效的数据总结,排序功能
# 导入numpy包
import numpy as np # 简写为np
创建numpy数组
numpy的一个重要对象object是ndarray 也称numpy数组
- ndarray是multidimensional array 的缩写 中文称多(multi)维(dimensional)数组(array)
- 数组可以存储大量数据并在其进行数学运算,我们可以使用数组在一块数据上进行操作从而避免使用循环来操作单个元素
1-1 一维数组
# 从列表中创建数组,使用np.array函数创建
value = [1,2,3]
arr1d = np.array(value)
arr1d
array([1, 2, 3])
# 查看数据类型
type(arr1d)
numpy.ndarray
# 查看维度,返回1 说明是1维数组
arr1d.ndim
1
1-2 二维数组
# 从二维列表中创建二维数组
value = [[1,2,3],[4,5,6]]
arr2d = np.array(value)
arr2d
array([[1, 2, 3],
[4, 5, 6]])
二维数组 类似一个矩阵
- 0轴axis=0,是列,也就是垂直方向
- 1轴axis=1,是行,也就是水平方向
- 矩阵对于数据分析来说,是一个重要概念,一般用列代表观测对象的各种属性特征,用特征来记录每一个观测对象的一组测试量数据
# 查看维度
arr2d.ndim
2
# 使用shape来查看行数和列数
# arr2d是一个2行三列的二维素组,
arr2d.shape#注意结果存储在一个元组里
(2, 3)
1-3 其他快速创建数组的函数
- 一维数组
# 创建空数组,返回的是一堆垃圾值
np.empty(10)
array([ 2.31584178e+077, -2.32034991e+077, 5.51039867e-310,
1.38549349e-309, 4.71889424e-310, 5.55092879e-310,
4.78170532e-310, 4.73926540e-310, 2.54110129e-292,
6.95335581e-309])
# 创建全为0的数组
np.zeros(5)
array([ 0., 0., 0., 0., 0.])
# 创建元素都为1的数组
np.ones(5)
array([ 1., 1., 1., 1., 1.])
# 创建序列数组
# np.arange类似于Python的range函数,是它的数组版
# 数组元素从0到9
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 10以内的偶数组成的数组
np.arange(0,10,2)#从0到10不包含10步长为2
array([0, 2, 4, 6, 8])
# 创建01之间的随机数
np.random.rand(5)#随机5个 随机指定形状的数组 如果是 3,2就是随机3行2列
array([ 0.99220327, 0.44805664, 0.69512126, 0.42698234, 0.49119111])
# 创建指定范围内的随机整数
np.random.randint(1,10,size=8)#size值得也是形状,可以是整数或元组
array([6, 4, 2, 4, 4, 6, 6, 2])
- 二维数组
np.empty((3,3))
array([[ 2.31584178e+077, 1.73059603e-077, 2.37663529e-312],
[ 2.56761491e-312, 8.48798317e-313, 9.33678148e-313],
[ 8.70018275e-313, 2.02566915e-322, 0.00000000e+000]])
np.zeros((2,3))
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
np.ones((2,3))
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
np.random.rand(3,5)
array([[ 0.72979818, 0.77293449, 0.90877323, 0.75618689, 0.09780505],
[ 0.64524273, 0.28629676, 0.62415151, 0.20635084, 0.89698474],
[ 0.62485541, 0.6831554 , 0.86562018, 0.27209155, 0.05378966]])
np.random.randint(1,10,size=(3,5))
array([[1, 7, 2, 3, 7],
[9, 9, 3, 5, 6],
[6, 5, 4, 5, 2]])
2 索引和切片
- 选取数组中的元素或者是数据的子集
- 使用[]运算符对数据进行切片和索引操作
2-1 一维数组
- 一维数组的索引和切片和Python的list差不多
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 索引
arr[3]
3
# 切片
arr[3:7]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
注意 数组切片是原始数组的一个视图表达,也就是说 数据不会被复制,接下来对切片数据的任何修改都会影响到原有的数组
arr2 = arr[3:7]
arr2[0] = 13
arr # arr的元素也被改变了
array([ 0, 1, 2, 13, 4, 5, 6, 7, 8, 9])
** 如果需要对数组的切片进行复制,需要使用copy方法**
arr = np.arange(10)
arr3 = arr[3:7].copy()
arr3[0] = 13
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2-2 二维数组
# 用一维数组来生成二维数组
# 修改一维数组的shape值
mat = np.arange(1,17)
mat.shape = (4,4)
mat
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
- 获取二维数组的某一行
mat[0]
array([1, 2, 3, 4])
- 二维数组的切片 是沿着行方向的
mat[1:3]#第一行到第三行 不包含第三行
array([[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
# 等同于 放入一个列表
mat[[1,2]]#查看第一行和第二行
array([[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
- 查看某个元素,也有两种方式
#先获取第一行再查找第三列
mat[1][3]
8
#用逗号来分隔行索引和列索引
mat[1,3]
8
- 切片和索引的混用
方括号第一个参数指定要取的行的位置,第二个参数指定要取的列的位置,中间使用逗号隔开
# 获取第0行到第2行,的第一列数据
mat[0:3,1]
array([ 2, 6, 10])
# 可以同时对行和列做切片
# 取第一行到最后一行,第2列到第三列
mat[2:,2:]
array([[11, 12],
[15, 16]])
3 读取文件
# 读取红酒品质数据,源数据以逗号分隔,并且跳过第一行
# 数据文件中第一行是字段名,属于字符串类型,而numpy数组的所有元素必须是一致的数据类型,所以需要跳过第一行,否则会出错。
# np.genfromtxt从文本文件加载数据
wine_data = np.genfromtxt('winequality-red.csv',delimiter=';',skip_header=1)
wine_data
array([[ 7.4 , 0.7 , 0. , ..., 0.56 , 9.4 , 5. ],
[ 7.8 , 0.88 , 0. , ..., 0.68 , 9.8 , 5. ],
[ 7.8 , 0.76 , 0.04 , ..., 0.65 , 9.8 , 5. ],
...,
[ 6.3 , 0.51 , 0.13 , ..., 0.75 , 11. , 6. ],
[ 5.9 , 0.645, 0.12 , ..., 0.71 , 10.2 , 5. ],
[ 6. , 0.31 , 0.47 , ..., 0.66 , 11. , 6. ]])
# 查看数组形状
wine_data.shape
(1599, 12)
wine_data.ndim
2
# 查看数据类型
wine_data.dtype
dtype('float64')
# 取前10行数据中的8,10,11列,分别对应红酒的PH值、酒精度、质量评分这三类属性
# 为简单起见,后续将使用这组数据进行分析示例
wine = wine_data[:10,[8,10,11]]
wine
array([[ 3.51, 9.4 , 5. ],
[ 3.2 , 9.8 , 5. ],
[ 3.26, 9.8 , 5. ],
[ 3.16, 9.8 , 6. ],
[ 3.51, 9.4 , 5. ],
[ 3.51, 9.4 , 5. ],
[ 3.3 , 9.4 , 5. ],
[ 3.39, 10. , 7. ],
[ 3.36, 9.5 , 7. ],
[ 3.35, 10.5 , 5. ]])
4 布尔型索引
- 之前的切片索引方法是通过指定行或列的位置来取一个数组的一部分
- 顾名思义,布尔索引是通过一个布尔型数组来确定所需要的行或列的位置
- 当行或者列位置对应的布尔索引为true的时候,我们会保留这个行或列,反之,当对应的值为false则不选取
# 获取评分大于5的红酒数据 第二列代表质量评分
wine[:,2]>5
array([False, False, False, True, False, False, False, True, True, False], dtype=bool)
wine[wine[:,2]>5]
array([[ 3.16, 9.8 , 6. ],
[ 3.39, 10. , 7. ],
[ 3.36, 9.5 , 7. ]])
# 获取评分大于5且酒精度大于等于10的红酒数据
mask = (wine[:,2] > 5) & (wine[:,1] >= 10)
mask
array([False, False, False, False, False, False, False, True, False, False], dtype=bool)
wine[mask]
array([[ 3.39, 10. , 7. ]])
5 数组的运算
5-1 数组与单个数之间的运算
每个元素都参与运算
mat/2
array([[ 0.5, 1. , 1.5, 2. ],
[ 2.5, 3. , 3.5, 4. ],
[ 4.5, 5. , 5.5, 6. ],
[ 6.5, 7. , 7.5, 8. ]])
mat ** 2
array([[ 1, 4, 9, 16],
[ 25, 36, 49, 64],
[ 81, 100, 121, 144],
[169, 196, 225, 256]])
# 将红酒评分数据转换成百分制,即原评分乘以10
score = wine[:,2]
score
array([ 5., 5., 5., 6., 5., 5., 5., 7., 7., 5.])
score * 10
array([ 50., 50., 50., 60., 50., 50., 50., 70., 70., 50.])
- numpy数组的任何数学运算,都会将运算运用到元素级别
- 这样的矢量化运算是numpy数组的优势,Python列表要实现这一操作就需要编写循环
# 将上述评分数据转化为Python列表
score_list = list(score)
score_list
[5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0]
# 直接乘以10 是把列表复制了10遍
print(score_list * 10)
[5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0, 5.0, 5.0, 5.0, 6.0, 5.0, 5.0, 5.0, 7.0, 7.0, 5.0]
# 方法1 使用循环将每一个元素乘以10
new_list = []#初始化空数组
# 循环取得每个元素乘以10放入新的数组
for s in score_list:
new_list.append(s * 10)
print (new_list)
[50.0, 50.0, 50.0, 60.0, 50.0, 50.0, 50.0, 70.0, 70.0, 50.0]
# 方法2 列表解析
[s * 10 for s in score_list]
[50.0, 50.0, 50.0, 60.0, 50.0, 50.0, 50.0, 70.0, 70.0, 50.0]
5-2 数组与数组之间的运算
- 两个行列数相符的数列可以进行运算
- 运算操作将应用到数组中对应的每一个元素
mat + mat
array([[ 2, 4, 6, 8],
[10, 12, 14, 16],
[18, 20, 22, 24],
[26, 28, 30, 32]])
np.add(mat,mat)
array([[ 2, 4, 6, 8],
[10, 12, 14, 16],
[18, 20, 22, 24],
[26, 28, 30, 32]])
# 两个数组相乘,也可以使用np。multiply函数实现
# 对应元素之间的乘法,不同于线性代数中的矩阵相乘
# 对应的每一个元素进行相乘
mat*mat
array([[ 1, 4, 9, 16],
[ 25, 36, 49, 64],
[ 81, 100, 121, 144],
[169, 196, 225, 256]])
# 将每一行的红酒数据与第0行的数据进行比较,即计算与第0行数据的差值
# 注意,这里两个数组的大小不同
# 大小不同的数组之间的运算 叫做广播 所谓广播就是shape不一致时,通过广播调整数组使得shape一样,满足规则,则可以运算,否则就出错 。
wine-wine[0]
array([[ 0. , 0. , 0. ],
[-0.31, 0.4 , 0. ],
[-0.25, 0.4 , 0. ],
[-0.35, 0.4 , 1. ],
[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ],
[-0.21, 0. , 0. ],
[-0.12, 0.6 , 2. ],
[-0.15, 0.1 , 2. ],
[-0.16, 1.1 , 0. ]])
6 常用函数举例
wine
array([[ 3.51, 9.4 , 5. ],
[ 3.2 , 9.8 , 5. ],
[ 3.26, 9.8 , 5. ],
[ 3.16, 9.8 , 6. ],
[ 3.51, 9.4 , 5. ],
[ 3.51, 9.4 , 5. ],
[ 3.3 , 9.4 , 5. ],
[ 3.39, 10. , 7. ],
[ 3.36, 9.5 , 7. ],
[ 3.35, 10.5 , 5. ]])
# 计算红酒数据每一个属性的平均值,即每一列数据的平均值
# 使用np.sum对所有数据求和
np.sum(wine)
185.55000000000001
# 使用axis参数来设置求和方式,axis=0表示对列求和 axis=1表示对行求和
np.sum(wine,axis=0)
array([ 33.55, 97. , 55. ])
# 每列的总数除以行数,得到每列的均值
np.sum(wine,axis=0)/len(wine)
array([ 3.355, 9.7 , 5.5 ])
# 直接使用np.mean函数,要记得设置axis参数
np.mean(wine,axis=0)
array([ 3.355, 9.7 , 5.5 ])
# 红酒数据每一项属性中的最大和最小值
np.max(wine,axis=0)
array([ 3.51, 10.5 , 7. ])
np.min(wine,axis=0)
array([ 3.16, 9.4 , 5. ])
- numpy数组和Python列表相比 效率更高
数组和列表都有max函数可以找到最大值,我们来看下他们的运算速度
# 先随机生成10000个随机数,然后找他们的最大值
random_arr = np.random.rand(10000)
random_list = list(random_arr)
# 直接使用Python的max函数
%timeit max(random_list)
331 µs ± 5.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# 使用numpy的max函数
%timeit np.max(random_arr)
9.64 µs ± 221 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 将红酒数据中的ph值进行排序
np.sort(wine[:,0])
array([ 3.16, 3.2 , 3.26, 3.3 , 3.35, 3.36, 3.39, 3.51, 3.51, 3.51])
# 找出红酒数据中都有哪几种评分,即求评分数据中不重复的打分项
np.unique(wine[:,2])
array([ 5., 6., 7.])
# 生成一组新的数据,如果评分大于5,其值为good,如果小于5,其值为bad
# 1.定义一个空的列表,用来存放数据
# 2.判断每一个数据,将good或bad添加到新的列表中
new = list()
for s in wine[:,2]:
if s > 5:
new.append('good')
else:
new.append('bad')
new
['bad', 'bad', 'bad', 'good', 'bad', 'bad', 'bad', 'good', 'good', 'bad']
# 使用列表解析
[('good' if s > 5 else 'bad') for s in wine[:,2]]
['bad', 'bad', 'bad', 'good', 'bad', 'bad', 'bad', 'good', 'good', 'bad']
# 使用np.where 根据条件 取值
np.where(wine[:,2]>5,'good','bad')
array(['bad', 'bad', 'bad', 'good', 'bad', 'bad', 'bad', 'good', 'good',
'bad'],
dtype='<U4')
# 案例
names = np.array(["Xiao Ming","Xiao Zhang","Xiao Gang","Xiao Hong","Xiao Pang","Xiao Wu","Xiao Dai",
"Xiao Qian","Xiao Fan","Xiao Wang"])
scores = np.array([ 91, 68, 84, 55, 95, 81, 67, 82, 86, 78])
# 找出不及格的学生姓名
names[scores<=60]
array(['Xiao Hong'],
dtype='<U10')
# 找出最高分、最低分,平均分数
maxcount = np.max(scores)
mincount = np.min(scores)
meancount = np.mean(scores)
print(maxcount,mincount,meancount)
95 55 78.7
# 将数值成绩转化成字母成绩,大于等于90分为A, 70-89分为B,小于70分为C
np.where(scores>=90,'A',np.where(scores>=70,'B',"C"))
array(['A', 'C', 'B', 'C', 'A', 'B', 'C', 'B', 'B', 'B'],
dtype='<U1')
[ 'A' if score >= 90 else 'b' if score >= 70 else 'C' for score in scores]
['A', 'C', 'b', 'C', 'A', 'b', 'C', 'b', 'b', 'b']