Numpy的介绍和使用

介绍

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。

NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:

  • 一个强大的N维数组对象 ndarray
  • 广播功能函数
  • 整合 C/C++/Fortran 代码的工具
  • 线性代数、傅里叶变换、随机数生成等功能

Ndarray

NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

ndarray 对象是用于存放同类型元素的多维数组。

ndarray 中的每个元素在内存中都有相同存储大小的区域。

ndarray 内部由以下内容组成:

  • 一个指向数据(内存或内存映射文件中的一块数据)的指针。
  • 数据类型或 dtype,描述在数组中的固定大小值的格子。
  • 一个表示数组形状(shape)的元组,表示各维度大小的元组。
  • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。

ndarray 的内部结构:

跨度可以是负数,这样会使数组在内存中后向移动,切片中 obj[::-1] 或 obj[:,::-1] 就是如此。

创建一个 ndarray 只需调用 NumPy 的 array 函数即可:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
名称描述
object数组或嵌套的数列
dtype数组元素的数据类型,可选
copy对象是否需要复制,可选
order创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok默认返回一个与基类类型一致的数组
ndmin指定生成数组的最小维度

import numpy as np

score = np.array([[80, 89, 86, 67, 79],
                  [78, 97, 89, 67, 81],
                  [90, 94, 78, 67, 74],
                  [91, 91, 90, 67, 69],
                  [76, 87, 75, 67, 86],
                  [70, 79, 84, 67, 84],
                  [94, 92, 93, 67, 64],
                  [86, 85, 83, 67, 80]])
print(score)
print(type(score))

输出

[[80 89 86 67 79]
 [78 97 89 67 81]
 [90 94 78 67 74]
 [91 91 90 67 69]
 [76 87 75 67 86]
 [70 79 84 67 84]
 [94 92 93 67 64]
 [86 85 83 67 80]]
<class 'numpy.ndarray'>

ndarray与Python原生list运算效率对比

# ndarray和list效率对比
python_list = []
start_time = datetime.datetime.now()
for i in range(100000000):
    python_list.append(random.random())
end_time = datetime.datetime.now()
print("list的运行时间:", end_time-start_time)

start_time = datetime.datetime.now()
ndarray_list = np.array(python_list)
end_time = datetime.datetime.now()
print("ndarray的运行时间:", end_time-start_time)

输出

list的运行时间: 0:00:22.598421
ndarray的运行时间: 0:00:04.590315

啧啧啧,这能比???

为啥Ndarray这么快

  1. 内存块风格

    ndarray到底跟原生python列表有什么不同呢,请看一张图:

    从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。

    这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。

  2. ndarray支持并行化运算(向量化运算)

    numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算

  3. 效率远高于纯Python代码

    Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。


Ndarray的属性

属性说明
ndarray.ndim秩,即轴的数量或维度的数量
ndarray.shape数组的维度,对于矩阵,n 行 m 列
ndarray.size数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtypendarray 对象的元素类型
ndarray.itemsizendarray 对象中每个元素的大小,以字节为单位
ndarray.flagsndarray 对象的内存信息
ndarray.realndarray元素的实部
ndarray.imagndarray 元素的虚部
ndarray.data包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
score = np.array([[80, 89, 86, 67, 79],
                  [78, 97, 89, 67, 81],
                  [90, 94, 78, 67, 74],
                  [91, 91, 90, 67, 69],
                  [76, 87, 75, 67, 86],
                  [70, 79, 84, 67, 84],
                  [94, 92, 93, 67, 64],
                  [86, 85, 83, 67, 80]])
print(type(score))

print(score.shape)  # (8, 5)
print(score.ndim)  # 2
print(score.size)  # 40
print(score.dtype)  # int32 默认
print(score.itemsize)  # 4

输出

<class 'numpy.ndarray'>
(8, 5)
2
40
int32
4

Ndarray数据类型

名称描述
bool_布尔型数据类型(True 或者 False)
int_默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc与 C 的 int 类型一样,一般是 int32 或 int 64
intp用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8字节(-128 to 127)
int16整数(-32768 to 32767)
int32整数(-2147483648 to 2147483647)
int64整数(-9223372036854775808 to 9223372036854775807)
uint8无符号整数(0 to 255)
uint16无符号整数(0 to 65535)
uint32无符号整数(0 to 4294967295)
uint64无符号整数(0 to 18446744073709551615)
float_float64 类型的简写
float16半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_complex128 类型的简写,即 128 位复数
complex64复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128复数,表示双 64 位浮点数(实数部分和虚数部分)

numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。

import numpy as np
data = np.array([1.1, 1.2, 1.3], dtype=np.float32)
print(data)
print(data.dtype)

输出

[1.1 1.2 1.3]
float32

Ndarray常用操作

生成0和1数组
zero = np.zeros([3, 4])
print(zero)
print("元素类型", zero.dtype)

print("------------------")

one = np.ones([3, 4], dtype=np.int_)
print(one)

输出

