Numpy使用说明

导入numpy

import numpy as np

Numpy最重要的一个特点就是它可以快速地创建一个N维数组对象,即numpy.ndarray。(本专栏ndarray对象和数组并不做概念上的区分)。
然后你可以利用ndarray这种数据结构非常高效地执行一些数学运算,并且语法风格和Python基本一致。

一、创建数组

1、用np.array()创建数组

通过array函数创建ndarray对象,即将python数组转换为ndarray对象

(1)创建一维数组

ndarray是一个通用的同构数据多维容器,其中的所有的元素必须是相同的类型,numpy会根据输入的实际情况进行转换。

data0 = [2, 4, 6.5, 8]
arr0 = np.array(data0)

(2)创建多维数组

data1 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr1 = np.array(data1)

(3)查看创建的arr0的变量类型

type(arr0)

(4)判断是否是ndarray类型

isinstance(arr0, np.ndarray)

(5)利用dtype关键字,传入合适的数据类型,显式地定义

arr2 = np.array(data1, dtype=np.float)

dtype的类型
np.float
np.int
np.str       S1
np.unicode   U1
np.bool
np.complex

(6)更改数组的数据类型

arr2.astype(np.int)

(7)数组的格式化输出

#对浮点数数组,保留3位有效数字,并禁用科学计数法;小数位数不够,后面不会补0
arr3 = np.array([3.141592653, 9.8], dtype=np.float16)  # 定义一个一维数组
np.set_printoptions(precision=3, suppress=True)

2、创建数组的其他方式

(1)创建一个大小为10的全0数组

np.zeros(10, dtype=np.int)

(2)创建一个大小为5的全1数组

np.ones(5, dtype=np.int)

(3)创建空的(2,3)二维数组

np.empty((2, 3), dtype=np.int)

(4)创建一个大小为3×3的单位矩阵

# np.identity(n, dtype=<type ‘float’>)
np.identity(3, dtype=np.int)
Out: array([[1, 0, 0],
            [0, 1, 0],
            [0, 0, 1]], dtype=int8)

(5)创建3×4的矩形矩阵,并且为1的对角线向右偏移1个单位。

# np.eye(N, M=None, k=0, dtype=float, order='C')
np.eye(N=3, M=4, k=1, dtype=np.int)
Out: array([[0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]], dtype=int)

3、创建等差数组

(1)np.arange(start,stop,step)

指定 start、stop、以及step。arange和range一样,是左闭右开的区间。
也可以只传入一个参数,这种情况下默认start=0,step=1

np.arange(10)
np.arange(1, 10, 1)
np.arange(1.2, 3.8, 0.3)

(2)np.linspace(start, stop[, num=50[, endpoint=True[, retstep=False[, dtype=None]]]]])

start、stop参数,和arange()中一致;
num为待创建的数组中的元素的个数,默认为50
endpoint=True,则为左闭右闭区间,默认为True;endpoint=False,则为左闭右开区间
retstep用来控制返回值的形式。默认为False,返回数组;若为True,则返回由数组和步长组成的元祖

arr_linspace = np.linspace(1, 99, 11, endpoint=False)

(3)ndarray.reshape()

这里定义了一个长度为20的等差数组,然后通过reshape方法,调整数组的大小为5×4

arr_linspace.reshape(5, 4)

4、创建等比数组

(3)geomspace()方法,创建指数等比数列

np.geomspace(start, stop, num=50, endpoint=True, dtype=None)

start和stop,分别为区间的起始和终止值,为强制参数;
num 为待生成等比数列的长度,指定后,程序会自动计算取等比数列的公比;
endpoint默认为True,结果为左闭右必区间。否则为False,左闭右开区间;

np.geomspace(2, 16, 4)

(4)logspace()方法,创建对数等比数列

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)

start:区间起始值为base的start次方
stop:区间终止值为base的stop次方(是否取得到,需要设定参数endpoint)
num:为待生成等比数列的长度。按照对数,即start和stop值进行等分。默认值为50
endpoint:若为True(默认),则可以取到区间终止值,即左闭右闭区间,规则同上

np.logspace(1, 4, num=4, base=2)

4、创建随机数数组

