Day077Numpy

mac2025-08-08  16

Numpy

Numpy是科学计算基础库,提供大量科学计算相关功能,比如数据统计,随机数生成等。其提供最核心类型为多维数组类型(ndarray)。numpy支持向量处理ndarray对象,提高程序运算速度。

ndarray:n-dimensional array object,任意维数的数组对象

Numpy numpy.org/

1、使用方式

安装numpy库 pip install numpy 使用numpy库 import numpy as np

2、数组创建

Numpy提供很多函数创建数组,常用函数如下:

arrayarangeones/ones_likezeros/zeros_likeempty/empty_likefull/full_likeeye/identitylinspacelogspace

导入numpy模块

import numpy as np

Ipython中的 In 和 Out

# In :Ipython解释器提供特殊对象,用来存储输入信息,列表类型 # Out :Ipython解释器提供特殊对象,用来存储输出信息,字典类型。当单元格运行后,最后一个表达式非空的时候,将信息保存到out对象 # np.__version__ # 查看版本号 # print(np.__version__) In

array()方法

# 使用array方法创建一维数组,传入参数为列表 # n = np.array([1,2,3]) # # 注意:对于display()方法,python解释器不支持,ipython解释器才支持。 # display(n) # print(n) # 使用array创建多维数组,传入参数是嵌套列表 n= np.array([[1,2],[3,4]]) display(n)

arange方法

# arange方法类似python中range方法,传入参数也包含起始值,结束值和步长 # n = np.arange(10) # n = np.arange(1,10) # n=np.arange(1,10,2) # n # 步长可以是浮点型,以及负数 n = np.arange(3,1,-0.5) n

ones 和 ones_like

# ones(shape,dtype=None,order='C')创建全为1的数组 # shape 整型或者元祖 # dtype 数据类型 默认numpy.float64 n1 = np.ones(3) display(n1) n2 = np.ones((3,4)) display(n2) np.ones((3,2)) # ones_like:根据传入的数组形状创建全为1的数组 n3 = np.ones_like(n2) display(n3)

zeros 和 zeros_like

# zeros方法创建全为0的数组 n1 = np.zeros(3) display(n1) n2 = np.zeros((3,4)) display(n2) # zeros_like:根据传入的数组形状创建全为0的数组 n3 = np.zeros_like(n2) display(n3)

empty 和 empty_like

# empty创建全为空数组:注意,数据并不是设置为0,而是值未初始化,需要我们自己来初始化 n1 = np.ones(3) n1 = None n1 = np.empty(3) display(n1) # empty_like 根据传入的数组形状创建全为空的数组 n2 = np.empty_like(n1) display(n2)

full 和 full_like

# full(shape,fill_value) 创建全为某个指定数据的数组 # shape 数组维度或者形状 # fill_value 指定数据 n1 = np.full((2,2),3) display(n1) # full_like:根据传入数组形状创建数组,同时指定全为某个数 n2 = np.full_like(n1,4) display(n2)

eye和identity

# eye和identity创建单位矩阵 n1 = np.eye(3) display(n1) n2 = np.identity(3) display(n2)

linspace

# linspace根据一定间隔创建等差数组 # 格式:np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) # 1,2,3,4,5 # endpoint=True 间隔 end-start/(num-1) n1 = np.linspace(1,5,num=5) display(n1) # 1,2,3...50 n2 = np.linspace(1,50) display(n2) # endpoint=False 间隔 end-start/num # 5-1/5 4/5 0.8 # 1 1.8 2.6 3.4 4.2 n3 = np.linspace(1,5,num=5,endpoint=False) display(n3)

logspace

# logspace根据指数函数创建等比数组 # 格式:np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None) # 1 2 4 8 n1 = np.logspace(0,3,num=4,base=2) display(n1) # 1 10 100 1000 n2 = np.logspace(0,3,num=4) display(n2)

3、数组ndarray和列表(List)比较

优势

