Numpy学习笔记

本文详细介绍了NumPy的基础知识,包括数组创建、数据类型、数组操作、数组形状变换、数组拷贝、算术运算、广播机制、数组拼接、切片、条件逻辑操作以及Numpy与本地数据的读写。文中还探讨了NaN和inf的处理,并展示了随机数生成和常用函数的使用,最后通过例子展示了如何处理数据中的缺失值。
摘要由CSDN通过智能技术生成

1 Numpy介绍

内建数据结构:list --> Array模块 --> Numpy基础包

1.1 Numpy

Numpy(Numerical Python)是目前Python数值计算中最为重要的基础包。大多数计算包都提供了基于Numpy的科学函数功能,将Numpy的数组对象作为数据交换的通用语。

1.2 Numpy特点

  • 提供高效多维数组
  • 提供了基于数组的便捷算术操作以及广播机制
  • 对数据进行快速的矩阵计算
  • 对硬盘中数组数据进行读写操作

官网:https://numpy.org/devdocs/user/quickstart.html

2 Numpy基本操作

2.1 创建数组

创建N维数组对象:生成数组最简单的方式就是使用array函数。array函数接收任何的序列型(sequence)对象,生成一个新的包含传递数据的Numpy数组。

  • numpy.array(object)
import numpy

li = [1,2,3,4]
arr = numpy.array(li)
print(type(arr),arr)
  • numpy.arange([start,] stop[, step,], dtype=None)
import numpy

# 左开右闭,类似与range()函数
arr = numpy.arange(start=1,stop=5)
print(type(arr),arr)    # <class 'numpy.ndarray'> [1 2 3 4]

注意

  • ndarray数组是一个通用的多维同类数据容器,意味着数组里面每一个元素均为相同类型。(同质性)

2.2 数组的数据类型

Numpy数据类型

类型类型代码描述
int8,uint8i1,u1有符号和无符号的8数位整数
int16,uint16i2,u2有符号和无符号的16数位整数
int32,uint32i4,u4有符号和无符号的32数位整数
int64,uint64i8,u8有符号和无符号的64数位整数
float16f2半精度浮点数
float32f4标准单精度浮点数
float64f8标准双精度浮点数
bool布尔值,存储True或False
string_SASCII字符串类型,eg:‘S10’
unicode_UUnicode类型,eg:‘U10’

2.2.1 查看数组数据类型

  • arr.dtype # 查看数组的数据类型
import numpy

arr = numpy.arrange(1,5)
print(arr.dtype)    # 类型为int32

arr1 = numpy.array([1,2,3,4.5])
print(arr1.dtype)   # float64

arr2 = numpy.array([True,1,2,'www',5.0])
print(arr2.dtype)   # <U11

注意

  • numpy.array()会自动推断生成数组的数据类型,即会自动转换数据类型

2.2.2 指定数组的数据类型

  • numpy.array(object,dtype=None) # 创建数组时通过dtype直接指定
import numpy

arr = numpy.array([1,2,3],dtype='f8')
print(arr,arr.dtype)    # [1. 2. 3.] float64

arr1 = numpy.array([1,2,3,0],dtype='?')
print(arr1,arr1.dtype)    # [ True  True  True False] bool
  • arr.astype(dtype) # 修改数组数据类型,但并没有改变数组本身的数据
import numpy

arr = numpy.array([1,2,3])
arr = arr.astype(numpy.float32)
print(arr.dtype)    # float32

2.3 数组形状

2.3.1 查看数组维度和形状

  • arr.ndim:查看数组的维度,返回值为整数

  • arr.shape:查看数组的形状,返回值为行列组成的元组

import numpy

arr = numpy.array([1,2,3])
print(arr.ndim)     # 输出结果:1
print(arr.shape)    # 输出结果:(3,)

2.3.2 N-维数组对象

  • 一维

axis 0

123
  • 二维

axis 0–> 0轴:行
axis 1–> 1轴:列

(0,1) --> (行,列)

123
456

注意:如果向array的二维数组传递不对等元素,则子列表会被当成独立的元素,从而变成一维的。

  • 三维

0轴:面或者块(页)

1轴:行

2轴:列

import numpy as np

arr = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
print(arr.shape)    # 结果:(2, 2, 3)
print(arr)
'''
结果:
[[[ 1  2  3]
  [ 4  5  6]]
  
 [[ 7  8  9]
  [10 11 12]]]
'''

注意:如果向array的三维数组传递不对等元素,则子列表会被当成独立的元素,从而变成二维的。

图片是三维的:宽、高、颜色。 声音是四维的。

拓展