(1)np.random.rand()方法,创建[0, 1)之间的均匀分布的随机数组

np.random.rand(d0, d1, ..., dn)

函数的输入为若干个整数,表示输出随机数的大小为d0×d1× ...×dn
如果没有参数输入,则返回一个float型的随机数

# 产生一个大小为3×2,符合0-1之间的均匀分布的数组
np.random.rand(3, 2)

(2)np.random.uniform()方法,创建[low, high)之间的均匀分布的随机数组

numpy.random.uniform(low=0.0, high=1.0, size=None)

uniform方法可以指定产生随机数的范围[low,high),size为数组的形状,输入格式为整形(一维)或者整形元祖
如果不指定size的话,则返回一个服从该分布的随机数

# 产生一个大小为3×2,符合0-10之间的均匀分布的数组
np.random.uniform(1, 10, (3, 2))

(3)np.random.randn()方法,创建服从标准正态分布的数组(均值为0,方差为1)

np.random.randn(d0, d1, ..., dn)

该方法和rand类似,函数的输入为若干个整数,表示输出随机数的大小为d0×d1× ...×dn
如果没有参数输入,则返回一个服从标准正态分布的float型随机数

# 产生一个大小为3×2,符合标准正态分布的数组
np.random.randn(3, 2)

(4)np.random.normal()方法,创建服从μ=loc,σ=scale的正态分布的数组

np.random.normal(loc=0.0, scale=1.0, size=None)

loc:指定均值 μ; scale:指定标准差 σ
size:输入格式为整形(一维)或者整形元祖,指定了数组的形状

# 产生一个大小为3×2,符合均值为5,标准差为10的正态分布的数组
np.random.normal(5, 10, (3, 2))

(5)np.random.randint()方法,在指定区间[low, high)中离散均匀抽样的数组

np.random.randint(low, high=None, size=None, dtype=np.int64)

函数返回区间[low, high)内的离散均匀抽样,dtype指定返回抽样数组的数据类型,默认为整形
size:输入格式为整形(一维)或者整形元祖,指定了数组的形状

# 在[1, 5)之间离散均匀抽样,数组形状为3行2列
np.random.randint(1, 5, (3, 2))

(6)numpy.random.choice()方法,对具体样本进行有放回或者无放回的抽样

np.random.choice(a, size=None, replace=True, p=None)

从样本a中进行抽样,a可以为数组、列表或者整数,若为整数,表示[0,a)的离散抽样;
replace为False,表示无放回抽样;replace为True,表示有放回抽样
size为生成样本的大小
p为给定数组中元素出现的概率
因为理想情况下,每次投篮都不影响下一次的结果,所以把这个问题归结为有放回的抽样,一共进行10次
shoot_lst用来存储投篮的结果

# 从["命中", "未命中"]中有放回抽样,其中命中的概率为0.65,共抽取10次,返回的格式为为ndarray
np.random.choice(["命中", "未命中"], size=10, replace=True, p=[0.65, 0.35])

二、数组索引与切片

  • 一维数组

    ar1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • 二维数组

    ar2 = [[0, 1, 2],
    [3, 4, 5],
    [6, 7, 8]]

  • 三维数组

    ar3 = [[[1, 2, 3],
    [4, 5, 6]],
    [[7, 8, 9],
    [10, 11, 12]],
    [[13, 14, 15],
    [16, 17, 18]]]

1、索引

array[index]

ar1[1]
# Out: 1, 从0开始,1为第2个

ar1[-1]
# Out: 9,-1为末尾

2、切片

array[start:stop:step=1]

start从0开始计数,stop从1开始计数
start为0时可以省略,stop=len(array)时可以省略

ar11 = ar1[1:8:2]
# Out: [1, 3, 5, 7]

ar22 = ar1[1:3, 1]
ar33 = ar1[1:3, 1, :3]

3、布尔型索引

cities = np.array(["hz", "sh", "hz", "bj"])
arr_rnd = np.arange(4, 4)

(1) 利用数组的比较运算,生成一个布尔类型的数组

cities == "hz"
# Out: array([ True, False, True, False])

利用布尔型数组,进行数组索引;观察索引的规律
我们可以做这样一个推断:布尔型数组的长度要和被索引的轴的长度一致