数组可与标量进行计算,数组之间可进行向量化计算数组在运算时,具有广播能力。数组底层使用c语言编写,运行速度快数组底层使用c数组的存储方式,节省内存空间 # 班上同学的python成绩,统一加1分 # 列表操作 scores = [90,91,92] # 循环遍历列表 for i in range(len(scores)): scores[i]+=1 display(scores) # 数组操作 scores_ndarray = np.array([90,91,92]) # 整体操作,不再需要循环遍历 scores_ndarray+=1 display(scores_ndarray) a = np.array([1,2,3,4]) b = np.array([[1,1,1],[2,2,2]]) display(a+b)

4、魔法命令

魔法命令是ipython提供特殊命令,能实现一些特殊功能,比如统计时间(time/timeit)和占用内存(memit/mprun)等功能。 魔法命令两种形式:

% :行模式%% :单元格模式

time

time 统计语句执行时间,被统计语句只执行一次

timeit

timeit可以循环多次执行被统计语句,得到平均执行时间,支持行模式和单元格模式。 timeit命令参数,–n 指定每轮测试次数,-r 指定测试轮数(默认为7) 单元格模式

第一行语句(与timeit同一行语句)为初始化语句,作用为后续代码中变量提供初始化功能。初始化语句每轮测试只执行一次,且不参与计时。第二行至整个单元格末尾语句会执行相应次数,并参与计时。 # 统计time.sleep(0.5)语句执行时间 import time start = time.time() time.sleep(0.5) end = time.time() display(end-start) # time用来统计语句执行时间,被统计语句只执行一次 %time time.sleep(0.5) %time a=1 # 46.1 ns ± 2.75 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) # 7 runs 运行7轮 # 10000000 loops 每轮循环执行次数 # 46.1 ns ± 2.75 ns per loop (mean ± std 均值是46.1 标准差是2.75 ns 【46.1 ns - 2.75,46.1 ns + 2.75】 %timeit a=1 # -n 每轮循环的次数 # -r 执行轮数 默认是7轮 %timeit -n 1000 -r 2 a=1 %%time time.sleep(0.5) time.sleep(0.6) %%timeit -n 2 -r 2 time.sleep(0.5) time.sleep(0.6) %%timeit -n 2 -r 3 print('初始化语句') print('hello world') # 单元格模式下,我们可以在timeit后面(同一行)使用初始化语句 # 初始化语句作用为后续被统计的执行代码提供变量的初始化 # 初始化语句执行次数由轮数来决定 %%timeit li = list(range(100000)) # 第一行作为初始化语句,不参与计时 操作 # 对列表的+1操作,多行,故timeit使用单元格模式 for i in range(len(li)): li[i]+=1 %%timeit a = np.arange(100000) # 1ms=1000us a+=1

writefile

将单元格内容写入到文件中。如果文件不存在则创建,如果文件存在,则覆盖文件。如果指定 –a 参数,则追加内容,不覆盖。

%%writefile test.py # 文件不存在则创建 x=1 print(x) print("hello world!") %%writefile test.py # 文件存在,则覆盖 print('update....') %%writefile -a test.py # 指定 –a 参数,则追加 print('update222222....')

执行结果:

Appending to test.py

run

运行外部python文件,运行结束后,外部文件中定义的变量得到保留。 格式: %run 文件路径

前提准备:在jupyter 主目录下(与 魔法命令 run所在的numpy.ipynb目录一致)新建一个 test.py 的文件,里面包含代码如下

a=1 print(a) print("hello world!")

在 numpy.ipynb 中:

%run test.py

执行结果:

1 hello world

再次执行下面语句:

In [22]:(输入)

a

Out[22]:(输出)

​ 1

memit

分析语句内存使用情况。memit支持行模式与单元格模式。单元格模式下,初始化语句不会参与计算内存。第二行至整个单元格末尾会参与计算内存。 说明:

memit不是Ipython内置,需要安装memory_profiler模块(pip install memory_profiler)安装后,需要通过%load_ext memory_profiler载入,才能使用

载入

%load_ext memory_profiler def m1(): print('hello world') %memit m1()

运行结果:

hello world hello world hello world hello world peak memory: 52.05 MiB, increment: 0.14 MiB

对单个语句使用:

%memit x=2

运行结果:

peak memory: 67.02 MiB, increment: 0.00 MiB

mprun

逐行分析语句内存使用情况,分析结果列如下:

Line 行号Mem usage 内存使用大小increment内存增量Line content 代码内容

说明:

mprun不是Ipython内置,需要安装memory_profiler模块安装后,需要通过%load_ext memory_profiler载入,才能使用mprun测试的函数必须定义在独立模块中,不能定义在交互式Ipython环境中如果需要重新加载模块,可以调用importlib模块提供reload函数实现 %%writefile test2.py def m(): li1 = [i for i in range(20000)] li2 = [i for i in range(400000)]

执行结果:

Overwriting test2.py

%load_ext memory_profiler

执行结果:

The memory_profiler extension is already loaded. To reload it, use: %reload_ext memory_profiler

In [25]:

# import test2 # 修改代码后,想要再次导入代码所在的模块成功,需要使用importlib模块的relaod方法 import importlib importlib.reload(test2)

Out[25]:

In [26]:

# %mprun -f 分析函数 执行语句 %mprun -f test2.m test2.m()

4、数组属性

数组对象具有如下常用属性:

ndim:n-dimension,维度shape:形状,每个维度上相应长度dtype::数据类型size:数组元素个数itemsize:一个数组元素占用内存空间,字节为单位

In [7]:

x = np.array([1,2,3]) display(x.ndim) y = np.array([[1,2,3],[2,3,4]]) display(y.ndim) # 返回数组对象形状,每个维度上长度,元祖 display(y.shape) # 返回数据类型 display(y.dtype) # 返回元素个数 display(y.size) # 返回一个元素占用内存空间,字节为单位 display(y.itemsize)

执行结果:

​ 1

​ 2

​ (2,3)

​ dtype('int32')

​ 6

​ 4

5、数据类型及转换

创建数组时候,可使用dtype指定数组中元素类型如果没有指定,根据元素类型进行推断如果类型不同,会选择兼容类型使用astype函数转换数据类型

In [13]:

# 使用dtype指定数组中元素类型 x = np.array([1,2,3],dtype=np.float32) display(x.dtype) # 如果没有指定,根据元素类型进行推断 y = np.array([1.1,2.1,3.1]) display(y.dtype) # 如果类型不同,会选择兼容类型(向上) z = np.array([1.1,2,3,4]) display(z.dtype) # 使用astype函数转换数据类型 w = np.array([1.1,2.2,3.3,-4.4]) display(w.dtype) m = w.astype(np.int64) display(m)

执行结果:

​ dtype('float32')

​ dtype('float64')

​ dtype('float64')

​ dtype('float64')

​ array([ 1, 2, 3, -4], dtype=int64)

6、改变数组形状

我们可以通过数组对象的reshape方法(或者np的reshape函数)改变数组形状。 说明:

nump中很多方法,既可以使用np来访问,也可以通过数组对象来访问 # 一维数组改为多维数组 x = np.arange(6) display(x) # 数组对象,reshape的参数可以是元祖,也可以将元祖中内容分开传入 # y=x.reshape(3,2) # np的reshape方法,只能使用元祖传入,不能将元祖中内容分开传入 y=np.reshape(x,3,2) display(y) # 多维数组改为1维数组 # x = np.array([[1,2,3],[3,4,5]]) # display(x) # # y = x.reshape((-1)) # y = np.reshape(x,(-1)) # display(y)

7、索引与切片

在python中,序列类型支持索引与切片。ndarray数组也支持类似操作。不过两者之间既有相同点,也有不同点。

相似点:数组对象也支持索引与切片,语法python中索引与切片类似不同点:数组切片返回的原数组数据视图。如果需要复制底层数组元素,可使用数组对象copy方法 注意:视图共享底层数组元素。

In [25]:

# 索引访问 x = np.arange(9).reshape(3,3) display(x) # 从低维获取数据 # x是2维数组,包含低维和高维,低维对应向下坐标轴,表示为0方向;高维对应向右 坐标轴,表示1方向。 # x[1]从低维度,也就是从0方向上获取数据,即访问的第一行的数据 display(x[1]) display(x[1][1])

执行结果:

​ array([[0, 1, 2], ​ [3, 4, 5], ​ [6, 7, 8]])

​ array([3, 4, 5])

​ 4

