天天看点

Numpy 知识总结(浓缩)

# 一,Numpy 知识点总结:
# 1, 创建 ndarray:
# 1)np.array()方法: 接收一切序列类型对象,包括其他数组。
import numpy as np
myndarry=np.array([1,2,3,4,"a","b"]) 

# 2)其他方法,如:np.zeros(),np.ones(),np.empty(),np.arange(),np.ones_like(),np.zeros_like(),
# np.eye(),np.empty_like(),np.identity()等。
np.zeros(5), np.zeros((2,3))   
np.ones(5), np.ones((2,3))   
np.empty((2,2))     # np.empty返回全0数组是不安全的,很多情况下,返回的都是一些未初始化的垃圾值.
np.arange(5), np.arange(1,5), np.arange(1,10,2) # array([0, 1, 2, 3, 4])  # 一维数组
arr02=np.zeros_like(arr01)
arr03=np.ones_like(arr01)
arr04=np.empty_like(arr01)
 
# 2, 数组的属性:
print(myarray.ndim)       # 1      维数
print(myarray.size)       # 5      元素总数
print(myarray.shape)      # (5,)   形状     一维数组的形状 (n,)或(1,n)
print(myarray.dtype)      # int32  数据类型
print(myarray.itemsize)   # 4      每个元素的字节大小  32/8=4

# 3, ndarray 的数据类型:
# 1)自动推断类型:
arr01=np.array([0,1,2,3,4])
arr01.dtype # dtype('int32')

# 2)创建数组时为数组指定数据类型时:
arr02=np.array([0,1,2,3,4],dtype='float64')
arr02.dtype  #dtype('folat64')

# 3)使用astype显示转换数据类型,返回一个新数组:
arr01=np.array([0,1,2.5,3.1,4.2],dtype='float64')
arr02=arr01.astype(np.int32)  # 将浮点型数组转为整数,并不会四舍五入,而是直接截断    array([0, 1, 2, 3, 4])

arr01=np.array(['0','1','2.5','3.1','4.2'])
arr02=arr01.astype(np.float64)
arr02        # array([0. , 1. , 2.5, 3.1, 4.2])

arr01=np.array([0,1,2,3,4],dtype='float64')
arr02=np.array(["1","4","5"])
arr03=arr02.astype(arr01.dtype) # 使用其他数组的数据类型
arr03.dtype

# 4, 数组和标量之间的运算
# 大小相等的数组之间的任何算术运算都会将运算应用到元素级:
# 不同大小的数组之间的运算叫做广播,本书不对广播机制做深入了解,可在附录A NUmpy高级应用中了解一下。
arr*arr
arr+arr
arr-arr
arr/arr
arr**2
1/arr
arr-0.5
3*arr+2
arr>arr2 # 返回布尔类型数组

# 5, 基本索引和切片
# 1)一维数组: Numpy 数组的索引方法非常多,一维数组很简单和pyton 列表类似。
# 一维数组元素的访问:arr1d[5]
# 一维数组的切片:arr1d[5:8]
# 一维数组的切片赋值:arr1d[3:7]=12  会影响原数组的值
# 一维数组切片的显式复制: arr_new=arr1d[5:8].copy() 对 arr_new的修改,不会影响 arr1d

# 6, 高维数组的索引(访问)和切片: 二维数组   获取行,获取列,获取行列子集,获取元素
arr2d=np.arange(1,10).reshape(3,3)
# 二维数组的元素索引--获取一维数组(行):arr2d[2] 相当于 arr2d[2,]      # array([7, 8, 9])
# 二维数组的元素索引--获取单个元素:arr2d[2][1] 相当于 arr2d[2,1]       # 8
# 二维数组的元素索引--获取一维数组(列)arr2d[:,1]                      # 获取列需要切片  array([2, 5, 8])
# 二维数组的元素索引--获取二维的子集数组(行列子集)arr2d[:2,1:]         # 获取行列子集需要切片  

# 注意:
#上面所有的只要有两个[][]的都可以看作两次索引,比如 arr2d[2][1]相当于 arr_new01=arr2d[2] arr_new02=arr_new01[1]
#当然,对切片的赋值也会广播到整个选区:arr2d[:,:1]=9