(2)利用布尔型数组、切片进行1个维度的索引

arr_rnd[cities == "hz"]
# Out:
# array([[0, 1, 2, 3],
#        [8, 9, 10, 11]])
# 即从arr_rnd中取出cities2为True的对应元素

(3)利用布尔型数组、切片进行2个维度的索引

arr_rnd[cities == "hz", :3]
# cities == "hz" 为第一维度
# :3 为第二维度
# Out:
# array([[0,1,2],[8,9,10]])
arr_rnd[:3, cities == "hz"]
# 这样也成立,但不等于arr_rnd[cities == "hz", :3]
# Out:
# array([[0,2],[4,6],[6,8])

(4)将arr_rnd中>0的元素置为0

arr_rnd[arr_rnd > 0] = 0
# Out:
# array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])

(5)实现多个布尔型数组之间的“和”、“或”、“非”运算:

# 非运算 ~
~(cities == "hz")
# Out: array([False,  True, False,  True,  True,  True,  True])

# 和运算 &
(cities == "hz") & (cities == "sz")
# Out: array([False, False, False, False, False, False, False])

# 或运算 |
(cities == "hz") | (cities == "sz")
# Out: array([ True, False,  True, False, False, False,  True])

4、 花式索引

新建4×6的二维数组arr_demo01

arr_demo01 = np.arange(24).reshape(4, 6)

(1)方法1:分别将4个角的元素索引出来,然后把取出来的4个元素,重新组成一个新2×2的数组

arr_method1 = np.array([[arr_demo01[0, 0], arr_demo01[0, -1]],
                        [arr_demo01[-1, 0], arr_demo01[-1, -1]]])
# Out:
# array([[0, 5],
#        [18, 23]])

(2)方法2:利用布尔索引,可以同时索引不连续的行。分别对axis 0方向和axis 1方向进行索引。但是需要注意的是,得分2次索引;

arr_method2 = arr_demo01[[True, False, False, True]][:, [True, False, False, False, False, True]]
# Out:
# array([[0, 5],
#        [18, 23]])

花式索引外围必须有一个中括号[],即索引值不为整数,而是数组或其他类型数据
我们传入一个整数数组,对axis 0方向进行索引,并且索引结果的顺序和传入的整数数组一一对应:

arr_demo01[[2, 0]]
# Out:
# array([[12, 13, 14, 15, 16, 17],
#        [0, 1, 2, 3, 4, 5]])

如果同时传入2个整数数组,中间用逗号分开。 那么这两个数组会以两两配对的形式,对元素进行索引。而并不是一个矩形状的索引区域!
即arr_demo01[0,0]和arr_demo01[-1,-1],类似arr_demo01[0][0]和arr_demo01[-1][-1]

arr_demo01[[0, -1], [0, -1]]
# Out:
# array([ 0, 23])

(3)方法3:分别传入4个角的坐标,请朋友们注意观察传入的2个整数数组的规律

arr_demo01[[0, 0, -1, -1], [0, -1, 0, -1]]
# 即arr_demo01[0,0]、arr_demo01[0,-1]、arr_demo01[-1,0]和arr_demo01[-1,-1]
# Out: array([ 0,  5, 18, 23])

arr_demo01[[0, 0, -1, -1], [0, -1, 0, -1]].reshape(2, 2)
# Out:
# array([[0, 5],
#        [18, 23]])

(4)方法4:利用花式索引和切片混用。也是通过连续2次索引,得到一个矩形状的区域

arr_demo01[[0, -1]][:, [0, -1]]
# 第一次索引 [[0, -1]]
# Out:
# array([[0, 1, 2, 3, 4, 5],
#        [18, 19, 20, 21, 22, 23]])
# 第二次索引 [:, [0, -1]]
# Out:
# array([[0, 5],
#        [18, 23]])

(5)方法5:利用函数np.ix_,构建矩形索引器:

# 即arr_demo01[0,0]、arr_demo01[0,-1]、arr_demo01[-1,0]和arr_demo01[-1,-1]
arr_demo01[np.ix_([0, -1], [0, -1])]
# Out:
# array([[0, 5],
#        [18, 23]])