from matplotlib import pyplot as plt
# 读取图片数据
img = plt.imread("hsq.jpg")
print(img)
'''
array([[[118,  91,  48],
        [120,  93,  50],
        [122,  95,  52],
        ...,
        [161, 153, 150],
        [162, 154, 151],
        [161, 153, 150]],
       [[118,  91,  48],
        [119,  92,  49],
        [121,  94,  51],
        ...,
        [155, 147, 144],
        [161, 153, 150],
        [171, 163, 160]],
       [[119,  92,  49],
        [120,  93,  50],
        [121,  94,  51],
        ...,
        [161, 153, 151],
        [160, 152, 150],
        [166, 158, 156]],
       ...,
       [[175, 157, 145],
        [171, 153, 141],
        [165, 147, 135],
        ...,
        [208, 205, 200],
        [175, 172, 167],
        [130, 127, 122]],
       [[172, 155, 145],
        [169, 152, 142],
        [164, 146, 136],
        ...,
        [160, 157, 152],
        [109, 106, 101],
        [ 69,  66,  61]],
       [[163, 146, 136],
        [163, 146, 136],
        [161, 143, 133],
        ...,
        [105, 102,  97],
        [ 65,  62,  57],
        [ 57,  54,  49]]], dtype=uint8)
'''

print(img.ndim)
print(img.shape)
'''
3
(220, 288, 3)
'''

plt.imshow(img)

2.4 重塑数组

对应方法不会改变原数组本身

2.4.1 一维转多维

  • arr.reshape(shape,order=‘C’)

参数:shape为数组重塑形状;order表示重塑方向,其中C顺序(行方向)重塑、F顺序(列方向)重塑。

import numpy as np

arr1 = np.arange(6)
print(arr1,arr1.shape)     # [0 1 2 3 4 5]  (6,)

 # 注意重塑后的行列数乘积必须等于原来的行列数乘积,这里 2*3 = 6*1
arr2 = arr1.reshape(2,3)   
print(arr2,'\n',arr2.shape)
'''
结果:
[[0 1 2]
 [3 4 5]]
 (2, 3)
'''
# print(arr1.reshape(-1,3))     # 形状维度可以有一个值为-1,表示维度通过数据进行判断

arr3 = arange(12).reshape(2,2,3)
print(arr3)

2.4.2 多维转一维

  • arr.flatten()
  • arr.ravel()
import numpy

arr = numpy.arange(16).reshape(4,4)
'''
结果:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
'''

arr1 = arr.flatten()   # 扁平化
print(arr1)
'''
结果:
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]
'''

arr2 = arr.ravel()     # 分散化
print(arr2)
'''
结果:
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]
'''

2.4.3 数组转置与换轴

  • arr.transpose():转置
  • arr.T:转置
  • arr.swapaxes():换轴
import numpy as np

arr = np.arange(20).reshape(4,5)
print(arr)
'''
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]
'''

# 转置:可以用arr.transpose() 或者 arr.T
arr1 = arr.transpose()
print(arr1)
'''
[[ 0  5 10 15]
 [ 1  6 11 16]
 [ 2  7 12 17]
 [ 3  8 13 18]
 [ 4  9 14 19]]
'''


# 换轴:arr.swapaxes(axis1,axis2)
arr2 = arr.swapaxes(1,0)        # 把0轴(行)和1轴(列)互换
print(arr2)
'''
[[ 0  5 10 15]
 [ 1  6 11 16]
 [ 2  7 12 17]
 [ 3  8 13 18]
 [ 4  9 14 19]]
'''

2.5 创建数组的其他函数

2.5.1 常用函数汇总

函数名描述
array将输入数据转换为ndarray数组,自动推断数据类型,默认复制所有输入数据
asarray将输入数据转换为ndarray数组,但输入数据已经是ndarray则不再复制
arangepython内建函数range的数组版,返回一个数组
zeros根据给定形状和数据类型生成全0数组。注意:需要传入序列或者整数
ones根据给定形状和数据类型生成全1数组。注意:需要传入序列或者整数
empty根据给定形状和数据类型生成一个没有初始化数值的空数组
full根据给定形状和数据类型生成指定数值的数组
eye构造单位矩阵,可以创建矩形和方形单位矩阵
identity只能创建方形单位矩阵
one_like构造相同形状的全为1的数组

2.5.2 array函数和asarray函数的区别

import numpy as np

# 将列表转为array类型
data = [1,2,3,4]        # list类型
arr1 = np.array(data)
arr2 = np.asarray(data)
print(arr1)     # [1,2,3,4]
print(arr2)     # [1,2,3,4]

# 修改data列表里面的2改为5,arr1和arr2的值都没有受影响
data[1] = 5
print(data)     # [1, 5, 3, 4]
print(arr1)     # [1 2 3 4]
print(arr2)     # [1 2 3 4]

data_2 = np.arange(4)     # ndarray类型
print(data_2)             # [0 1 2 3]
arr3 = np.array(data_2)
arr4 = np.asarray(data_2)

data_2[1] = 5
print(data_2)       # 结果为[0 5 2 3]     数据有改变
print(arr3)         # 结果为[0 1 2 3],不变,说明array函数拷贝了副本,不会受原来的值变动影响
print(arr4)         # 结果为[0 5 2 3]     数据有改变,说明asarray函数不拷贝,会随原来的值变动

2.5.3 其他方法实例

import numpy