# 切片访问 # 0 1 2 # 3 4 5 # 6 7 8 x = np.arange(9).reshape(3,3) display(x) # 得到 # 3 4 5 # 6 7 8 # y = x[1:3] # display(y) # 得到 # 3 4 # 6 7 # y = x[1:3,0:2] # display(y) # 得到 # 1 2 # 4 5 # 7 8 # y = x[:,1:3] # display(y) # 得到 # 1 2 # 4 5 # y = x[0:2,1:3] # display(y) # 得到 修改步长 # 0 1 2 # 6 7 8 y = x[0:3:2,:] display(y)

执行结果:

​ array([[0, 1, 2], ​ [3, 4, 5], ​ [6, 7, 8]])

​ array([[0, 1, 2], ​ [6, 7, 8]])

# 切片得到新的数组,和原有的数组共享底层内存中数据,修改其中一方都会去影响对方的数据 # 通过数组对象的copy方法得到新的数组,新的数组和原有数组之间不共享数据 x = np.array([1,2,3]) # y = x[:] # # y[0]=100 # x[0]=200 # display(x) # display(y) w = x.copy() w[0]=30 display(x) display(w)

执行结果:

​ array([1, 2, 3])

​ array([30, 2, 3])

# 对列表切片操作,使用的浅拷贝,修改新的列表不会影响原有的列表 li = [1,2,3] li2 = li[:] li2[0] = 10 display(li) display(li2)

执行结果:

​ [1, 2, 3]

​ [10, 2, 3]

8、整数数组进行索引

当选取元素不连续时候,可以提供一个索引数组选择(或修改)对应索引位置元素。 说明

通过整数数组索引,返回的是原数组拷贝可以提供多个一维数组索引,此时会将每个数组中内容对应作为索引,返回对应的元素

In [57]:

x = np.arange(20).reshape(5,4) display(x) # 获取第0 2 3,不连续数据 # y = x[[0,2,3]] # display(y) # y[0][0]=100 # display(y) # display(x) # 返回0 (0,0) 2 (0,2) 8 (2,0)10 (2,2) # [0,0,2,2] [0,2,0,2] y= x[[0,0,2,2],[0,2,0,2]] display(y)

执行结果:

​ array([[ 0, 1, 2, 3], ​ [ 4, 5, 6, 7], ​ [ 8, 9, 10, 11], ​ [12, 13, 14, 15], ​ [16, 17, 18, 19]])

​ array([ 0, 2, 8, 10])

9、布尔数组进行索引

我们可通过布尔数组对数组进行索引,获取对应的元素。获取数据原则,为True,获取对应位置,为False,不获取。 说明:

索引布尔数组通过对现有数组计算得到逻辑运算符和python不同:and->&, or->|,not->~,条件组合时候,条件需用小括号 x = np.arange(12).reshape(4,3) display(x) # 使用布尔数组获取第0行 1行数据 y=x[[True,True,False,False]] display(y) # 大于5 # x[x>5] # 大于1小于5数据返回 x[(x>1) & (x<5)]

执行结果:

​ array([[ 0, 1, 2], ​ [ 3, 4, 5], ​ [ 6, 7, 8], ​ [ 9, 10, 11]])

​ array([[0, 1, 2], ​ [3, 4, 5]])

Out[26]:

array([2, 3, 4])

10、数组扁平化

我们可以通过调用ravel或flatten方法,对数组对象进行扁平化处理

np.ravel/ravelflatten 两者区别在于,ravel返回数组原数组共享数据,而flatten返回原数组拷贝

In [33]:

x = np.arange(12).reshape(3,2,2) display(x) # y = np.ravel(x) # 返回的数组和原数组共享数据,修改返回数组影响原有数组 y=x.ravel() y[0]=200 # 返回的原数组拷贝,修改返回数组不影响原有数组 # y = x.flatten() # y[0] = 100 display(x) display(y)

执行结果:

array([[[ 0, 1], [ 2, 3]], [[ 4, 5], [ 6, 7]], [[ 8, 9], [10, 11]]]) array([[[200, 1], [ 2, 3]], [[ 4, 5], [ 6, 7]], [[ 8, 9], [ 10, 11]]]) array([200, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

11、数组存储顺序

在创建数组时,我们可以通过order参数指定数组元素存储顺序。存储顺序分为2种:

C: 按照行存储F: 按照列存储 说明:order参数作用于两个步骤:一是数据抽取(扁平化处理)顺序;二是数据构建(数组填充)顺序 x = np.array([1,2,3,4]).reshape((2,2),order='C') y = np.array([1,2,3,4]).reshape((2,2),order='F') display(x) display(y)

执行结果:

​ array([[1, 2], ​ [3, 4]])

​ array([[1, 3], ​ [2, 4]])

x = np.array([[1,2],[3,4]]).reshape((2,2),order='C') y = np.array([[1,2],[3,4]]).reshape((2,2),order='F') display(x) display(y)

执行结果:

array([[1, 2], ​ [3, 4]])

array([[1, 2], ​ [3, 4]])

结果说明:order()函数的数据作用过程,作用于两步:1.扁平化处理;2.数据构建。

12、通用函数ufunc(universal function)

Numpy提供很多通用函数,它们可看做对应Python计算向量化版本

abs/fabscell/floorexplog/log2/log10modfsin/sinh/cos/coshsqrt

In [16]:

x = np.array([-1.2,10,1.5]) display(x) # np.abs(x) np.modf(x)

执行结果:

array([ -1.2, 10. , 1.5])

Out[16]:

(array([-0.2, 0. , 0.5]), array([ -1., 10., 1.]))

13、统计函数

Numpy具有如下常用统计函数

mean/summax/minargmax/argminstd/varcumsum/cumprod # 统计函数如果只传入数组对象的话,它会对数组首先做一个扁平化处理,再对扁平化后的一维数组的所有的数据进行统计 x = np.arange(1,5).reshape(2,2) display(x) # display(np.mean(x),np.sum(x)) # display(np.max(x),np.min(x)) # argmax 得到最大值对应索引值,argmin最小值对应索引值 # display(np.argmax(x),np.argmin(x)) # std标准差 var方差 # display(np.std(x),np.var(x)) # cumsum 累加和 cumprod 累乘 display(np.cumsum(x),np.cumprod(x))

执行结果:

array([[1, 2], [3, 4]]) array([ 1, 3, 6, 10], dtype=int32) array([ 1, 2, 6, 24], dtype=int32)

14、轴(axis)

可以指定axis参数改变统计的轴。在二维数组中,0表示竖直方向操作,1表示沿着水平方向操作。 超过二维的多维数组,轴相对复杂,可认为沿着轴所指定坐标变化方向,其他轴坐标不变。进行操作。比如轴是0,则根据第0个坐标变化方向

1、为什么统计函数需要传入axis参数 2、如何理解axis,特别数组维度超过2维时候。例如:学生成绩表格如下

| 姓名 | 语文 | 数学 | | ---- | ---- | ---- | | 张三 | 90 | 94 | | 李四 | 85 | 100 |

scores = np.array([[90,92],[85,100]]) # axis=0,从竖直方向统计数据,获得语文的最高分,以及数学的最高分 display(np.max(scores,axis=0)) # 如果我们指定轴为0,第一个维度的坐标变化的,第二个维度的坐标不变

运行结果:

​ array([ 90, 100])

x = np.arange(12).reshape((3,2,2)) display(x) display(x.sum(axis=0))

运行结果:

array([[[ 0, 1], [ 2, 3]], [[ 4, 5], [ 6, 7]], [[ 8, 9], [10, 11]]]) array([[12, 15], [18, 21]])

15、连接和拆分函数

np.concatenate对多个数组按指定轴方向进行连接np.vstack/np.hstacknp.split/np.hsplit/np.vsplit

101班成绩 .

| 数学 | 语文 | | ---- | ---- | | 95 | 100 | | 96 | 98 |

102班成绩 .

| 数学 | 语文 | | ---- | ---- | | 97 | 98 | | 96 | 99 | | 95 | 94 |

101班成绩 数学 语文 [[95,100], [96,98]]

102班成绩 数学 语文 [[97,98], [96,99], [95,94]]

# 对101班和102班成绩进行垂直连接,列数一致 x = np.array([[95,100], [96,98]]) y = np.array( [[97,98], [96,99], [95,94]]) # display(x,y) # w = np.concatenate((x,y),axis=0) w = np.vstack((x,y)) display(w) # 对w进行横向切分,将数据切分2部分 # z = np.split(w,2,axis=1) # display(z) # 对w进行纵向切分,得到3部分数据 第0,1行,第2,3行 第4行 z = np.split(w,[2,4],axis=0) display(z)

运行结果:

array([[ 95, 100], [ 96, 98], [ 97, 98], [ 96, 99], [ 95, 94]]) [array([[ 95, 100], [ 96, 98]]), array([[97, 98], [96, 99]]), array([[95, 94]])]

101班成绩 数学 语文 [[95,100], [96,98]]

101班 身高 体重 [[175,65], [177,70]] 175 65 177 70

# 对101班zs和ls成绩和身高及体重数据水平连接,保证行数一致 x = np.array([[95,100], [96,98]]) y = np.array( [[175,65], [177,70]]) display(x,y) # w = np.concatenate((x,y),axis=1) w = np.hstack((x,y)) display(w) # 对w进行纵向切分 z = np.split(w,2,axis=0) display(z)

运行结果:

array([[ 95, 100], [ 96, 98]]) array([[175, 65], [177, 70]]) array([[ 95, 100, 175, 65], [ 96, 98, 177, 70]]) [array([[ 95, 100, 175, 65]]), array([[ 96, 98, 177, 70]])]

16、其他函数

any/alltransposedotnp.sortnp.argsort

In [103]:

# any和all运算时,数组元素为0 False 空返回False,其他返回True # any有一个数组元素返回True,any返回True x = np.array([0,0,False]) display(x.any(),x.all())

运行结果:

False False

In [109]:

# transpose对数组数据进行装置 x = np.arange(1,5).reshape(2,2) display(x) # display(x.transpose()) display(x.T) # 数组转置本质上轴的颠倒,对于二维数组a[i][j]-->a[j][ip] a[0][1]-->a[1][0] # 传入参数,指定轴的颠倒顺序 y = np.arange(1,13).reshape(3,2,2) # display(y) # 如果tanspose方法不传入参数,默认前后颠倒 a[i][j][k]-->a[k][j][i] # transpose(0,2,1) a[i][j][k]-->a[i][k][j] # # display(y.transpose(0,2,1))

运行结果:

array([[1, 2], [3, 4]]) array([[1, 3], [2, 4]])

In [113]:

x = np.array([[1,2],[3,4]]) y = np.array([[2,3],[1,2]]) display(x,y) # 不是矩阵乘法运算 # display(x*y) # 使用dot实现矩阵乘法(点积)运算,如果dot传的参数是一个具体的数值,则对该数组对象做广播的操作,即每个 元素都乘传递的具体数值 # display(x.dot(y)) display(x.dot(3))

运行结果:

array([[1, 2], [3, 4]]) array([[2, 3], [1, 2]]) array([[ 3, 6], [ 9, 12]])

In [120]:

# sort 排序 x = np.array([3,-1,2]) # display(np.sort(x)) y=np.array([[3,2],[1,2]]) display(y) # sort对数组内容进行排序,默认按照最后一个轴的方向排序,如果是二维,按照水平方向排序,从小到大 # display(np.sort(y,axis=1)) # argsort 对数组内容对应的下标进行排序, display(np.argsort(y))

运行结果:

array([[3, 2], [1, 2]]) array([[1, 0], [0, 1]], dtype=int64)

17、归一化矩阵

将矩阵值转化为0到1区间

归一化公式:x-min/max-min max为每列最大值,min为每列最小值 90 1 80 2 70 2 min 70 1 max 90 2 90-70/90-70=20/20=1 80-70/90-70=10/20=0.5

In [5]:

x = np.array([[90,1],[80,2],[70,2]]) # 得到0方向最大值 max = x.max(0) # 得到0方向最小值 min = x.min(0) # 得到max-min的范围值 range = max-min # 矩阵减去min在0方向的复制,除以范围在0方向上复制 shape = x.shape y = x - np.tile(min,(shape[0],1)) y = y/np.tile(range,(shape[0],1)) y

Out[5]:

array([[ 1. , 0. ], [ 0.5, 1. ], [ 0. , 1. ]])

In [4]:

a = np.tile([1,2],(1,2)) a

Out[4]:

array([[1, 2, 1, 2]])

最新回复(0)