Numpy学习笔记
1 Numpy介绍
1.1 Numpy的优势
Numpy(Numerical Python)是一个开源的Python科学计算库,本身是由C语言开发,用于快速处理任意维度的数组。Numpy支持常见的数组和矩阵操作。对于同样的数值计算任务,使用Numpy比直接使用Python要简洁的多。
-
Numpy优势
思考:使用Python列表可以存储一维数组,通过列表的嵌套可以实现多维数组,那么为什么还需要使用Numpy的ndarray呢?
在这里我们通过一段代码运行来体会到ndarray的好处:
import random import time import numpy as np a = [] for i in range(100000000): a.append(random.random()) # 通过%time魔法方法, 查看当前行的代码运行一次所花费的时间 %time sum1=sum(a) b=np.array(a) %time sum2=np.sum(b)
其中第一个时间显示的是使用原生Python计算时间,第二个内容是使用numpy计算时间:
CPU times: user 852 ms, sys: 262 ms, total: 1.11 s Wall time: 1.13 s CPU times: user 133 ms, sys: 653 µs, total: 133 ms Wall time: 134 ms
Numpy专门针对ndarray的操作和运算进行了设计,所以数组的存储效率和输入输出性能远优于Python中的嵌套列表,数组越大,Numpy的优势就越明显。
-
内存风格
-
list:分离式存储,存储内容多样化
-
ndarray:一体式存储,存储类型必须一样
从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。
这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素。
-
ndarray支持并行化运算(向量化运算)
-
效率远高于纯Python代码
Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制
-
2 ndarray的创建与数据类型
2.1 ndarray介绍
NumPy提供了一个N维数组类型ndarray,它描述了相同类型的“items”的集合。具有矢量算术运算能力和复杂的广播能力,并具有执行速度快和节省空间的特点
注:ndarray的下标从0开始,且数组里的所有元素必须是相同类型
-
属性&形状
属性名字 属性解释 ndarray.shape 数组维度的元组 ndarray.ndim 数组维数 ndarray.size 数组中的元素数量 ndarray.itemsize 一个数组元素的长度(字节) ndarray.dtype 数组元素的类型 -
创建数组
# 创建不同形状的数组 a = np.array([[1,2,3],[4,5,6]]) b = np.array([1,2,3,4]) c = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])
打印出形状:
a.shape >>> (2,3) # 二维数组 b.shape >>> (4,) # 一维数组 c.shape >>> (2,2,3) # 三维数组
-
-
类型
dtype是numpy.dtype类型,先看看对于数组来说都有哪些类型
名称 描述 简写 np.bool 用一个字节存储的布尔类型(True或False) ‘b’ np.int8 一个字节大小,-128 至 127 ‘i’ np.int16 整数,-32768 至 32767 ‘i2’ np.int32 整数,-231 至 232 -1 ‘i4’ np.int64 整数,-263 至 263 - 1 ‘i8’ np.uint8 无符号整数,0 至 255 ‘u’ np.uint16 无符号整数,0 至 65535 ‘u2’ np.uint32 无符号整数,0 至 2 ** 32 - 1 ‘u4’ np.uint64 无符号整数,0 至 2 ** 64 - 1 ‘u8’ np.float16 半精度浮点数:16位,正负号1位,指数5位,精度10位 ‘f2’ np.float32 单精度浮点数:32位,正负号1位,指数8位,精度23位 ‘f4’ np.float64 双精度浮点数:64位,正负号1位,指数11位,精度52位 ‘f8’ np.complex64 复数,分别用两个32位浮点数表示实部和虚部 ‘c8’ np.complex128 复数,分别用两个64位浮点数表示实部和虚部 ‘c16’ np.object_ python对象 ‘O’ np.string_ 字符串 ‘S’ np.unicode_ unicode类型 ‘U’ -
创建数组的时候指定类型
a = np.array([[1, 2, 3],[4, 5, 6]], dtype=np.float32) a.dtype dtype('float32') arr = np.array(['python', 'tensorflow', 'scikit-learn', 'numpy'], dtype = np.string_) arr array([b'python', b'tensorflow', b'scikit-learn', b'numpy'], dtype='|S12')
注意:若不指定,整数默认int64,小数默认float64
-
2.2 ndarray的创建
-
生成0和1的数组
np.ones(shape[, dtype, order])
np.ones_like(a[, dtype, order, subok])
np.zeros(shape[, dtype, order])
np.zeros_like(a[, dtype, order, subok])
zero = np.zeros([3, 4]) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.]])
-
从现有数组生成
np.array(object[, dtype, copy, order, subok, ndmin])
np.asarray(a[, dtype, order])
a = np.array([[1,2,3],[4,5,6]]) # 从现有的数组当中创建 a1 = np.array(a) # 相当于索引的形式,并没有真正的创建一个新的 a2 = np.asarray(a)
-
生成固定范围的数组
np.linspace (start, stop, num, endpoint):生成等间隔的序列
numpy.arange(start,stop, step, dtype):创建等差数组-指定步长
numpy.logspace(start,stop, num):创建等比数列
numpy.shuffle():将打乱数组序列(类似于洗牌)
参数说明:
start 序列的起始值 stop 序列的终止值, num 要生成的等间隔样例数量,默认为50 endpoint 序列中是否包含stop值,默认为ture
举例:
# 生成等间隔的数组 np.linspace(0, 100, 11) # 结果 array([ 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100.]) # np.arange() np.arange(10, 50, 2) # 结果 array([10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48]) # np.logspace():生成10^x np.logspace(0, 2, 3) # 结果 array([ 1., 10., 100.]) # np.shuffle(np.arange(15)) [ 5 8 1 7 4 0 12 9 11 2 13 14 10 3 6]
-
生成随机数组
np.random模块
-
均匀分布
np.random.rand(d0, d1, …, dn),返回**[0.0,1.0)**内的一组均匀分布的数
np.random.uniform(*low=0.0*, *high=1.0*, *size=None*),功能:从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high。low: 采样下界,float类型,默认值为0;high: 采样上界,float类型,默认值为1;size: 输出样本数目,为int或元组(tuple)类型,例如,size=(m,n,k), 则输出mnk个样本,缺省时输出1个值。返回值:ndarray类型,其形状和参数size中描述一致。
np.random.randint(low, high=None, size=None, dtype=‘l’)。从一个均匀分布中随机采样,生成一个整数或N维整数数组,取数范围:若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数。
# 生成均匀分布的随机数 x1 = np.random.uniform(-1, 1, 100000000) # 结果 array([ 0.22411206, 0.31414671, 0.85655613, ..., -0.92972446, 0.95985223, 0.23197723])
-
正态分布
正态分布是一种概率分布。正态分布是具有两个参数μ和σ的连续型随机变量的分布,第一参数μ是服从正态分布的随机变量的均值,第二个参数σ是此随机变量的方差,所以正态分布记作N(μ,σ )。
-
特点
μ决定了其位置,其标准差σ决定了分布的幅度。当μ = 0,σ = 1时的正态分布是标准正态分布。
-
方差
是在概率论和统计方差衡量一组数据时离散程度的度量
其中M为平均值,n为数据总个数,S为标准差,S^2可以理解一个整体为方差。
标准差和方差的意义:
可以理解成数据的一个离散程度的衡量
-
创建
np.random.randn(d0, d1, …, dn)。从标准正态分布中返回一个或多个样本值
**np.random.normal(*loc=0.0*, *scale=1.0*, *size=None*)**loc:float此概率分布的均值(对应着整个分布的中心centre)。scale:float此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)。size:int or tuple of ints 输出的shape,默认为None,只输出一个值。
np.random.standard_normal(size=None)。返回指定形状的标准正态分布的数组。
案例:随机生成8只股票2周的交易日涨幅数据。
分析:8只股票,**两周(10天)**的涨跌幅数据,如何获取?
- 两周的交易日数量为:2 X 5 =10
- 随机生成涨跌幅在某个正态分布内,比如均值0,方差1
# 创建符合正态分布的8只股票10天的涨跌幅数据 stock_change = np.random.normal(0, 1, (8, 10)) # 结果 array([[-0.03862668, -1.46128096, -0.75596237, 0.89737022, -1.86978433, 0.38845392, 1.14856354, -1.10912275, 1.28900021, -0.86801677], [ 1.8701446 , 0.50407342, -0.74396489, -1.69641331, -0.89969227, 2.42459765, 0.78987443, -0.82935223, 0.82546455, 0.40524289], [-1.7365776 , -0.81501515, -1.08974743, -1.4138561 , 0.85495155, 0.30076624, -2.0813311 , 1.52886975, 0.62945643, -1.48714683], [-1.12084983, -0.63070289, -0.20677245, -0.49096973, -0.40551104, -0.46320893, -0.73190969, 0.00392486, 2.524498 , 0.25843191], [ 0.05001371, 0.52267878, 1.31974783, 0.64840953, 1.56360431, -0.79233575, 1.47275167, 0.61070343, -0.33247221, -0.57492172], [ 0.7092757 , 0.00928591, 0.27008373, 0.79050681, -0.95887888, 0.03661459, 0.81303927, -0.54139691, 0.69623969, 0.06570421], [-1.40481949, 0.49151272, 1.01992235, 1.89152928, -0.76415623, 0.3100241 , 1.27156806, -1.76199057, -0.77419965, -0.17574386], [-0.21745814, -1.78433763, -0.7953073 , 0.4765644 , -0.2589575 , 0.97014013, 1.67321489, 1.73370987, 0.29886514, 1.27186522]])
-
-
-
形状修改
让刚才的股票行、日期列反过来,变成日期行,股票列
-
ndarray.reshape(shape[, order]) Returns an array containing the same data with a new shape.
# 在转换形状的时候,一定要注意数组的元素匹配 stock_change.reshape([10, 8]) stock_change.reshape([-1,20]) # 数组的形状被修改为: (4, 20), -1: 表示通过待计算
-
ndarray.resize(new_shape[, refcheck]) Change shape and size of array in-place.
stock_change.resize([10, 8])
-
ndarray.T 数组的转置
stock_change.shape (10, 8) stock_change.T.shape (8, 10)
-
3 ndarray的索引、切片
3.1 一维数组的索引与切片
与Python的列表索引功能相似
-
示例代码:
# 一维数组 arr1 = np.arange(10) print(arr1) print(arr1[2:5]) # 结果 [0 1 2 3 4 5 6 7 8 9] [2 3 4]
#### 3.2 多维数组的索引与切片
> arr[r1:r2, c1:c2]
>
> arr[1,1] 等价 arr[1][1]
>
> [:] 代表某个维度的数据
- 示例代码:
```python
# 多维数组
arr2 = np.arange(12).reshape(3,4)
print(arr2)
print(arr2[1])
print(arr2[0:2, 2:])
print(arr2[:, 1:3])
# 结果
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[4 5 6 7]
[[2 3]
[6 7]]
[[ 1 2]
[ 5 6]
[ 9 10]]
3.3 条件索引
布尔值多维数组:arr[condition],condition也可以是多个条件组合。
注意,多个条件组合要使用 & | 连接,而不是Python的 and or。
-
示例代码
# 找出 data_arr 中 2005年后的数据 data_arr = np.random.rand(3,3) print(data_arr) year_arr = np.array([[2000, 2001, 2000], [2005, 2002, 2009], [2001, 2003, 2010]]) filtered_arr = data_arr[(year_arr <= 2005) & (year_arr % 2 == 0)] print(filtered_arr) # 结果 [[ 0.53514038 0.93893429 0.1087513 ] [ 0.32076215 0.39820313 0.89765765] [ 0.6572177 0.71284822 0.15108756]] [ 0.53514038 0.1087513 0.39820313]
4 ndarray运算
4.1 计算函数
ceil()
: 向上最接近的整数,参数是 number 或 arrayfloor()
: 向下最接近的整数,参数是 number 或 arrayrint()
: 四舍五入,参数是 number 或 arrayisnan()
: 判断元素是否为 NaN(Not a Number),参数是 number 或 arraymultiply()
: 元素相乘,参数是 number 或 arraydivide()
: 元素相除,参数是 number 或 arrayabs()
:元素的绝对值,参数是 number 或 arraywhere(condition, x, y)
: 三元运算符,x if condition else y,复合逻辑需要结合np.logical_and和np.logical_or使用
# 重新生成8只股票10个交易日的涨跌幅数据
stock_change = np.random.normal(0, 1, (8, 10))
stock_change = stock_change[0:5, 0:5]
# 逻辑判断, 如果涨跌幅大于0.5就标记为True 否则为False
stock_change > 0.5
array([[ True, False, False, True, False],
[ True, True, False, False, False],
[ True, False, True, False, True],
[False, True, False, False, False],
[False, False, False, True, True]])
# BOOL赋值, 将满足条件的设置为指定的值-布尔索引
stock_change[stock_change > 0.5] = 1
array([[ 1. , -0.72404879, -1.33045773, 1. , 0.3869043 ],
[ 1. , 1. , 0.20815446, -1.67860823, 0.06612823],
[ 1. , 0.42753488, 1. , -0.24375089, 1. ],
[-0.971945 , 1. , -0.95444661, -0.2602084 , -0.48736497],
[-0.32183056, -0.92544956, -0.42126604, 1. , 1. ]])
# 判断前四个股票前四天的涨跌幅 大于0的置为1,否则为0
temp = stock_change[:4, :4]
np.where(temp > 0, 1, 0)
# 判断前四个股票前四天的涨跌幅 大于0.5并且小于1的,换为1,否则为0
np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0)
# 判断前四个股票前四天的涨跌幅 大于0.5或者小于-0.5的,换为1,否则为0
np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0)
4.2 判断函数
np.any()
: 至少有一个元素满足指定条件,返回Truenp.all()
: 所有的元素满足指定条件,返回True
# 判断stock_change[0:2, 0:5]是否全是上涨的
>>> np.all(stock_change[0:2, 0:5] > 0)
False
# 判断前5只股票这段期间是否有上涨的
>>> np.any(stock_change[0:5, :] > 0 )
True
4.3 统计运算
在数据挖掘/机器学习领域,统计指标的值也是我们分析问题的一种方式。常用的指标如下:
np.mean()
,np.sum()
:所有元素的平均值,所有元素的和,参数是 number 或 arraynp.max()
,np.min()
:所有元素的最大值,所有元素的最小值,参数是 number 或 arraynp.std()
,np.var()
:所有元素的标准差,所有元素的方差,参数是 number 或 arraynp.argmax()
,np.argmin()
:最大值的下标索引值,最小值的下标索引值,参数是 number 或 arraynp.cumsum()
,np.cumprod()
:返回一个一维数组,每个元素都是之前所有元素的 累加和 和 累乘积,参数是 number 或 array- 多维数组默认统计全部维度,
axis
参数可以按指定轴心统计,值为0
则按列统计,值为1
则按行统计。
案例:股票涨跌幅统计运算
进行统计的时候,axis 轴的取值并不一定,Numpy中不同的API轴的值都不一样,在这里,axis 0代表列, axis 1代表行去进行统计
# 接下来对于这4只股票的4天数据,进行一些统计运算
# 指定行 去统计
print("前四只股票前四天的最大涨幅{}".format(np.max(temp, axis=1)))
# 使用min, std, mean
print("前四只股票前四天的最大跌幅{}".format(np.min(temp, axis=1)))
print("前四只股票前四天的波动程度{}".format(np.std(temp, axis=1)))
print("前四只股票前四天的平均涨跌幅{}".format(np.mean(temp, axis=1)))
如果需要统计出哪一只股票在某个交易日的涨幅最大或者最小?
np.argmax(temp, axis=)— 最大元素对应的下标
np.argmin(temp, axis=) — 最小元素对应的下标
# 获取股票指定哪一天的涨幅最大
print("前四只股票前四天内涨幅最大{}".format(np.argmax(temp, axis=1)))
print("前四天一天内涨幅最大的股票{}".format(np.argmax(temp, axis=0)))
4.4 去重排序函数
np.unique()
:找到唯一值并返回排序结果,类似于Python的set集合
arr = np.array([[1, 2, 1], [2, 3, 4]])
print(arr)
print(np.unique(arr))
# 结果
[[1 2 1]
[2 3 4]]
[1 2 3 4]
小结:
关于Numpy的总结就到这里,接下来我们一起总结Pandas的使用。
好了,今天就到这里,拜了个拜~