arr0 = numpy.zeros(1)       # 生成全为0的一维数组
arr1 = numpy.zeros((2,3))   # 生成全为0的二维
arr2 = numpy.empty(1).dtype()    # 结果为dtype('float')
arr3 = numpy.full(3,4)      # 生成元素全为4的一维数组,元素个数为3
arr4 = numpy.full(3,[1,2,3])    # 结果为array([1,2,3])
arr5 = numpy.full((2,3),2)  # 生成一个元素全为2的二维数组,两行三列
arr6 = numpy.eye(3)     # 生成一个3行3列的单位矩阵
arr7 = numpy.ones_like(arr) # 生成一个形状与arr一致但值全为1的数组

2.6 数组的拷贝

栈区 --> 内存中的内存
堆区 --> 内存中的硬盘

2.6.1 不拷贝

只是简单的赋值,比如 arr2 = arr,也就是说,arr2与arr指向堆区的内存空间一致。

import numpy as np

arr = np.arange(12)
print(arr)              # [ 0  1  2  3  4  5  6  7  8  9 10 11]
arr2 = arr
# 判断内存地址是不是一致,用is判断(也可以用" .id "的方法来判断)
print(arr is arr2)      # True

arr2[1] = 20
print(arr)              # [ 0 20  2  3  4  5  6  7  8  9 10 11]

2.6.2 浅拷贝

在栈区重新开辟一块内存空间指向同一个堆区 arr3 = arr.view()。注意:当我通过arr3去修改堆区某元素的值,那arr访问的就是改变后的值

import numpy as np

arr = np.arange(12)
print(arr)              # [ 0  1  2  3  4  5  6  7  8  9 10 11]

# 视图层的拷贝,浅拷贝
arr3 = arr.view()
print(arr3)             # [ 0  1  2  3  4  5  6  7  8  9 10 11]
print(arr3 is arr)      # False

arr3[0] = 10

print(arr)              # [10  1  2  3  4  5  6  7  8  9 10 11]

2.6.3 深拷贝

在栈区重新开辟一块内存空间指向堆区重新开辟的一块内存空间 arr4 = arr.copy()。注意:当我通过arr3去修改堆区某元素的值,arr的值不会受影响。

import numpy as np

arr = np.arange(12)
print(arr)              # [ 0  1  2  3  4  5  6  7  8  9 10 11]

arr4 = arr.copy()
print(arr4)             # [ 0  1  2  3  4  5  6  7  8  9 10 11]
print(arr4 is arr)      # False

arr4[0] = 10

print(arr)              # [ 0  1  2  3  4  5  6  7  8  9 10 11]

2.7 Numpy数组算术

数组之所以重要是因为它允许我们进行批量操作数据并且没有任何for循环,也被称为向量化。

2.7.1 数组与标量的算术操作

数组与标量的算术操作(和Python的运算符类似)会把计算参数传递给数组的每一个元素。(两个特殊值:nan --> not a number ;inf --> infinity 无穷数,分母为0时得到。)
实例

import numpy

arr = numpy.arange(6).reshape(2,3)
print(arr+1)
'''
[[1 2 3]
 [4 5 6]]
'''

拓展

# [0,1,2,3,4,5] 中每个元素加1

# 方法一:列表推导式
lt1 = [i+1 for i in range(6)]

# 方法二:用map()函数
# map(func,*iterables) 映射,将可迭代对象里面的每一个元素传到func函数里面去进行处理并返回结果
def add_one(x):
    return x+1

