代码可直接执行。。。
import profile,time,os
import numpy as np #导入该函数会导致程序重复执行??
"""
if __name__=="__main__":
#如果不用main函数会导致重复打印a,if __name__=="__main__":的作
#用为:只有当改文件以脚本被执行时才会执行下面的代码。
最总找到问题:python 文件名和模块名一样会导致重复导入函数和文件,导致本身导入一次而运行两次
if __name__=="__main__":
编写私有化部分 ,这句代码以上的部分,可以被其它的调用,以下的部分只有这个文件自己可以看见,
如果文件被调用了,其他人是无法看见私有化部分的。也就是说你自己运行该模块的时候 这句话是执行的
因为自己运行时__name__就是__main__,而当别人调用你这个模块时,以下代码会被忽略,此时的__name__是模块名
"""
#python自带array模块创建数组的方法:
import array
L=list(range(10))
a=array.array("i",L) #i表示数据类型:整形int
print(a)
#用numpy内的array创建数组:
b=np.array([0,32,3.14,31])#numpy数组必须为同一类型数据,否则会向上准换
print(b)
#也可以给出关键字参数来指定数组类型:
c=np.array([1, 2, 3, 4], dtype='float32')
print(c)
"""numpy数组的列表嵌套列表可以作为二维数组
array([[2, 3, 4],
[4, 5, 6],
[6, 7, 8]])"""
print("从头创建数组方法:")
a=np.zeros(10,dtype=int)#创建一个长度为10的数组,数组的值都是0
b=np.ones((3,5),dtype=float)#创建一个3×5的浮点型数组,数组的值都是1
c=np.full((3,5),3.14)#创建一个3×5的浮点型数组,数组的值都是3.14j
d=np.arange(0,20,2)#从0开始,到20结束,步长为2
e=np.linspace(0,1,5)#创建一个5个元素的数组,这5个数均匀地分配到0~1
f=np.random.random((3,3))#创建一个3×3的、在0~1均匀分布的随机数组成的数组
g=np.random.normal(0,1,(3,3))# 创建一个3×3的、均值为0、方差为1的正态分布的随机数数组
h=np.random.randint(0,10,(3,3))#创建一个3×3的、[0, 10j)区间的随机整型数组
i=np.eye(3)#创建一个3×3的单位矩阵
j=np.empty(3)# 创建一个由3个整型数组成的未初始化的数组# 数组的值是内存空间中的任意值
x = np.arange(9).reshape((3, 3)) # 创建0-8数组然后分布在3x3的矩阵
print("a:",a,"\nb:",b,"\nc:",c,"\nd:",d,"\ne:",e,"\nf:",f,
"\ng:",g,"\nh:",h,"\ni:",i,"\n",j)
"""np.ones((3,5),dtype=float)用一个字符串参数来指定数据类型:float32和float64数位的区别,
一个在内存中占分别32和64个bits,也就是4bytes或8bytes数位越高浮点数的精度越高,详细看下表:
数据类型 描述j
bool_ 布尔值(真、True 或假、False),用一个字节存储
int_ 默认整型(类似于C 语言中的long,通常情况下是int64 或int32)
intc 同C 语言的int 相同(通常是int32 或int64)
intp 用作索引的整型(%%和C 语言的ssize_t 相同,通常情况下是int32 或int64)
int8 字节(byte,范围从–128 到127)
int16 整型(范围从–32768 到32767)
int32 整型(范围从–2147483648 到2147483647)
int64 整型(范围从–9223372036854775808 到9223372036854775807)
uint8 无符号整型(范围从0 到255)
uint16 无符号整型(范围从0 到65535)
uint32 无符号整型(范围从0 到4294967295)
uint64 无符号整型(范围从0 到18446744073709551615)
float_ float64 的简化形式
float16 半精度浮点型:符号比特位,5 比特位指数(exponent),10 比特位尾数(mantissa)
float32 单精度浮点型:符号比特位,8 比特位指数,23 比特位尾数
float64 双精度浮点型:符号比特位,11 比特位指数,52 比特位尾数
complex_ complex128 的简化形式
complex64 复数,由两个32 位浮点数表示
complex128 复数,由两个64 位浮点数表示"""
print("数组操作:")
np.random.seed(0)#设定随机种子数(让下面整个程序可以生成的随机数的数量只能为1)
x1 = np.random.randint(10, size=6) # 一维数组
x2 = np.random.randint(10, size=(3, 4)) # 二维数组
x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组
print("x1:\n",x1,"\nx2:",x2,"\nx3:",x3,)
#每个数组有nidm(数组的维度)、shape(数组每个维度的大小)和 size(数组元素个数的总数)属性:
print("x3 ndim: ", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size: ", x3.size)#另外还有.dtype数据类型属性\.itemsize每个元素大小\.nbytes总
#数组操作与列表操作基本一样(下面列出不同的地方)
print(x2[2,0])#与普通列表的差别使用逗号分隔元组获取元素
x2[2,0]=100#可以和列表一样用索引修改元素值
print(x2)#numpy数组与py列表不一样,数组类型是固定的所以int数组中插入浮点值会被截短成整型!!
print("一维数组切片:")
#一维数组数组切片和列表一样x[start:stop:step]
x1=np.array([0,1,2,3,4,5,6,7,8,9])
print(x1[::-1])#当步长为负数时所有元素逆顺序
print(x1[5::-2])#从索引5开始每隔一个元素逆序:5,3,1 !!!!!!
# 步长为负时先倒序后再进行切片
#ndarray就多维数组的意思
print("多维数组切片:")
#多维切片通过逗号分隔维度,先从最外层开始,然后各个维度切片与一维类似。
x2=np.array([[12, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
print(x2[:2,:3])#取第0、1行,0、1、2列
print(x2[:3, ::2])#所有行,每隔一列
print(x2[::-1, ::-1])#行列同时逆序
#数组取列行
print("取第一列:\n",x2[:, 0])#可以用于excel的列;取行可以缩简为x2[0]
#!!!数组切片返回的是数组数据的视图,而不是数值数据的副本(这点和列表不一样)。
print("修改前:\n",x2)
a=x2[:2,:3]
a[1,2]=100#!!此处切片为下x2的镜像,所以修改后会导致原数组跟着修改(大数据时可以节省内存和时间)
print("修改后:\n",x2)
# 在操作一个二维数组的一列时可以先将一列的镜像赋予给一个变量,在变量进行运算后,原数组也就被更改了
#若想候明确地复制数组里的数据或子数组可以用copy()函数(修改,原数据不变):
a=x2[:2,:3].copy()
#数组变形:将一个一维数组转变为二维的行或列的矩阵,变形不会修改原值,需要重新赋予
# 通过变形获得的行向量
x = np.array([1, 2, 3])
x.reshape((1, 3))#out:array([[1, 2, 3]]), 这里(1,3)代表1行,3列
#也可以通过newaxis 关键字
#通过newaxis获得的行向量
x = np.array([1, 2, 3])
x[np.newaxis, :] #out:array([[1, 2, 3]])相当于创建一个新的轴(维度)放在(new,x)
# 通过变形获得的列向量
x = np.array([1, 2, 3])
y=x.reshape((3, 1))#x本身不作修改,必须从新赋值给y(上面一样),不然只会显示原值
print(y)
#另一种方法x[:, np.newaxis]
print("数组拼接和分裂:")
#拼接或连接NumPy 中的两个数组主要用到np.concatenate、np.vstack 和np.hstack函数实现
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
print(np.concatenate([x, y]))#将数组组成的列表或者元组作为第一个参数来拼接数组,也可以3个以上
grid3 = np.array([[[1, 2, 3,100],
[4, 5, 6,100],
[7, 8, 9,100]],
[[10,11,12,100],
[13,14,15,100],
[16,17,18,100]]])
print("三维数组的拼接")
print("\naxis=0\n",np.concatenate([grid3, grid3], axis=0))
print("\naxis=1\n",np.concatenate([grid3, grid3], axis=1))
print("\naxis=2\n",np.concatenate([grid3, grid3], axis=2))#沿着第二个轴拼接(从0开始索引)
#!!!axis=0代表最外层一维拼接,1为二层拼接,2是最内层(数据由外往内数)
"""上面是3维数组,excel类似表格多为二维数组,二维数组中axis=0相当于在行底下拼接,
axis=1相当于在列后拼接数据!!!!类似于下面:"""
print("二维数组的拼接")
grid2 = np.array([[1, 2, 3],
[4, 5, 6]])
print(np.concatenate([grid2, grid2]))#相当于axis=0
print(np.concatenate([grid2, grid2],axis=1))
#沿着固定维度处理数组时,使用np.vstack(垂直栈)和np.hstack(水平栈)函数会更简洁:
x = np.array([1, 2, 3])
grid = np.array([[9, 8, 7],
[6, 5, 4]])
print("垂直栈数组:\n",np.vstack([x, grid]))
y=np.array([[99],
[99]])
print("水平栈数组:\n",np.hstack([grid,y ]))#两个数组固定纬度相同,相当于grid和y
#另外还有:np.dstack 将沿着第三个维度拼接数组。
print("\n数组的分裂:")
#分裂可以通过np.split、np.hsplit和np.vsplit 函数来实现(不修改原值,需要重新赋予变量)
x = [1, 2, 3, 99, 99, 3, 2, 1]
x1, x2, x3 = np.split(x, [3, 5])#向传递一个索引列表作为参数,索引列表记录的是分裂点位置
print(x1,x2,x3)#N 分裂点会得到N + 1 个子数组
grid = np.arange(16).reshape((4, 4))#将0-16分放入到一个4x4的矩阵中
print(grid)
upper, lower = np.vsplit(grid, [2])#垂直分割,在矩阵中按垂直第2个元素开始分割
print("upper:\n",upper)
print("lower:\n",lower)
# !!垂直是沿着行数来来分割,水平是沿着列数来分割
left, right = np.hsplit(grid, [2])#水平分割,在矩阵中按水平方向的第2个元素开始分割
print("left:\n",left)
print("right:\n",right)
#!!!np.dsplit 将数组沿着第三个维度分裂。(按照表格数号来分隔)
print("\nNumPy数组的计算:通用函数")
"""!!Python 的相对缓慢通常出现在很多小操作需要不断重复的时候,比如对数组的每个元素做循环操
作时CPython 在每次循环时必须做数据类型的检查和函数的调度。每次进行倒数运算时,Python
首先检查对象的类型,并且动态查找可以使用该数据类型的正确函数。如果我们在编译代码时进行这样的操作,
那么就能在代码执行之前知晓类型的声明,结果的计算也会更加有效率。"""
#np.random.seed(0)
def compute_reciprocals(values):
"""举例一个算数组所有元素的倒数用时"""
output = np.empty(len(values))
for i in range(len(values)):
output[i] = 1.0 / values[i]
return output#看到程序存在这样大量的循环,可以考虑尝试用数组的方法
big_array = np.random.randint(1, 100, size=10000)#加大size来测试速度
profile.run("aaa=compute_reciprocals(big_array)")
#通用函数计算时间:
#numpy向量操作是通过通用函数实现的对数组内的元素进行运算
start=time.clock()
print(1.0 / big_array,"\n通用函数耗时:",)
end=time.clock()#通用函数的主要目的是对NumPy 数组中的值执行更快的重复操作
print(end-start)
print("两个数组进行运算:\n",np.arange(5) / np.arange(1, 6))#除了标量和数组运算也可以两个数组进行运算
#两个数组元素数量应该相同,否则出错
x = np.arange(9).reshape((3, 3))
print("多维数组运算:\n",2**x)#对多维数组内每个元素进行运算
#NumPy 通用函数它用到了Python 原生的算术运算符标准的加、减、乘、除都可以使用:
x = np.arange(1,5)
print("\nnumpy的通用函数:\nx =", x)
print("x + 5 =", x + 5)
print("x - 5 =", x - 5)
print("x * 2 =", x * 2)
print("x / 2 =", x / 2)
print("x // 2 =", x // 2)
print("-x = ", -x)
print("x ** 2 = ", x ** 2)
print("x % 2 = ", x % 2)#abs(x)求绝对值
print("e^x =", np.exp(x))
print("2^x =", np.exp2(x))
print("3^x =", np.power(3, x))
print("ln(x) =", np.log(x))
print("log2(x) =", np.log2(x))
print("log10(x) =", np.log10(x))
print("\n1. 指定输出")
#所有的通用函数都可以通过out 参数来指定计算结果的存放位置:
x = np.arange(5)
y = np.empty(5)#创建一个由5个整型数组成的未初始化的数组# 数组的值是内存空间中的任意值
np.multiply(x, 10, out=y)#multiply(x,y)乘法
print(y)
y = np.zeros(10)
np.power(2, x, out=y[::2])#写入每隔一个元素的位置
print(y)
"""写成y[::2] = 2 ** x那么结果将是创建一个临时数组,该数组存放的是
2 ** x 的结果,并且接下来会将这些值复制到y数组中(占用内存)。
对于较大的数组,通过使用out 参数将能够有效节约内存。"""
print("\n聚合:")
x = np.arange(1, 6)
print(np.add.reduce(x))#可以直接作用在函数对象上计算,此处相当于将x内的原始逐个相加直到得到单个结果。
#可以用任何通用函数的reduce方法。一个reduce 方法会对给定的元素和操作重复执行,直至得到单个的结果。
np.multiply.reduce(x)#相乘
#需要储存每次计算结果可以用accumulate方法
np.add.accumulate(x)#renturn:array([ 1, 3, 6, 10, 15])
print("\n外积:")
#任何通用函数都可以用outer 方法获得两个不同输入数组所有元素对的函数运算结果
x = np.arange(1, 6)
print(np.multiply.outer(x, x))#两个数组的乘法表,类似迪尔卡积
# 这里相当于shape(0,5)*shap(5,0)
L = np.random.random(1000000)#创建100个0~1的数字填满数组
sum(L)
np.sum(L)
#虽然py有np中的sum函数非常相似,但由于np的sum直接在编译码中执行操作,所以这里速度要快得
#相同的np.min()和np.max()也比原py中的min和max函数快得多
print("\n多维度聚合:")
M = np.random.random((3, 4))
print(M)
print(M.sum())#默认情况下每一个NumPy 聚合函数将会返回对整个数组的聚合结果
#sum(a, axis=None, dtype=None, out=None, keepdims=np._NoValue)
print("axis=0\n",M.min(axis=0))#聚合函数还有一个参数axis,用于指定沿着哪个轴的方向进行聚合
print("axis=1\n",M.max(axis=1))#其中轴axis表示(3,4)二维矩阵中的的列行
"""
!!!!axis 关键字指定的是数组将会被折叠的维度,而不是将要返回的维度。
因此指定axis=0 最外层折叠。
表2-3:NumPy中可用的聚合函数
函数名称 NaN安全版本 描述
np.sum np.nansum 计算元素的和
np.prod np.nanprod 计算元素的积
np.mean np.nanmean 计算元素的平均值
np.std np.nanstd 计算元素的标准差
np.var np.nanvar 计算元素的方差
np.min np.nanmin 找出最小值
np.max np.nanmax 找出最大值
np.argmin np.nanargmin 找出最小值的索引
np.argmax np.nanargmax 找出最大值的索引
np.median np.nanmedian 计算元素的中位数
np.percentile np.nanpercentile 计算基于元素排序的统计值(array,num)第多少num百分的数值
np.any N/A 验证任何一个元素是否为真
np.all N/A 验证所有元素是否为真
大多数的聚合都有对NaN 值的安全处理策略(NaN-safe),
即计算时忽略所有的缺失值,这些缺失值即特殊的IEEE 浮点型NaN值
"""
print("\n数组的计算:广播")
"""另外一种向量化操作的方法是利用NumPy 的广播功能。广播可以简单理解为用于不同大
小数组的二进制通用函数(加、减、乘等)的一组规则。"""
print("一维数组和二维数组相加")
a = np.array([0, 1, 2])
M = np.ones((3, 3))
print(M)
print(a+M)
print("\n两个数组的同时广播")
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]
print(a)
print(b)
print(a + b)
"""广播可以理解成前将一个值扩展或广播以匹配另外一个数组的形状,这里将a 和b
都进行了扩展来匹配一个公共的形状,最终的结果是一个二维数组。但numpy实际计算中并没有
这个额外的内存分配,只是概念上的理解,详细图像看教材57页"""
print("\n广播的规则:")
#规则1:如果两个数组的维度数不相同,那么小维度数组的形状将会在最左边补1。(这里说的是维度补1)
#规则2:如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着
# 维度为1 的维度扩展以匹配另外一个数组的形状。
#规则3:如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常。
#(也就是说两个广播的数组必须要有一个数组的一个维度大小等于1)
print("示例1")
M = np.ones((2, 3))
a = np.arange(3)
print(M)
print(a)
print("a+M:\n",M+a)
#a.shape -> (1, 3)->(2, 3)根据规则1在其左边补1;根据规则2第一个维度不匹配,因此扩展这个维度以匹配数组
print("\n示例2")
a = np.arange(3).reshape((3, 1))
b = np.arange(3)
print(a)
print(b)
print("a+b:\n",a+b)
#a.shape -> (3, 1)->(3, 3)a的维度根据规则2,维度2扩展到3来匹配a
#b.shape -> (1, 3)->(3, 3)b根据规则1左边补1,根据规则2维度1扩展为3来匹配a
print("\n示例3")
M = np.ones((3, 2))
a = np.arange(3)
print(M)
print(a)
#根据规则1,2最终a.shape->(3, 3),M.shape->(3, 2)但根据规则3最终没有纬度等译1的,程序出错。
print(M+a[:, np.newaxis])#可以通过变形数组往右边补1,具体看实际用途
#上面事例可用于任意二进制通用函数
print("\n广播的实际应用:数组的归一化")#归一化是一种统计学的计算方式
X = np.random.random((10, 3))
print(X)
Xmean=X.mean(0)
print(Xmean)#沿着第一个维度为轴聚合求平局(尝试改成1理解维度轴的概念)
X_centered = X - Xmean
print(X_centered.mean(0))
print("\n2.6 比较、掩码和布尔逻辑")
#numpy中的布尔表达式和np相对于py的通用函数相似:(<, >, <=, >=, !=, ==)
x = np.array([1, 2, 3, 4, 5])
print("x<3:",x<3)#返回一个布尔数组
print("复合表达式",(2 * x) == (x ** 2))#利用复合表达式实现对两个数组的逐元素比较也是可行的
#和算术运算符一样,当你写x < 3 时,NumPy 内部会使用np.less(x, 3)。
"""
运算符 对应的通用函数
== np.equal
!= np.not_equal
< np.less
<= np.less_equal
> np.greater
>= np.greater_equal
"""
print("\n操作布尔数组:")
x = np.random.randint(10, size=(3, 4))
print(x)
print("x小于6的个数:",np.count_nonzero(x < 6))#统计布尔数组中True 记录的个数
np.sum(x < 6)#另一种实现方法,
print(np.sum(x < 6, axis=1))#sum()的好处是,和其他NumPy聚合函数一样,这个求和也可以沿着行或列进行
print(np.any(x<10))#快速检查所有这些值是否为True,可以用np.any() 或np.all()
print(np.all(x < 8, axis=1))#传入参数axis可以沿着着特定的坐标轴来判断
print("\n布尔运算符:")
"""
运算符 对应通用函数
& np.bitwise_and
| np.bitwise_or
^ np.bitwise_xor(异或运算符(^))
~ np.bitwise_not(取反运算符(~))
"""
print(np.sum((x > 3) & (x < 8)))
print(np.sum(~((x <= 3) | (x >= 8))))#利用A AND B 和NOT (A OR B) 的等价原理
print("\n将布尔数组作为掩码:")
#聚合计算另一种更强大的模式是使用布尔数组作为掩码,通过该掩码选择数据的子数据集。
print(x)
print(x<5)
print(x[x < 5])#将这些值从数组中选出(返回的是一个一维数组),可以进行简单的索引,即掩码操作
print("and 和or,以及逻辑操作运算符& 和| 的区别:")#一个是总的,一个是元素比较
"""
and 和or 判断整个对象是真或假,而& 和| 是指每个对象中的比特位。
当你使用and 或or 时,就等于让Python 将这个对象当作整个布尔实体。在Python 中,
所有非零的整数都会被当作是True:
In[30]: bool(42), bool(0)
Out[30]: (True, False)
当你对整数使用& 和| 时,表达式操作的是元素的比特,将and 或or 应用于组成该数
字的每个比特:
In[33]: bin(42)
Out[33]: '0b101010'
In[34]: bin(59)
Out[34]: '0b111011'
In[35]: bin(42 & 59)
Out[35]: '0b101010'
In[36]: bin(42 | 59)
Out[36]: '0b111011'
请注意,& 和| 运算时,对应的二进制比特位进行比较以得到最终结果。
当你在NumPy 中有一个布尔数组时,该数组可以被当作是由比特字符组成的,其中
1 = True、0 = False。这样的数组可以用上面介绍的方式进行& 和| 的操作:
In[37]: A = np.array([1, 0, 1, 0, 1, 0])
B = np.array([1, 1, 1, 0, 1, 1])
A | B
Out[37]: array([ True, True, True, False, True, True], dtype=bool)
而用or 来计算这两个数组时,Python 会计算整个数组对象的真或假,这会导致程序出错:
In[38]: A or B
ValueError
同样,对给定数组进行逻辑运算时,你也应该使用| 或&,而不是or 或and
如果试图计算整个数组的真或假,程序也同样会给出ValueError 的错误
因此可以记住:and 和or 对整个对象执行单个布尔运算,而& 和| 对一个对象的内
容(单个比特或字节)执行多个布尔运算。对于NumPy 布尔数组,后者是常用的操作。
"""
print("\n2.7 花哨的索引:")
#花哨的索引和前面那些简单的索引非常类似,但是传递的是索引数组,而不是单个标量.
rand = np.random.RandomState(42)
x = rand.randint(100, size=10)
print(x)
print([x[3], x[7], x[4]])
ind=[3, 7, 4]
print(x[ind])#传递索引的单个列表或数组来获得同样的结果
#利用花哨的索引,结果的形状与索引数组的形状一致,而不是与被索引数组的形状一致:
ind = np.array([[3, 7],
[4, 5]])
print(x[ind],"\n多维度:")
#花哨的索引也对多个维度适用:
X = np.arange(12).reshape((3, 4))
print(X)
row = np.array([0, 1, 2])
col = np.array([2, 1, 3])
print(X[row, col]) # 和标准的索引方式一样,第一个索引指的是行,第二个索引指的是列
"""在花哨的索引中,索引值的配对遵循2.5 节介绍过的广播的规则。
因此当我们将一个列向量和一个行向量组合在一个索引中时,会得到一个二维的结果"""
print(row[:, np.newaxis])
print(X[row[:, np.newaxis], col])#两个形状必须是一样的
#这里row.shape变形成为(3,1),相当于row每一行都要与col的每一列进行匹配!!!!!!!!!
#!!特别的是,花哨的索引返回的值反映的是广播后的索引数组的形状,而不是被索引的数组的形状
# 花哨索引的运算符类是于& 相当于广播后的两个元素组合成为新的索引
print("\n组合索引:")
print("X:\n",X,"\n")
print(X[2, [2, 0, 1]])#可以将花哨的索引和简单的索引组合使用,这里是第3行与列表内索引匹配
#也可以将花哨的索引和切片组合使用:
print(X[1:, [2, 0, 1]])#这里是第2行开始与列表内索引匹配
print("用花哨的索引修改值")
x = np.arange(10)
i = np.array([2, 1, 8, 4])
x[i] = 99#修改原来数组
print(x)
x[i] -= 10#与+=类似
print(x)
#操作中重复的索引会导致一些出乎意料的结果产生:
x = np.zeros(10)
i = [2, 3, 3, 4, 4, 4]
x[i] += 1
print(x)
#得出结果并非是x[4]=3;而是[0. 0. 1. 1. 1. 0. 0. 0. 0. 0.]数组并没有发生多次累加,而是发生了赋值。
x = np.zeros(10)
np.add.at(x, i, 1)#如果希望累加,可以借助通用函数中的at() 方法
print(x)#另一个可以实现该功能的类似方法是通用函数中的reduceat() 函数
#at() 函数在这里对给定的操作、给定的索引(这里是i)以及给定的值(这里是1)执行的是就地操作。
bins = np.linspace(-5, 5, 20)
counts = np.zeros_like(bins)#生成一个形状和bins一样的数组。快速划分区间直方图73页
print("\n数组的排序:")
#正常的排序算法复杂度为[N**2]次方,列表元素翻一倍,排序时长翻4倍;
#NumPy中的快速排序:np.sort和np.argsort其算法复杂度为[N log N ,默认情况下是快速排序
x = np.array([2, 1, 4, 3, 5])
print(np.sort(x))#不修改原始输入数组的基础上返回一个排好序的数组,可以使用np.sort
x.sort()#如果希望用排好序的数组替代原始数组,可以使用数组的sort 方法
print(x)
x = np.array([2, 1, 4, 3, 5])
i = np.argsort(x)
print("argsort排序:\n",i)#函数argsort,该函数返回的是原始数组排好序的索引值
#In:x[i] out:array([1, 0, 3, 2, 4]) 这些索引值可以被用于(通过花哨的索引)创建有序的数组
print("\n沿着行或列排序")
rand = np.random.RandomState(42)
a = rand.randint(0, 10, (4, 6))
print(a)
#通过axis 参数,沿着多维数组的行或列进行排序
print("对a的每一列排序:\n",np.sort(a, axis=0))
print("对a的每一行排序:\n",np.sort(a, axis=1))
print("\n部分排序:分隔")
#np.partition 函数的输入是数组和数字K,前面k个元素为最小的k个元素,后面为剩下位置的值.
x = np.array([7, 2, 3, 1, 6, 5, 4])
print(np.partition(x, 3))
"""np.partition 函数的输入是数组和数字K;结果数组中前三个值是数组中最小的三个值,
剩下的位置是原始数组剩下的值。在这两个分隔区间中,元素都是任意排列的。"""
print(np.partition(a, 2, axis=1))#这里对a的数组进行按行分隔排序。
#同样也有np.argpartition,函数计算的是分隔的索引值
print("\n示例:K个最近邻")
#dist_sq = np.sum((X[:,np.newaxis,:] - X[np.newaxis,:,:]) ** 2, axis=-1)一步到位
#下面是分解:
#何利用argsort 函数沿着多个轴快速找到集合中每个点的最近邻
X = rand.rand(10, 2)
print(X)#计算两两数据点对间的距离。两点间距离的平方等于每个维度的距离差的平方的和。
differences = X[:, np.newaxis, :] - X[np.newaxis, :, :]
#坐标系中计算每对点的差值(利用广播的规则)
print("\nX[:,np.newaxis,:]:\n",X[:,np.newaxis,:])
#变形成3维,原2维度平均分配到各个3维度上,differences.shape=(10, 1, 2)
print("\nX[np.newaxis,:,:]:\n",X[np.newaxis, :, :])
#变形成3维,原2维数据变成一个3维数据的全部,differences.shape=(1, 10, 2)
# print("differences:",differences)
sq_differences = differences ** 2#求出差值的平方
# print(sq_differences) #帮助理解用
dist_sq = sq_differences.sum(-1)#按照最后一个轴来合并,即行dist_sq.shape=(10, 10)
# print(dist_sq)#最后变成一个二维数组(合并最后一个轴后该轴消失,上一级轴变成最后一个轴)
print("对角线:\n",dist_sq.diagonal())#查看对角线元素的函数,对角线都为0,那是与自己本身的距离
nearest = np.argsort(dist_sq, axis=1)#按照轴1进行排序(行),得出离最近距离的索引值排序
print(nearest)#这里第一列其实就是对角线,也就是自己本身的距离的索引
print("\n求k个最近邻的方法")# 用argpartition()函数,用法与上面partition()差不多。
K = 2 #这种方法不能确定最近的点,只能确定前K个,前K个是无序的
nearest_partition = np.argpartition(dist_sq, K + 1, axis=1)#K+1是为了加上自己本身的点
#79页是更详细的例子解析
print(nearest_partition)
"""
做大数据量的最近邻搜索时,有几种基于树的算法的算法复杂度可
以实现接近[N log N ],或者比暴力搜索法的[N 2] 更好。其中一种就是KD-Tree,在
Scikit-Learn(http://bit.ly/2fSpdxI)中实现。
"""
print("\n2.9 结构化数据:NumPy的结构化数组")
name = ['Alice', 'Bob', 'Cathy', 'Doug']
age = [25, 45, 37, 19]
weight = [55.0, 85.5, 68.0, 61.5]
#通过指定复合数据类型,可以构造一个结构化数组:
data = np.zeros(4, dtype={'names':('name', 'age', 'weight'),
'formats':('U10', 'i4', 'f8')})#采用字典的方法生成了一个空的数组容器
"""这里U10 表示“长度不超过10 的Unicode 字符串”,i4 表示“4 字节(即32 比特)整型”,
f8 表示“8 字节(即64 比特)浮点型"""
print("生成了一个空的数组容器:\n",data)
print("数组类型:\n",data.dtype)#查看结构化数组数据类型
data['name'], data['age'], data['weight']= name, age, weight#将列表数据放入数组中
print("out:\n",data)
print(data['name'])# 获取所有名字,这里的name是创建结构化数组时给出的
print(data[0])# 获取数据第一行
print(data[-1]['name'])#获取最后一行的名字,相当于结构化的行列。
#利用布尔掩码,还可以做一些更复杂的操作,如按照年龄进行筛选:
print(data[data['age'] < 30]['name'])# 获取年龄小于30岁的人的名字,[data['age'] < 30]返回满足条件的行号
print(data[data['age'] < 30])
print("\n生成结构化数组")
#结构化数组的数据类型有多种制定方式。上面采用字典的方法
#数值数据类型可以用Python 类型或NumPy 的dtype 类型指定:
np.dtype({'names':('name', 'age', 'weight'),
'formats':((np.str_, 10), int, np.float32)})
#复合类型也可以是元组列表
np.dtype([('name', 'S10'), ('age', 'i4'), ('weight', 'f8')])
#可以不指定类型名称:
np.dtype('S10,i4,f8')
"""
后一个字符指定的是数据的类型:字符、字节、整型、浮点型,等等(如表2-4 所示)。最后一个字符表示该
对象的字节大小。
表2-4:NumPy的数据类型
NumPy数据类型符号 描述 示例
'b' 字节型 np.dtype('b')
'i' 有符号整型 np.dtype('i4') == np.int32
'u' 无符号整型 np.dtype('u1') == np.uint8
'f' 浮点型 np.dtype('f8') == np.int64
'c' 复数浮点型 np.dtype('c16') == np.complex128
'S'、'a' 字符串 np.dtype('S5')
'U' Unicode 编码字符串 np.dtype('U') == np.str_
'V' 原生数据,raw data(空,void) np.dtype('V') == np.void
"""
#更高级的复合类型:
tp = np.dtype([('id', 'i8'), ('mat', 'f8', (3, 3))])#mat是一种矩阵,类似于array,CSDN收藏
X = np.zeros(1, dtype=tp)
print(X)#类似一个三维数组
print(X[0])
print(X['mat'][0])
print(X[0][1][1][1]) # 结构化数据和np数组切片区别!!!!np数组:x[1,2]
print("\n记录数组:结构化数组的扭转")
"""NumPy 还提供了np.recarray 类它和前面介绍的结构化数组几乎相同,
但是它有一个独特的特征:域,域可以像属性一样获取,而不是像字典的键那样获取"""
print(data['age'])
data_rec = data.view(np.recarray)#将这些数据转化成一个记录数组
print(data_rec.age)#获取方式变成了类似于函数属性的获取(也可以用data_rec['age']来获取)
#记录数组的缺点是会增加额外的时间开销
#os.system("pause")