[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
元素类型 float64
------------------
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

从现有的数组中生成
print("-----array(深拷贝)-----")
data01[0, 3] = 100
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data01):", data01[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----asarray(浅拷贝)-----")
data02[0, 3] = 110
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data02[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----copy(深拷贝)-----")
data03[0, 3] = 120
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data03[0])
print("array产生的数组修改后的数据(score):", score[0])

输出

-----array(深拷贝)-----
原始数据: [80 89 86 67 79]
array产生的数组修改后的数据(data01)[ 80  89  86 100  79]
array产生的数组修改后的数据(score)[80 89 86 67 79]
-----asarray(浅拷贝)-----
原始数据: [ 80  89  86 110  79]
array产生的数组修改后的数据(data02)[ 80  89  86 110  79]
array产生的数组修改后的数据(score)[ 80  89  86 110  79]
-----copy(深拷贝)-----
原始数据: [ 80  89  86 110  79]
array产生的数组修改后的数据(data02)[ 80  89  86 120  79]
array产生的数组修改后的数据(score)[ 80  89  86 110  79]

生成固定范围的数组
arr = np.linspace(0, 10, 5)  # [0, 10] 等距离,num默认是50
print(arr)
arr = np.arange(0, 10, 2.5)  #  [a, b) c是步长,step默认是1
print(arr)

输出

[ 0.   2.5  5.   7.5 10. ]
[0.  2.5 5.  7.5]

均匀分布
data = np.random.uniform(-1, 1, 1000000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


正态分布
data = np.random.normal(1.75, 0.1, 100000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


案例:随机生成8只股票2周的交易日涨幅数据
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
print(stock_change)
# 获取第一个股票的前3个交易日的涨跌幅数据
stock_change[0, :3]

输出

[[-0.03469926,  1.68760014,  0.05915316,  2.4473136 , -0.61776756,
  -0.56253866, -1.24738637,  0.48320978,  1.01227938, -1.44509723],
 [-1.8391253 , -1.10142576,  0.09582268,  1.01589092, -1.20262068,
  0.76134643, -0.76782097, -1.11192773,  0.81609586,  0.07659056],
 [-0.74293074, -0.7836588 ,  1.32639574, -0.52735663,  1.4167841 ,
  2.10286726, -0.21687665, -0.33073563, -0.46648617,  0.07926839],
 [ 0.45914676, -0.78330377, -1.10763289,  0.10612596, -0.63375855,
  -1.88121415,  0.6523779 , -1.27459184, -0.1828502 , -0.76587891],
 [-0.50413407, -1.35848099, -2.21633535, -1.39300681,  0.13159471,
  0.65429138,  0.32207255,  1.41792558,  1.12357799, -0.68599018],
 [ 0.3627785 ,  1.00279706, -0.68137875, -2.14800075, -2.82895231,
  -1.69360338,  1.43816168, -2.02116677,  1.30746801,  1.41979011],
 [-2.93762047,  0.22199761,  0.98788788,  0.37899235,  0.28281886,
  -1.75837237, -0.09262863, -0.92354076,  1.11467277,  0.76034531],
 [-0.39473551,  0.28402164, -0.15729195, -0.59342945, -1.0311294 ,
  -1.07651428,  0.18618331,  1.5780439 ,  1.31285558,  0.10777784]]


[ 0.75372007  0.37205739 -0.45823456]

形状修改
print(stock_change.reshape((10, 8)).shape)
stock_change.resize((10, 8))
print(stock_change.shape)
print(stock_change.T.shape)

输出

(10, 8)
(10, 8)
(8, 10)

序列化
print(stock_change.tostring())

输出

b'\x1cDY5\xba\xf6\xfd?\x1f!\xa4"H\x12\xd3\xbf\x8a\xb8\n"n\x86\xe8?V\xc8E\x01\x0c\xba\xe4?#\xa5\xcd4\xfd8\xdc?-\xfb\x01\x9by\xee\xb5?\x97\xca\xc6\xd3\xaf;\xe0?\x9b;\x1f\xd9d\x17\xfb\xbfY\x10\xca\x9c\x99D\xe5?d\xbf\x93\xfe\xfbr\xf1\xbfQ\x89\x0f\xca\x88:\xf7\xbfo\xdd22=\x9d\xf2\xbf\xa1,\xbc\xc7>B\xf0\xbfl\x8d\......省略

数组去重
data = np.array([[1,2,3,4],[3,4,5,6]])
print(np.unique(data))
print(set(data.flatten()))

输出

[1 2 3 4 5 6]
{1, 2, 3, 4, 5, 6}


Ndarray运算

逻辑运算
import numpy as np

stock_change = np.random.normal(1.5, 2, (8, 10))
# 逻辑判断, 如果涨跌幅大于等于0.5就标记为True 否则为False
print(stock_change >= 0.5)
# 修改所有涨幅小于0.5的为0.5
stock_change[stock_change < 0.5] = 0.5

输出

[[False  True  True  True False  True False  True False  True]
 [False  True  True  True  True  True False  True  True False]
 [ True  True  True False  True  True False  True False False]
 [ True  True False  True  True  True False False  True False]
 [ True  True  True False  True  True  True False False  True]
 [ True  True  True  True  True  True  True  True  True False]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]]

where运算
temp = stock_change[:4, :4]
print(temp)
print(np.where(temp > 0.5, 1, 0))
# 判断前四个股票前四天的涨跌幅 大于0.5并且小于1的,换为1,否则为0
# 判断前四个股票前四天的涨跌幅 大于0.5或者小于-0.5的,换为1,否则为0
print(np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0))
print(np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0))