list(map(add_one,range(6))

2.7.2 两个等尺寸数组的算术操作

两个等尺寸数组的算术操作实际上是逐元素操作。

import numpy

arr = numpy.arange(1,7).reshape(2,3)
print(arr)
'''
[[1 2 3]
 [4 5 6]]
'''

print(arr + arr)
'''
[[ 2  4  6]
 [ 8 10 12]]
'''

print(arr / arr)
'''
[[1. 1. 1.]
 [1. 1. 1.]]
'''

print(arr - arr)
'''
[[0 0 0]
 [0 0 0]]
'''

print(arr > arr)    # 使用比较运算符,对应位置进行比较,返回布尔值

2.7.3 广播机制

广播机制规则:如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的。广播会在缺失和(或)长度为1的维度上进行。

(1) 与列数相同并且只有1行的数组之间进行运算

在其丢失的轴上进行,也就是0轴(行)广播

import numpy

arr1 = numpy.arange(12).reshape(4,3)
print(arr1)
'''
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

arr2 = numpy.arange(3).reshape(1,3)
print(arr2)     # [0 1 2]

# (4,3) - (1,3) = (4,3)
arr = arr1 - arr2
print(arr.shape,'\n',arr)
'''
(4, 3) 
 [[0 0 0]
 [3 3 3]
 [6 6 6]
 [9 9 9]]
'''

(2)与行数相同并且只有1列的数组之间进行运算

在其长度为1轴上进行,此处也就是1轴广播

import numpy

arr1 = numpy.arange(12).reshape(4,3)
print(arr1)
'''
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

arr2 = numpy.arange(4).reshape(4,1)
print(arr2)
'''
[[0]
 [1]
 [2]
 [3]]
'''

# (4,3) - (4,1) = (4,3)
arr = arr1 - arr2
print(arr.shape,'\n',arr)
'''
(4, 3) 
 [[0 1 2]
 [2 3 4]
 [4 5 6]
 [6 7 8]]
'''

注意:维度完全不一致,则无法广播

2.8 数组拼接

  • numpy.vstack():垂直(vertical)拼接,以行方向进行堆叠
  • numpy.hstack():水平(horizontal)拼接,以列方向进行堆叠
import numpy as np

t1 = np.arange(12).reshape(2,6)
t2 = np.arange(12,24).reshape(2,6)

# 垂直拼接
t3 = np.vstack((t1,t2))

# 水平拼接
h3 = np.hstack((t1,t2)

注意:水平拼接需要对应行数一致,垂直拼接需要对应列数一致。

2.9 切片

2.9.1 一维索引与切片

同Python中内建的数据类型list一值

  • 索引默认从0开始
  • 切片左闭右开
  • 步长为整数

注意:截取子数组,然后改变子数组的值,原数组的值也会改变,这是因为数组的截取是浅拷贝,要区别于列表的切片。

2.9.2 二维索引与切片

  • 方式一:二维数组递归方式获取
  • 方式二:二维数组逗号分隔获取(行,列):

(1)取单行 ---- arr[x1,:]

(2)取连续行 ---- arr[x1:x2,:]

(3)取分开行 ---- arr[[x1,x2],:]

(4)取子矩阵 ---- arr[x1:x2,y1:y2]

(5)取点 ---- arr[[x1,x2],[y1,y2]]

import numpy as np

arr = np.arange(24).reshape(4,6)
print(arr)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
'''

# 取第2行
arr[1,:]

# 取2到3连续行
arr[1:3,:]

# 取第2行与第4行
arr[1:4:2,:]    # 或者arr[1::2,:]

# 用神奇索引取第2行与第4行
arr[[1,3],:]

# 取子数组[[8 9],[14,15]]
arr[1:3,2:4]

# 用神奇索引(也叫花式索引)取8和15 (注意:使用神奇索引并不是取子数组,而是分开执行)  
arr[[1,2],[2,3]]

注意

  • 当有需要修改数组当中的值时,我们可以直接取值进行赋值。
  • 当数组与标量进行比较时,数组当中每个元素与标量进行比较,返回bool值,与此同时,该比较也可以作为索引,被称为布尔索引。比如arr[arr>20],取出arr数组中元素大于20的值,然后组成新的一维数组。
import numpy as np

arr = np.arange(24).reshape(4,6)
print(arr)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
'''
  
# 将第二列的值全部修改为0
arr[:,1] = 0    # 先取值再赋值

print(arr > 10)  # 每个元素返回bool值,满足条件为True,反之为False

# 取值,即把为True的值取出来
arr[arr > 10]

# 筛选出 >10 并且 <20 的值
arr[(arr>10) & (arr<20)]    # 注意有多个运算符时,优先级会紊乱,所以要括号进行限定

2.10 数组的条件逻辑操作

numpy.where()函数是三元表达式 x if condition else y 的向量化版本。

  • numpy.where(condition,[x,y]) # 当满足条件,执行x,否则执行y
import numpy

arr = numpy.arange(16).reshape(4,4)
print(arr)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
 '''

# np.where(arr<10)  # 返回元组(满足条件的行索引,满足条件的列索引) 
# 将<10的变为0,>=10变为10
arr1 = numpy.where(arr<10,0,10)
print(arr1)
'''
[[ 0  0  0  0]
 [ 0  0  0  0]
 [ 0  0 10 10]
 [10 10 10 10]]
'''

# 将arr<8的变为0,其它的保留不变
arr2 = np.where(arr<8,0,arr)   # 注意:x和y也可以传数组
print(arr2)
'''
[[ 0  0  0  0]
 [ 0  0  0  0]
 [ 8  9 10 11]
 [12 13 14 15]]
'''
  • np.clip(a, a_min, a_max, out=None,\*\*kwargs):用于裁剪(限制)数组中的值,等价于但效率要高于 np.minimum(a_max, np.maximum(a, a_min)) ,要求a_min < a_max

参数:(1)a —> 数组;(2)a_min —> 整数,下边界;(3)a_max —> 整数,上边界;(4)out —> 裁剪后输出的结果,要求必须和原数组的形状一致

import numpy as np

arr = numpy.arange(16).reshape(4,4)
print(arr)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
'''
 
# 将arr <= 5 替换为5  arr >= 10 的替换为10
arr1 = arr.clip(5,10)   # np.clip(x,y)的一般用法:小于x的替换为x,大于y的替换为y
print(arr1)
'''
[[ 5  5  5  5]
 [ 5  5  6  7]
 [ 8  9 10 10]
 [10 10 10 10]]
'''

2.11 Numpy操作本地数据

2.11.1 写入本地数据

numpy.savetxt(fname, X, fmt=’%.18e’, delimiter=’ ‘, newline=’\n’, header=’’,footer=’’, comments=’# ', encoding=None) 该函数不止可以操作txt文件,还可以操作csv文件

参数:

  • fname ----> 文件名称,默认保存在本地,可修改路径,比如fname=‘D:\test\test.csv’
  • X ----> 保存到text文件的1维或2维数组数据
  • fmt=’%.18e’ ----> 写入文件的格式,例如:%d,%.2f,%.18e
  • delimiter ----> 分隔符
  • newline ----> 换行符
  • header ----> 指定表头
  • footer ----> 指定结束符
  • comments ----> 在“ header”和“ footer”字符串之前添加的字符串,默认标记为 “#”
  • encoding ----> 指定编码

实例

import numpy as np

# 随机生成40位同学期中与期末的成绩(40行2列的数据)
scores = np.random.randint(0,100,size=(40,2))
print(scores)

# 将scores数据保存到csv文件中(以逗号分隔、数据类型为整数型,表头为期中 期末,注释comments为空)
np.savetxt(fname=r'D:\scores.csv',X=scores,delimiter=',',fmt='%d',header='期中,期末',comments='')

2.11.2 读取本地数据

np.loadtxt(fname, dtype=float, comments=’#’, delimiter=None,converters=None, skiprows=0, usecols=None, unpack=False,ndmin=0, encoding=‘bytes’, max_rows=None)

参数

  • fname ----> 文件路径及文件名称
  • dtype ----> 数据类型,默认为浮点型
  • comments ----> 如果行的开头为#,就会跳过该行
  • delimiter ----> 分隔符
  • converters ----> 对列数据进行预处理,需要传递字典,比如{0:func}表示第0列进行func函数预处理。
  • skipprows ----> 跳过行,整数,默认为0
  • usecols ----> 整数或序列,表示读取哪一列或哪几列,比如usecols=(1,4,5)表示读取第二列、第五列、第六列。
  • unpack ----> 如果为True,则对返回的数组进行转置,以便可以使用``x,y,z = loadtxt(…)’'解压缩参数。 与结构化数据类型一起使用时,将为每个字段返回数组。 默认值为False。
  • ndmin ----> 返回的数组将至少具有“ ndmin”维。 否则,将挤压一维轴。
  • encoding ----> 指定编码
  • max_rows ----> 设置显示的最大行数

实例1

import numpy as np

'''
注意:
(1)如果不使用分隔符,Python会认为数据是一个整体的字符串,如"11,12",一旦指定分隔符之后,数据会变为 11  12;
(2)表头为字符串,不能转化为浮点型,需要跳过第一行,另外skiprows=1表示跳过第一行,而不是索引为1的那一行
'''
scores = np.loadtxt(fname=r'D:\scores.csv',delimiter=',',skiprows=1)
print(scores)

# 上面跳过第一行的原因为:表头是字符串,表数据是整数型,而array数组要求元素必须是同一种数据类型。如果不进行跳过,也可以将表数据全部转化为字符串
scores_s = np.loadtxt(fname=r'D:\python报班学习\Python数据分析-Amy\scores.csv',delimiter=',',dtype='object')

实例2: 合并云南白药.csv与五浪液.csv的数据

import numpy as np

# 使用代码将两个表的数据(表头一致)进行拼接的步骤:1、读取数据,只保留第一个表的表头,另一个表的表头跳过;2、垂直合并表格。
# 读取云南白药数据
ynby = np.loadtxt(fname=r'G:\云南白药.csv',delimiter=',',dtype='object')
# 读取五粮液数据
wly = np.loadtxt(fname=r'G:\五粮液.csv',delimiter=',',dtype='object',skiprows=1)
# 查看两个数据表的形状
print(ynby.shape,'\n',wly.shape)    # 都为(156,11)

# 进行垂直拼接
concat = np.vstack((ynby,wly))
print(concat.shape)

# 保存数据
np.savetxt(fname=r'D:\concat.csv',X=concat,delimiter=',',fmt='%s')

2.12 NaN与inf

2.12.1 nan与inf介绍

  • nan:not a number 表示不是一个数字,属于浮点型
  • inf:np.inf表示正无穷,-np.inf表示负无穷,属于浮点型

2.12.2 NaN和inf的特点

  • nan与inf都是float类型
import numpy as np

print(type(np.nan))     # <class 'float'>
print(type(np.inf))     # <class 'float'>
  • 两个nan是不相等的:该特性可以用来判断nan的个数,其中(1)np.count_nonzero()函数用于计算非零的个数;(2)np.isnan()函数用于判断数组元素是否是NaN,返回为bool值。
import numpy as np

print(np.nan == np.nan)     # False

# 使用np.nan的特点判断nan的个数
arr = np.arange(6).reshape(2,3)
arr[1,2] = np.nan
# 方式一:通过np.nan != np.nan 以及布尔索引,再通过长度获取
print(len(arr[arr != arr]))
# 方式二:True == 1  False == 0 ,所以可以计算非0的个数
np.count_nonzero(arr != arr)
# 方式三:用np.isnan()函数
np.count_nonzero(np.isnan(arr))
  • np.nan与任何数值计算都是nan。
import numpy as np

print(np.arange([2,np.nan,3]) + 100)        # arr([102,nan,103])

由于np.nan与任何值计算都是nan,所以在运算时会带来较大的误差。一般我们都会将其处理掉。

2.12.3 如何处理nan

直接删除缺失值所在行,但是当数据量较小时,这样处理会有影响整体的数据。更优雅的做法(nan数量不多的情况下),是当求和时,将np.nan处理为0;当求均值时,将np.nan处理为非nan的均值。

实例

import numpy as np

b = np.arange(9).reshape(3,3)

# 将1和5替换为np.nan
b[(0,1),(1,2)] = np.nan

# 获取含有nan的索引
# print(np.where(np.isnan(b)))  # 返回的是元组(行和列)
row_index = np.where(np.isnan(b))[0]) # 获取含有nan的行索引

# 将含有nan的行删除
np.delete(b,row_index,axis=0)

练习:将 exam.csv 文件的数据读取,并且将成绩为空的值替换为非空数据的均值。

import numpy as np

# 读取数据,注意:1、ndarray为同质性数据;2、由于有缺失(有空格),所以需指定类型为字符串
exam_data = np.loadtxt(fname=r'G:\exam.csv',skiprows=1,delimiter=',',dtype=np.str)

# 取出空字符串的数据,赋值为np.nan
# 注意:这里不能直接将空字符串赋值为np.nan,这是因为字符串类型赋值为np.nan会转为na,而na无法转为浮点型,所以一般先赋值为0,然后再转化为需要的类型
exam_data[data_data == ' '] = 0

# 将数据转为float类型
exam_data = exam_data.astype(dtype=np.float)

# 取出为0的数据,赋值为np.nan
exam_data[exam_data == 0] = np.nan

# 将np.nan赋值为对应的列的均值
for exam_cols in range(exam_data.shape[1]):
    # 取出每一列的数据
    exam_col = exam_data[:,exam_cols]
    
    # 取出非nan的值
    non_nan_data = exam_col[exam_col == exam_col]
    
    # 求非nan的均值,然后赋值给nan
    exam_col[np.isnan(exam_col)] = non_nan_data.mean()
    
    # 进行四舍五入
    exam_col = np.round(exam_col)

2.13 numpy random模块

np.random为我们提供了许多获取随机数的函数,其实是Python内置random模块进行的封装。
参考网址:https://numpy.org/doc/stable/reference/random/legacy.html#numpy.random.RandomState

  • np.random.seed:用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed()值,则每次生成的随机数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。一般没有特殊要求不用设置。以下代码:
import numpy as np

# 随机种子,加上seed之后,每次执行的结果都是一样的
np.random.seed(1)
print(np.random.rand())
  • np.random.rand:生成一个值为[0,1)之间的数组,形状由参数指定,如果没有参数,那么将返回一个随机值。示例代码如下:

print(np.random.rand())     # 生成一个0~1之间的随机数
print(np.random.rand(2,3))  # 生成2行3列在0~1的随机数组
  • np.random.randn:生成均值(μ)为0,标准差(σ)为1的标准正态分布的值。示例代码如下:
import numpy as np

data = np.random.randn(2,3)  # 生成一个2行3列的数组,数组中的值都满足标准正太分布
  • np.random.randint:生成指定范围内的随机整数,并且可以通过size参数指定维度。示例代码如下:
import numpy as np

data = np.random.randint(low=0,high=10,size=(3,5)) #生成值在0-10之间,3行5列的数组
  • np.random.choice:从一个列表或者数组中,随机进行采样。或者是从指定的区间中进行采样,采样个数可以通过参数指定。注意:np.random模块没有sample()函数,该函数是内置的random模块的函数。
import numpy as np

data = np.arange(100)
res = np.random.choice(data,size=(2,3))    #从data中随机采样,生成2行3列的数组
  • np.random.shuffle:把原来数组的元素的位置打乱。注意:np.random.shuffle没有返回值,改变的是原数组。
import numpy as np

a = np.arange(10)
np.random.shuffle(a)     # 将a的元素的位置都会进行随机更换
print(a)
  • np.random.normal(loc=0.0,scale=1.0,size=None):默认生成均值loc为0,标准差scale为1的服从正态分布的数组,均值和标准差都可以重新设置
import numpy as np

# 生成一个均值为5,标准差为10的3行4列数组
np.random.normal(loc=5,scale=10,size=(3,4)

2.14 Numpy常用函数

2.14.1 聚合函数

方法描述
sum沿着轴向计算所有元素的累和,0长度的数组,累和为0
mean数学平均,0长度的数组平均值为NaN
max,min最大值和最小值
argmax,argmin最大值和最小值的位置
std,var标准差和方差
ptp极值(最大值减去最小值)
cumsum从0开始元素累积和,返回一个数组
median中值
import numpy as np

a1 = np.arange(12).reshape(3,4)

np.sum(a1)         # 全部相加
np.sum(a1,axis=0)  # 计算0轴(每一列)的累和,返回一个整型数组
np.sum(a1,axis=1)  # 计算1轴(每一行)的累和,返回一个数组

np.mean(a1)       # 求整个数组的均值
np.mean(a1,axis=0)  # 计算0轴(每一列)的均值,默认返回一个浮点型数组

# 其他函数类似

# 方差:样本数据与均值之间的偏离程度,方差越小,说明偏离均值越小,数据越稳定
np.var(a1)

# 标准差:方差的算术平方根(有正负之分),体现数据的波动性,标准差越大,波动越大
np.std()

print(np.cumsum(a1))    # 返回[ 0  1  3  6 10 15 21 28 36 45 55 66]

a2 = a1.astype('float')     # 由于nan是float类型,所以先转换类型
a2[2,2] = np.nan    # 将数组的其中一个值变为nan
print(np.sum(a2))   # 结果为nan,这是因为nan与任何值计算都是nan

# 需求:跳过nan进行求和,可以用np.nansum()函数
np.nansum(a2)

计算数组时,numpy的聚合函数要比Python内置的聚合函数效率高

import numpy as np
import time

a1 = np.arange(10000000)
start1 = time.time()
sum(a1)
end1 = time.time()
print(end1-start1)      # 1.8280293941497803

start2 = time.time()
np.sum(a1)
end2 = time.time()
print(end2-start2)      # 0.010016202926635742

2.14.2 一元函数

函数描述
np.abs绝对值
np.sqrt开根
np.square平方
np.exp计算指数(e^x)
np.log,np.log10,np.log2,np.log1p求以e为底,以10为低,以2为低,以(1+x)为底的对数
np.sign标签化
np.sort排序,默认axis=1,即默认按1轴从小到大进行排序
np.linspace平分,比如np.linspace(0,10,15)表示将0~10的数平均分成15份,返回一个数组
np.ceil向上取整,比如5.1会变成6,-6.9会变成-6
np.floor向下取整,比如5.9会变成5,-6.1会变成-7
np.rint,np.round四舍六入五成偶
np.modf将整数和小数分隔开来形成两个数组
np.isnan判断是否是nan
np.isinf判断是否是inf
np.cos,np.cosh,np.sin,np.sinh,np.tan,np.tanh三角函数
import numpy as np

# 生成-10到10之间服从均匀分布的3行5列的随机数组
arr = np.random.uniform(-10,10,size=(3,5))  
print(arr)

# 求绝对值
arr1 = np.abs(arr)

# 计算指数e^x
np.exp(0)   # e^0=1
np.exp(1)   # e^1=e

# 以e为底的对数,经常用来做数据的收敛
np.log(np.exp(1))   # 计算结果为1
np.log(0)           # 结果为0.0

# 标签化,大于0的为1,小于0的为-1
print(np.sign(arr))
'''
[[ 1. -1. -1.  1. -1.]
 [-1. -1.  1.  1.  1.]
 [ 1.  1. -1. -1. -1.]]
'''


np.rint(4.4)   # 四舍,结果为4
np.rint(4.5)   # 五舍,结果为4

np.rint(4.6)   # 六入,结果为5
np.rint(5.5)   # 五成双,结果为6

# 三角函数
np.sin(np.pi/2)     # 结果为1
np.sin(np.pi)       # 结果为1.2246467991473532e-16,按道理来说,应该为0,但由于是float64,精度不够,所以无线接近于0,而不是0

2.14.3 二元函数

函数有两个参数

函数描述
np.add加法运算(即1+1=2),相当于+
np.subtract减法运算(即3-2=1),相当于-
np.negative负数运算(即-2),相当于加个负号
np.multiply乘法运算(即23=6),相当于
np.divide除法运算(即3/2=1.5),相当于/
np.floor_divide取整运算,相当于//
np.mod取余运算,相当于%
greater,greater_equal,less,less_equal,equal,not_equal>,>=,<,<=,=,!=的函数表达式
logical_and&的函数表达式
logical_or\的函数表达式
import numpy as np

arr = np.random.uniform(-10,10,size=(3,5)) 

np.add(arr,arr)  # 加法运算

# 取出arr中 >0 并且 <5 的数
# 方式一:
arr[(arr<5) & (arr>0)]
# 方式二:
arr[np.logical_and(arr>0,arr<5)]  

2.14.4 布尔函数

  • np.all():只要该布尔数组里面有一个False,那么该函数就返回False
  • np.any():只要该布尔数组里面有一个True,那么该函数就返回True
import numpy as np

arr = np.random.uniform(-10,10,size=(3,5)) 

np.all((arr>0)&(arr<5))     # 结果为False
np.any((arr>0)&(arr<5))     # 结果为True

2.15 数组的线性代数运算

线性代数(例如矩阵乘法、矩阵分解、行列式以及其他数学函数)是任何数据分析库的重要组成部分。Numpy也提供这样的能力。

  • np.dot(arr,arr.T):矩阵的乘法运算
import numpy as np

arr = np.arange(4)

# 矩阵乘法
np.dot(arr,arr.T)

numpy.linalg封装了一组标准的矩阵分解运算以及诸如逆运算、行列式等功能。

函数描述
det计算矩阵行列式
eig计算方阵的特征值和特征向量
inv计算方阵的逆
qr计算QR分解
svd计算奇异值分解(SVD)
solve解线性方程
lstsq计算Ax=b的最小二乘解

需求1:利用inv函数,求解矩阵的逆矩阵(注意:矩阵可变,首先必须是方阵)

from numpy.linalg import inv

arr_lg = np.array([0,1,2],[1,0,3],[4,-3,8])

# 求方阵的逆
print(inv(arr_lg))
# 检验:矩阵*矩阵的逆 = 单位矩阵
print(np.dot(arr_lg,inv(arr_lg))

需求2:

# 求解如下方程组的解:
# x - 2y + z = 0
# 2y - 8z = 8
# -4x + 5y + 9z = -9

from numpy.linalg import solve

# 创建系数矩阵
A = np.array([0,-2,1],[0,2,-8],[-4,5,9])
B = np.array([0,8,-9])

# 解方程组
print(solve(A,B)    # 结果为array([29,16,3])

2.16 综合练习

GB_video_data_numbers.csv
US_video_data_numbers.csv

以上为英国与美国Youtube数据,其每列对应的是:点击,喜欢,不喜欢,评论

练习1:结合Matplotlib绘制各自的评论数量的图形,体现其评论数主要分布在哪个区间。

练习2:绘制图形,分析英国的Youtube中视频的评论数与喜欢数的关系。

练习3:当希望将两个国家的数据拼接一起来研究分析:
(1)拼接全为0的数组标识为英国
(2)拼接全为1的数组标识为美国
(3)将两个国家的数据拼接

实现方式一:

import numpy as np
import matplotlib
from matplotlib import pyplot
font = {
    'family':'SimHei',
    'weight':'bold',
    'size':12
}
matplotlib.rc("font", **font)

# 读取数据
gb_data = np.loadtxt(fname=r'D:\GB_video_data_numbers.csv',delimiter=',',dtype=np.int)
us_data = np.loadtxt(fname=r'D:\US_video_data_numbers.csv',delimiter=',',dtype=np.int)
print('英国Youtube数据',gb_data.shape,'\n',gb_data,'\n','美国Youtube数据',us_data.shape,'\n',us_data)

'''实现练习1和练习2的要求'''
# 截取需要的数据,喜欢数量在第二列、评论数量在第四列
gb_like = gb_data[:,1]
gb_comment = gb_data[:,3]
us_comment = us_data[:,3]

# 查看评论数的最大值、最小值、数值个数,以及小于均值的数值个数
print('英国评论数量最大值:{a};英国评论数量最小值:{b};英国评论数量值个数:{c}'.format(a=np.max(gb_comment),b=np.min(gb_comment),c=len(gb_comment)))
print('美国评论数量最大值:{a};美国评论数量最小值:{b};美国评论数量值个数:{c}'.format(a=np.max(us_comment),b=np.min(us_comment),c=len(us_comment)))
print('英国评论数小于均值的数值个数:{}'.format(len(gb_comment[gb_comment < np.mean(gb_comment)])))
print('美国评论数小于均值的数值个数:{}'.format(len(us_comment[us_comment < np.mean(us_comment)])))

'''
1、从上面的输出结果初步判断可能存在离群值,因此考虑使用箱型图体现其评论数主要分布在哪个区间;
2、用散点图体现评论数与喜欢数的相关关系。
'''
# 创建画布
fig = pyplot.figure(figsize=(8,6))

# 多图布局
gs = fig.add_gridspec(2,2)
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1])
ax3 = fig.add_subplot(gs[1,:])

# 自动调整子图的间距
fig.tight_layout()

# 绘制图形
ax1.boxplot(x=gb_comment,notch=True,sym='^',widths=0.1,meanline=True,showmeans=True,autorange=True)
ax2.boxplot(x=us_comment,notch=True,sym='*',widths=0.1,meanline=True,showmeans=True,autorange=True)
ax3.scatter(x=gb_comment,y=gb_like)

# 设置散点图 x轴 y轴的标签
ax3.set_xlabel('英国评论数')
ax3.set_ylabel('英国喜欢数')

# 设置标题
ax1.set_title(label='英国评论数箱型图')
ax2.set_title(label='美国评论数箱型图')
ax3.set_title(label='英国评论数与喜欢数的散点图')

pyplot.show()

'''实现练习3的要求'''
# 创建元素全为0、长度与gb_data行数相同的数组
arr_0 = np.zeros(shape=(gb_data.shape[0],1),dtype=np.int)

# 将创建好的全0数组与gb_data进行水平拼接
gb_data_new = np.hstack((gb_data,arr_0))

# 创建元素全为1、长度与us_data行数相同的数组
arr_1 = np.ones(shape=(us_data.shape[0],1),dtype=np.int)

# 将创建好的全1数组与us_data进行水平拼接
us_data_new = np.hstack((us_data,arr_1))

# 垂直拼接两个国家的数据
concat_data = np.vstack((gb_data_new,us_data_new))

# 检查数据
print(concat_data.shape,'\n',concat_data)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值