# 7, 布尔索引   ==   !=  ~  | <  >  <=  >=
# 返回结果的维度与布尔索引数组的维度相同:
names=np.array(["Bob","Joe","Will","Bob","Will","joe","joe"])  # size=7
data=np.random.randn(7,4)  # 行数为 7
bool_Bob = names == 'Bob'  # bool_Bob 是一个 size=7的一维布尔数组。  作为下面的索引条件,True表示满足条件
data[names == 'Bob'] 相当于 data[names == 'Bob',]    # 返回所有满足条件的单行或多行  一维或二维数组
data[names == 'Bob',:4] 相当于 data[names == 'Bob',] # 前4列中满足条件的行   二维数组
data[names!='Bob']
data[~(names=='Bob')]
mask=(names=='Bob')|(names=='Will')  data[mask]  # 必须带括号
mask=(names=='Bob')&(names=='Will')  data[mask]  # 必须带括号   # data[mask]为空数组
# names中元素的值是确定的,不可能既是‘Bob’又是的'Will',所以可以预想 mask 的元素全是False   
data[data<0]
# 对使用布尔索引获得的所有元素或行赋值:
data[data<0]=0  # 会影响 data
data[(data==0.1)|(data<0.2)]=0.25 
data[names=='joe']=7
# 对使用布尔索引获得的整列赋值:
bool_arr=np.array([False,False,True,False])
data=data.swapaxes(0,1)  # 轴对换返回的是一个新的数组,所以还用data来接收才能改变data数组。
data[bool_arr]=100       # 为列赋值
data=data.swapaxes(0,1)  # 再次转回来
data

# 8, 花式索引(整数数组索引):
# 与切片的一个很大不同点是,它总是将数据复制到新数组中,对花式索引结果的赋值,不影响原数组,
# 因为其形状与原数组都不一样了,自然没法赋值给原数组。
arr84=np.empty((8,4))
for i in range(8):
#   arr84[i,]=i
    arr84[i]=i
    
arr84[[4,3,0,6]]  # 取arr84数组的第5,第4,第1和第7行数据
arr84[[-3,-5,-7]]  #使用负的索引,会从数组的末尾开始选行,-3表示倒数第三行。

newarr84=np.arange(32).reshape((8,4))
newarr84[[1,5,7,2],[0,3,1,2]]
newarr84[[1,5,7,2]][:,[0,3,1,2]] # 4x4  分开写:new=newarr84[[1,5,7,2]],new2=new[:,[0,3,1,2]]   输出new2


# 9,数组转置和轴对换
# 转置是重塑的一种特殊形式,返回的是原数组的视图(不会进行任何复制操作)
# 我的理解,arr和arr.T ,arr.transpose() 都是arr的不同形式,对arr.T ,arr.transpose()的赋值操作会影响arr
# 1)array.T 属性  2)arr.transpose(轴号元组)方法  3)array.swapaxes(1,0)方法
# 上面三种方法或属性都不改变原来数组。
arr35=np.arange(15).reshape((3,5))
arr35.T
arrdot=np.dot(arr35.T,arr35)  # 点积操作
arr35=np.arange(15).reshape((3,5))
arr35.transpose((1,0))  # 轴号元组(1,0)
arr35.swapaxes(1,0)     # 两个轴号做参数,不是元组


# 10,通用函数 ufunc:快速的元素级的数组函数
# 可以看作是简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化包装器。
# 许多ufunc都是简单的元素级变体,如sqrt,exp:

# 一元 ufunc:(操作单个数组)  语法:np.ufunc(arr)
# abs,fabs--计算整数,浮点数,复数的绝对值,对于非复数值,可以使用更快的fabs
# sqrt------计算各元素的平方根,相当于arr**0.5
# square----计算各元素的平方,相当于arr**2
# exp-------计算各元素的以e为底的指数
# log,log10,log2,log1p--分别表示自然对数,底数为10的log,底数为2的log,log(1+x)
# sign--计算各元素的正负号:1(正数),0(零),-1(负数)
# ceil--计算各元素的ceiling值,即大于等于该值的最小整数。 (天花板值)
# floor--计算该值的floor值,即小于等于该值的最大整数。(地板值)
# rint--将各元素的值四舍五入到最接近的整数,保留dtype。
# modf--将数组的小数和整数部分以两个独立数组的形式返回。
# isnan--返回一个表示哪些值是 NAN (not a number)的布尔型数组
# isfinite--返回一个表示哪些元素是有尽的(非inf,非NAN)的布尔型数组
# isinf--返回一个表示哪些元素是无穷的的布尔型数组
# cos,cosh,sin,sinh,tan,tanh--普通型和双曲型三角函数
# arccos,aeccosh,arcsin,arcsinh,arctan,arctanh--反三角函数
# logicl-not--计算各元素not x的真值。相当于 -arr

# 二元ufunc:(操作两个数组)  语法:np.ufunc(arr1,arr2)
# add--将两个数组中对应的元素相加
# subtract--将两个数组中对应的元素相减
# multiply--将两个数组中对应的元素相乘
# devide,floor_divide--除法或向下圆整除法(丢弃余数)
# power--对于第一个数组中的元素A,根据第二个数组中的相应的元素B,计算A**B
# maximum,fmax--元素级的最大值计算,fmax将忽略NAN
# minimum,fmin--元素级的最小值计算,fmin将忽略NAN
# mod--元素级的取模计算(除法的余数)余数。
# copysign--将第二个数组中的符号复制给第一个数组中的值
# greater、greater_equal、less、less_equal、equal、not equal--执行数组元素的比较运算,产生布尔型数组。相当于中辍运算符 >,>=,<,<=,==,!=
# logical_and、logical_or、logical_xor--执行元素级的真值逻辑运算。相当于中辍运算符 &、|、^


#示例:
arr=np.arange(10) 
np.sqrt(arr)   np.exp(arr)   
arrfloat=np.random.randn(7)*5
np.modf(arrfloat) # 返回两个数组

arr1=np.random.randn(8) arr2=np.random.randn(8) 
np.add(arr1,arr2)  np.maximum(arr1,arr2)


# 11,面向数组编程
# 1) np.meshgrid(arr1,arr2)  生成网格点坐标矩阵
# 假设我们想得到一组值(网格型)上计算sqrt(x^2+y^2)。np.meshingrid(arr1,arr2)函数接受两个一维数组,并产生两个二维矩阵
# 假设一维数组的长度为n,那么二维数组的shape为(n,n)
#(对应于两个数组中所有的(x,y)对):
import numpy as np
points=np.arange(-5,5,0.01)       # 一维数组   
xs,ys=np.meshgrid(points,points)  # xs,ys均为二维数组,两个数组互为转置关系
z=np.sqrt(xs**2+ys**2)  # xs**2+ys**2是数组间的运算得到一个新数组  然后再sqrt
import matplotlib.pyplot as plt
plt.imshow(z,cmap=plt.cm.gray);plt.colorbar()  # 作图
plt.title("Image plot of $\sqrt{x^2+y^2})$ for a grid of values")


# 2) np.where(boolarr或返回布尔数组的表达式,arr1或标量1,arr2或标量2)
# 返回一个数组
xarr=np.array([1.1,1.2,1.3,1.4,1.5])
yarr=np.array([2.1,2.2,2.3,2.4,2.5])
condarr=np.array([True,False,True,True,False])
np.where(condarr,xarr,yarr)

arrrandn = np.random.randn(4,4)
new_arr = np.where(arrrandn>0,2,-2)   # np.where()常用于根据一个数组 arrrandn,而生成另一个新数组 new_arr。

arrrandn = np.random.randn(4,4)
new_arr = np.where(arrrandn>0,2,arr)  # 大于0的元素赋值为2,其他元素依然是arr对应的元素(即其他元素不变)。


# -------------------------这部分可不看--------------------------
# np.where(boolarr或返回布尔数组的表达式)  没搞明白存在的意义
# 返回元组
import numpy as np
a = np.array([1,3,5,7,9])
arr=np.where(a>5)  # (array([3, 4], dtype=int64),) 是【元组】
arr2=a[arr,]       # 等同于 a[arr]  返回:array([[7, 9]]) 一个二维数组 
arr2.ndim          # 2 
arr2.shape         # (1,2) 