三、数组的运算

1、数组与标量之间的运算

arr = np.array([[1, 2, 3], [4, 5, 6]])

通常我们把单独的数叫做标量,数组可以直接与标量进行计算,计算逻辑会自动传播到数组的全部元素中。

arr + 5
arr - 5
arr * 5
arr / 5
arr ** 5

2、数组的通用函数运算

(1)四则运算

最简单的通用函数就是数组与数组的四则运算。但是在进行数组的四则运算的时候,我们需要保证二者的维数一样
数组对应位置的元素加减乘除,并不是高等数学上的矩阵运算。
Numpy也封装了针对四则运算的函数

arr + arr  # np.add(arr, arr)
arr - arr  # np.subtract(arr, arr)
arr * arr  # np.multiply(arr, arr)
arr / arr  # np.divide(arr, arr)

(2)一元函数

arr_rnd = np.random.normal(5, 10, (3, 4))

对数组进行四舍五入运算。需要注意的是,结果数组仍然保留了输入数组的dtype属性

np.rint(arr_rnd)

# 函数                        说明
# abs,fabs                 计算绝对值,对于非负数值,可以使用更快的fass
# sqrt,square,exp           求各元素的平方根、平方、指数ex
# log,log10,log2,log1p  分别计算自然对数(底数为e)、底数为10的log、底数为2的log、log(1+x)
# sign                      计算各元素的正负号:1(整数)、0(零)、-1(负数)
# ceil                      计算各元素的、大于等于该值的最小整数
# floor                     计算各元素的、大于等于该值的最大整数
# rint                      将各元素值四舍五入到最接近的整数,并保留dtype
# modf                      把数组的小数和整数部分以两个独立的数组分别返回
# isnan                     判断各元素是否为空NaN,返回布尔型
# cos,cosh,sin,sinh,tan,tanh    普通型和双曲型三角函数

(3)二元运算

利用随机函数,产生2个数组

x = np.random.normal(5, 10, (3, 1))  # np.random.normal(5, 10, 3)
y = np.random.normal(5, 10, (3, 1))

计算,比较元素级的最大值

np.maximum(x, y)

计算,比较元素级的最小值

np.minimum(x, y)

计算,执行元素级的比较

np.greater(x, y)

# 函数                                    说明
# maximum,fmax                          计算元素级的最大值,fmax自动忽略空值NaN
# minimum,fmin                          计算元素级的最小值,fmin自动忽略空值NaN
# greater,greater_equal             执行元素级的比较,生产布尔型数组。效果相当于>,≥
# less,less_equal                       执行元素级的比较,生产布尔型数组。效果相当于<,≤
# equal,not_equal                       执行元素级的比较,生产布尔型数组。效果相当于==,!=
# logical_and,logical_or,logic_xor  执行元素级的逻辑运算,相当于执行运算符&、|、^

3、数组的线性代数运算

(1)矩阵乘法

矩阵的乘法,输入的2个数组的维度需要满足矩阵乘法的要求,否则会报错;

# arr.T表示对arr数组进行转置
# np.dot表示对输入的两个数组进行矩阵乘法运算
np.dot(arr, arr.T)
# Out:
# array([[14, 32],
#        [32, 77]])

(2)numpy.linalg工具:矩阵运算

# 函数    说明
# diag  以一维数组的形式返回方阵的对角线(或非对角线)元素,或将一维数组转换为方阵
# trace 计算对角线元素的和
# det   计算矩阵行列式
# eig   计算方阵的本征值和本征向量
# inv   计算方阵的逆
# pinv  计算矩阵的Moore-Penrose伪逆
# qr    计算QR分解
# svd   计算奇异值分解(SVD)
# solve 解线性方程
# lstsq 计算Ax=b的最小二乘解

4、数组的聚合函数运算

# 常用的聚合函数
# 函数            说明
# sum           求和运算
# cumsum        累积求和运算
# min           求最小值
# max           求最大值
# mean          求均值
# median        求中位数
# var           求方差
# std           求标准差

5、Numpy运算方向axis详解