输出

[[ 2.11334994  2.75371732 -1.45919878 -0.54644526]
 [ 2.50898042  2.49334823  3.46757975  1.67814258]
 [-1.63742684  2.21757841  0.51642822 -1.10437119]
 [ 1.08439702  0.2920416   0.31753524  2.20334352]]

[[1 1 0 0]
 [1 1 1 1]
 [0 1 1 0]
 [1 0 0 1]]

[[0 0 0 0]
 [0 0 0 0]
 [0 0 1 0]
 [0 0 0 0]]

[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]
 [1 0 0 1]]

最大值最小值
print(np.max(stock_change))
# 0代表列,1代表行
print(np.max(stock_change, axis=0))
print(np.max(stock_change, axis=1))
# 最大值的位置
print(np.argmax(stock_change, axis=0))
print(np.argmax(stock_change, axis=1))

输出

6.693146605729187
[6.69314661 2.82844572 5.81205157 5.35317406 4.01567427 5.66452237
 2.61476055 3.99797746 4.19418698 5.17729721]
[4.48925181 4.29683647 3.99797746 2.09293751 5.81205157 5.35317406
 5.17729721 6.69314661]
[7 4 4 5 6 7 2 2 5 6]
[5 0 7 1 2 3 9 0]

广播机制

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是 1
A (3d array): 		256 × 256 × 3
B (1d array): 		   		    3
Result (3d array):   256 × 256 × 3
    
A (4d array): 		9 × 1 × 7 × 1
B (3d array): 		    8 × 1 × 5
Result (4d array):   9 × 8 × 7 × 5
    
A (2d array): 		5 × 4
B (1d array): 		    1
Result (2d array):   5 × 4
    
A (3d array): 		15 × 3 × 5
B (3d array): 		15 × 1 × 1
Result (3d array):   15 × 3 × 5

矩阵运算

两种方法存储矩阵

  1. ndarray 二维数组
  2. matrix数据结构

data = np.array([[80, 86],
                [82, 80],
                [85, 78],
                [90, 90],
                [86, 82],
                [82, 90],
                [78, 80],
                [92, 94]])

# matrix存储矩阵
data_mat = np.mat([[80, 86],
                    [82, 80],
                    [85, 78],
                    [90, 90],
                    [86, 82],
                    [82, 90],
                    [78, 80],
                    [92, 94]])

weights = np.array([[2], [3]])
weights_mat = np.mat([[2], [3]])
# 矩阵乘法
print(np.matmul(data, weights))
print(np.dot(data, weights))
print(data @ weights)
print(data_mat * weights_mat)

输出

[[418]
 [404]
 [404]
 [450]
 [418]
 [434]
 [396]
 [466]]
.....都是一样的,就省略了

合并
data_1 = np.array([1, 2, 3])
data_2 = np.array([5, 6, 7])
print(np.hstack((data_1, data_2)))  # 水平拼接 horizontally
print(np.vstack((data_1, data_2)))  # 竖直拼接 vertically

data_1 = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
data_2 = np.array([[5, 6, 7]])
print(np.concatenate((data_1, data_2), axis=0))  # 自定义合并
print(np.concatenate((data_1, data_2.T), axis=1))  # 自定义合并

输出

[1 2 3 5 6 7]

[[1 2 3]
 [5 6 7]]

[[1 2 3]
 [2 3 4]
 [3 4 5]
 [5 6 7]]

[[1 2 3 5]
 [2 3 4 6]
 [3 4 5 7]]

分割
print("-----分割-----")
data = np.arange(0, 10)
print(np.split(data, 2))
print(np.split(data, [4, 6]))

输出

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

IO操作和数值处理

文件内容

id,value1,value2,value3
1,123,1.4,23
2,110,,18
3,,2.1,19

代码

test = np.genfromtxt("test.csv", delimiter=",")
print(test)
print(type(test[0, 0]))

输出

[[  nan   nan   nan   nan]
 [  1.  123.    1.4  23. ]
 [  2.  110.    nan  18. ]
 [  3.    nan   2.1  19. ]]
<class 'numpy.float64'>

我们可以看到,出现了缺失值nan。

为什么呢?当我们读取本地的文件为float的时候,如果数据类型不对(或者为None),就会出现nan

上方的[0,0]明明是字符串,但是是按float读取的,就出现了nan。这是由ndarray的数据结构决定的


总结

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值