a[a>5]  # array([7, 9])   # 一维数组,这可能才是我们想要的。

arr01=np.array([[7,9]])  # array([[7, 9]])
arr01.ndim  # 2
arr01.shape # (1, 2)
# --------------------------------------------------------------

# numpy.where的嵌套使用:
# 两个布尔类型的数组cond1和cond2,如果对应元素都是True,就是11,如果只有第一个数组的元素是True,就是10,
# 如果只有第二个数组的元素是True,就是01,如果两个数组的对应元素都是False元,就是00,用列表接收他们。

results=[]
arr1=np.array([True,False,False,False,True])
arr2=np.array([False,False,True,False,True])
n=arr1.size
for i in range(n):
    if arr1[i] and arr2[i]:
        results.append('11')
    elif arr1[i]:
        results.append('10')
    elif arr2[i]:
        results.append('01')
    else:
        results.append('00')
results

# 使用np.where进行嵌套就可以写得更简单:
np.where((arr1 & arr2),'11',np.where(arr1,'10',np.where(arr2,'01','00'))).tolist()


# 12,数学和统计方法   聚合函数和其他函数
# 可以作为数组的实例方法被调用,也可以作为顶级numpy函数使用


# 聚合函数:
# sum       沿着轴向计算所有的累计和,0长度的数组,累计和就是0
# mean      数学平均,0长度的数组平均值是 NAN
# std       标准差,可以选择自由度调整(默认分母是 n)
# var       方差,可以选择自由度调整(默认分母是 n)
# min,max   最小值和最大值
# argmin,argmax  最小值和最大值的位置

# 其他统计方法:
# cumsum    所有元素的累积和,第一个加数为0
# cumprod   所有元素的累积,第一个乘数是1
# 这两个函数不会使数组聚合,而是会产生一个中间结果的数组。


# 示例:
arr=np.random.randn(5,4)
print(arr.mean(),"--",np.mean(arr))  # 整个数组的平均值
print(arr.mean(1),"--",np.mean(arr,1))  # 每行的平均值
print(arr.mean(0),"--",np.mean(arr,0))  # 每列的平均值
print(arr.sum(axis=1),"--",np.sum(arr,axis=1))    # 计算每一列的和
print(arr.std(axis=1),"--",np.std(arr,axis=1))    # 计算每一列的标准差

# 对一维数组的某个轴数据使用cumsum,umprod:
arr1=np.array([1,2,3,4,5,6,7])
arr1.cumsum()  # array([1,  3,  6, 10, 15, 21, 28], dtype=int32)   等同 np.cumsum(arr1)
arr1.cumprod()  # array([   1,    2,    6,   24,  120,  720, 5040], dtype=int32)   等同 np.cumprod(arr1)

# 对二维数组的某个轴数据使用cumsum,umprod:
arr3=np.arange(9).reshape((3,3))
arr3


# 13,操作布尔值数组的方法   sum(),any(),all() 
# sum(),any(),all()  既可以作为数组实例的方法被调用,也可以作为顶级numpy函数使用。
# 这些函数用于非布尔类型数组,所有非 0元素,都会被认为是True.

# sum()
arr=np.random.randn(100)
print((arr>0.1).sum())  # 统计数组中元素大于0.1的个数   布尔类型数组的True相当于1,False相当于0   等同于 print(np.sum(arr>0.1))

# any()和all(), any检查数组中是否至少有一个True,all检查数组中是否全是True, 返回布尔类型的值
bools=np.array([False,True,False,False])
print(bools.any())     # True    print(np.any(bools))
print(bools.all())     # False   print(np.all(bools))


# 14, 数组排序  arr.sort() 会改变原数组; np.sort(arr)返回数组的copy,不会改变原数组。
# arr.sort()对一维数组排序:
arr=np.random.randn(6)
arr         # array([-1.5197868 ,  0.70317138, -1.32870498, -0.79815157,  0.44850826,  0.84079777])
arr.sort()  # 不返回值,原数组改变。
arr         # array([-1.5197868 , -1.32870498, -0.79815157,  0.44850826,  0.70317138,0.84079777])