我们把二维数组的垂直方向定义为axis 0轴,水平方向为axis 1轴。
当我们在对Numpy进行运算时,我们把axis=0指定为垂直方向的计算,axis=1指定为水平方向的运算。
规定求最大值的方向为垂直方向即可,即axis=0

np.max(arr_rnd, axis=0)

6、利用Numpy实现条件判断

where 函数中输入3个参数,分别是判断条件、为真时的值,为假时的值
在Numpy中,空值是一种新的数据格式,我们用np.nan产生空值

np.where(arr_rnd < 5, np.nan, arr_rnd)

7、np.frompyfunc

如果还是找不到合适的函数来实现自己的目的,那不妨自己写一个,也很简单。
我们只需要利用frompyfunc函数,将计算单元素的函数转换成,能对数组的每个元素进行操作的函数即可。
frompyfunc函数有三个输入参数,分别是待转化的函数、函数的输入参数的个数、函数的返回值的个数

四、Python 引用

a = ["a", "b", "c"]
b = a
a is b
# Out:
#     True
# b是a的引用,id(a)=id(b),id(a)为a的地址

1、Python的深拷贝与浅拷贝

import copy
m = ["Jack", "Tom", "Brown"]

2、深拷贝

n = copy.deepcopy(m)
# 判断二者是否相等,结果显而易见
m == n
# Out: True
# 判断二者是否具有同一性,答案为否。也就是说,列表m和列表n是存储在不同的地址里。
m is n
# Out: False

3、浅拷贝

n = copy.copy(m)
# 判断二者是否相等,结果显而易见
m == n
# 判断浅拷贝前后是否具有同一性,答案是不具备同一性
m is n
# Out: False

4、深拷贝和浅拷贝的区别

# students列表的长度为3,其中首位为字符串,其他位均为列表
students = ["Class 1", ["Jack", 178, 120], ["Tom", 174, 109]]
students_c = copy.copy(students)

# 查看内嵌的列表是否具备同一性
students[1] is students_c[1]
# Out: True

# 尝试更改students中某位学生的信息,通过测试更改后的students和students_c
students[1][1] = 180
students
# Out: ['Class 1', ['Jack', 180, 120], ['Tom', 174, 109]]
students_c
# Out: ['Class 1', ['Jack', 180, 120], ['Tom', 174, 109]]
# 发现:students_c也跟着改变了,这说明对于嵌套列表里的可变元素(深层次的数据结构),浅拷贝并没有进行拷贝,只是对其进行了引用

# 我们接着尝试更改students中的班级信息
students[0] = "Class 2"
students
# Out: ['Class 2', ['Jack', 180, 120], ['Tom', 174, 109]]
students_c
# Out: ['Class 1', ['Jack', 180, 120], ['Tom', 174, 109]]
# 发现:students_c没有发生变化,这说明对于嵌套列表里的不可变元素,浅拷贝和深拷贝效果一样

1、由不可变对象组成的列表,浅拷贝和深拷贝效果一样,拷贝前后互相独立,互不影响;
2、当列表中含有可变元素时,浅拷贝只是建立了一个由该元素指向新列表的引用(指针),当该元素发生变化的时候,拷贝后的对象也会发生变化;
3、深拷贝完全不考虑节约内存,浅拷贝则相对来讲比较节约内存,浅拷贝仅仅是拷贝第一层元素。

切片其实就是对源列表进行部分元素的浅拷贝!

5、视图view是对数据的引用,通过该引用,可以方便地访问、操作原有数据,但原有数据不会产生拷贝。

arr_ = np.arange(12).reshape(3,4)
view_ = arr_.view()
view_.shape = (4, 3)  # 更改维度
slice_ = arr_[:6]

视图是新建了一个引用,如果我们对视图进行修改,它会影响到原始数据,因为它们的物理内存在同一位置。
但是更改视图的维数,并不会引起原始数组的变化

6、副本是对数据的完整拷贝(Python中深拷贝的概念)。

如果我们对副本进行修改,它不会影响到原始数据,它们的物理内存不在同一位置。
Numpy建立副本的方法稍有不同。
方法一,是利用Numy自带的copy函数;

copy_ = arr_.copy()
# 比较发现,建立副本后,二者互不影响。

方法二,是利用deepcopy()函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335