# np.sort(arr)对一维数组排序:
arr=np.random.randn(6)
arr          # array([ 1.69866908, -0.93876399, -2.17448296,  1.18976963, -0.52686091,  -0.54713395])
np.sort(arr) # array([-2.17448296, -0.93876399, -0.54713395, -0.52686091,  1.18976963,  1.69866908])
arr          # array([ 1.69866908, -0.93876399, -2.17448296,  1.18976963, -0.52686091,  -0.54713395])  原数组未改变

# arr.sort()对于二维数组排序,参数为轴号,缺省时默认为 1(不推荐缺省):
arr2=np.random.randn(5,3)
arr2
arr2.sort() 相当于 arr2.sort(1) 
arr2   # 数组改变
np.sort(arr2,1)  # 原数组不改变  行数据排序
np.sort(arr2,0)  # 原数组不改变  列数据排序



# 15, 一维 ndarray的基础集合操作 
# 注,都是numpy的顶层方法,ndarray对象不存在这些方法。

# np.unique(arr)                 计算arr的唯一值,并排序
# np.intersect1d(arr1,arr2)      计算两个数组的交集,并排序
# np.union1d(arr1,arr2)          计算两个数组的并集,并排序
# np.ind1d(arr1,arr2)            计算arr1的元素,是否存在于arr2中,返回一个和 arr1长度一致的布尔类型数组
# np.setdifferent(arr1,arr2)     差集,在arr1中,但不在arr2中的元素
# np.setxor1d(arr1,arr2)         异或集,在arr1中或在arr2中,但不在二者的交集中

# 示例 1:np.unique(arr)   
names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
np.unique(names)  # array(['Bob', 'Joe', 'Will'], dtype='<U4')

# 用纯python 来实现上面的例子:
# 使用set()函数,将数组转化为set集合,自动去重,然后用sorted()函数对set集合排序,得到列表:
# 知识点:set(ndarray对象)得到去重后的set集合, sorted(set)得到排序后的列表。

names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
names_set=set(names)
sorted(names_set)  # ['Bob', 'Joe', 'Will']

# 示例 2:np.in1d(arr1,arr2)
values01=np.array([5,6,7,9,0,0,3])
values02=np.array([5,8,7,5])
np.in1d(values01,values02)  # array([ True, False,  True, False, False, False, False])



# 16, 使用数组进行文件输入和输出  (忽略)
# Numpy 可以将数据以【文本】或【二进制】的形式存入硬盘,或从硬盘载入。
# 由于大部分用户更倾向于使用pandas等其他工具来载入文本或表格型数据,因此,忽略。


# 17, 线性代数 (对于目前工作用不到,忽略)


# 18, 伪随机数生成 (记住几个常用的随机函数,用来生成测试数组)
# numpy.random 模块填补了python模块的不足,可以高效的生成多种概率分布下的完整样本值数组。

# numpy.random 中的部分函数列表:
# seed          像随机数生成器传递随即状态种子
# permutation   返回一个序列的随机排列,或者返回一个乱序的整数范围序列
# shuffle       随机排列一个序列
# rand          从均匀分布中抽取样本
# randint       根据给定的由低到高的范围抽取随机整数     np.random.randint(start,end,size=n),n是想生成的一维随机数组的大小
# randn         从均值0方差1的正态分布中抽取样本 (MATLAB 型接口)
# binomial      从二项分布中抽取样本
# normal        从正态(高斯)分布中抽取样本
# beta          从beta分布中抽取样本
# chisquare     从卡方分布中抽取样本

# python 中random.randint()用法: random.randint(0,1) 表示从0和1随机选取一个整数, 
#                                random.randint(0,5) 表示从0,1,2,3,4,5中随机选取一个整数

# 如,可以使用normal 来获得一个4x4的正态分布样本数组:
samples=np.random.normal(size=(4,4))  # 注意参数的写法
samples


# 19,综合示例 随机漫步 (见之前的博客)