lee-romantic 's Blog
Everything is OK!
Toggle navigation
lee-romantic 's Blog
主页
About Me
归档
标签
numpy模块的基础使用
2018-09-26 18:23:40
164
0
0
lee-romantic
简书上写得很好的一篇numpy教程: https://www.jianshu.com/p/60bf50100c2f #一.基础篇 NumPy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(通常是元素是数字)。在NumPy中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。 例如,在3D空间一个点的坐标 [1, 2, 3] 是一个秩为1的数组,因为它只有一个轴。那个轴长度为3.又例如,在以下例子中,数组的秩为2(它有两个维度).第一个维度长度为2,第二个维度长度为3. ``` a=[[ 1., 0., 0.], [ 0., 1., 2.]]#a是list类型的,且其元素是浮点类型的,不会有reshape方法 import numpy as np a=np.arange(15).reshape(3,5)#aa是numpy.ndarray类型的,可以通过type()方法查看 from numpy import * #这样子可以不给模块取名 a=arange(24).reshape(2,3,4) ``` Python已有列表类型,为什么需要一个数组对象(类型)? 例:计算 A 2 +B 3 ,其中,A和B是一维数组。 方法1: ``` def pysum(): a = [0, 1, 2, 3, 4,] b = [9, 8, 7, 6, 5,] c = [] for i in range(len(a)): c.append(a[i]**2 + b[i]**2) return c print(pysum()) ``` 方法2: ``` import numpy as np def npsum(): a = np.array([0, 1, 2, 3, 4,]) b = np.array([9, 8, 7, 6, 5,]) c = a**2 + b**2 return c print(npsum()) ``` 对比方法1和方法2,我们可以得到: • 数组对象可以去掉元素间运算所需的循环,使一维向量更像单个数据 • 设置专门的数组对象,经过优化,可以提升这类应用的运算速度 观察:科学计算中,一个维度所有数据的类型往往相同 •数组对象采用相同的数据类型,有助于节省运算和存储空间 `ndarray`是一个多维数组对象,由两部分构成: • 实际的数据 • 描述这些数据的元数据(数据维度、数据类型等) ndarray数组一般要求所有元素类型相同(同质),数组下标从0开始 NumPy的数组类被称作 `ndarray `。通常被称作数组。注意`numpy.array`和标准Python库类`array.array`并不相同,后者只处理一维数组和提供少量功能。更多重要ndarray对象属性有: ``` ndarray.ndim 返回数组轴的个数,在python的世界中,轴的个数被称作秩 ndarray.shape 返回数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n排m列的矩阵,它的shape属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim属性 返回ndarray.size 数组元素的总个数,等于shape属性中元组元素的乘积。 返回ndarray.dtype 一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外NumPy提供它自己的数据类型。 返回ndarray.itemsize 数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8). 返回ndarray.data 包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。 ```     **ndarray为什么要支持这么多种元素类型?** 对比:Python语法仅支持整数、浮点数和复数3种类型 • 科学计算涉及数据较多,对存储和性能都有较高要求 • 对元素类型精细定义,有助于NumPy合理使用存储空间并优化性能 • 对元素类型精细定义,有助于程序员对程序规模有合理评估 非同质的情况下,数组的各种属性已发生变化,与同质情况不同,不必去深究它。 非同质ndarray对象无法有效发挥NumPy优势,尽量避免使用 #二.ndarry的创建 ###方法1:从Python中的列表、元组等类型创建ndarray数组 ``` x = np.array(list/tuple) x = np.array(list/tuple, dtype=np.float32) ``` 当np.array()的参数不指定dtype时,numpy将根据数据的情况关联一个dtype类型 例子: ``` x1=np.array((1,2,3,4)) x2=np.array([2,4,5,6],np.float32) x3=np.array([[1,2,4,5],[23,4,56,7]],np.float32) x4=np.array([[1,2,4,5],(23,4,56,7)],np.int8)#这样混合列表和元组使用也可以 ``` ###方法2:使用numpy中函数创建ndarray数组,如:arange, ones, zeros等 1.使用np.arange(n)函数:类似range()函数,返回ndarray类型,元素从0到n-1,例如: ``` x1=np.arange(6) x1=x1.reshape((2,3))#要注意reshape()不改变原来的ndarray数组,只会生成一个新的 ``` 2.使用np.ones(shape)函数: 根据shape生成一个元素全为1的数组,shape是元祖类型(np.zeros()类似),没有指定元素数据类型时,默认为浮点型 ``` np.ones((2,4))#只能是tuple参数 array([[1., 1., 1., 1.], [1., 1., 1., 1.]]) ``` 3.使用np.full(shape, val)函数:根据shape生成一个数组,每个元素值均为val,shape是元祖类型 ``` x1=np.full((2,3),4) ``` 4.使用np.eye(n)函数:创建一个正方形的n*n单位矩阵,对角线元素为1,其余为0 ``` np.eye(5) array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]]) ``` 5.拓展 np.ones_like(a) :根据数组a的形状生成一个元素全为1的数组; np.zeros_like(a) :根据数组a的形状生成一个元素全为0的数组; np.full_like(a,val) :根据数组a的形状生成一个元素全为val的数组; ###方法3:使用numpy中的其它函数创建ndarray数组 1. np.linspace():根据起止数据等间距地填充数据,第三个参数代表数组的总元素数量,形成数组 ``` x1=np.linspace(2,10,4,dtype=np.int32)# x1 array([ 2, 4, 7, 10]) ``` ``` x2=np.linspace(1,10,4,endpoint=False,dtype=np.float32) x2 array([1. , 3.25, 5.5 , 7.75], dtype=float32) ``` 如上,参数endpoint=False,在1到10之间等间距取4个数,舍弃最后一个数。 2. np.concatenate(): 将两个或多个数组合并成一个新的数组 ``` x=np.concatenate((x1,x2)) x array([ 2. , 4. , 7. , 10. , 1. , 3.25, 5.5 , 7.75]) ``` #三.数组变换 ###1维度变换 1. reshape(shape):不改变数组元素,返回一个shape形状的数组,原数组不变。参数可以为tuple,或者直接整型数字 2. resize(shape):不改变数组元素,不返回一个shape形状的数组,而且原数组改变。 3. flatten():对数组进行降维,返回折叠后的一维数组,原数组不变 ###2类型变换 new_a是新数组,a是原数组,转换其元素的类型,如下: ``` new_a = a.astype(new_type) ``` ###3.数组向列表的转换: 函数: ``` ls = a.tolist() ``` #四.数组索引和切片 **索引:**获取数组中特定位置元素的过程 **切片:**获取数组元素子集的过程 ###1.一维数组的索引和切片:与Python的列表类似 ``` a=np.arange(10) a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) a[4] 4 a[2:] array([2, 3, 4, 5, 6, 7, 8, 9]) a[3:8:2]#注:起始编号为3,终止编号为8(不包括),步长为2 array([3, 5, 7]) ``` ###2.多维数组的索引和切片 多维数组索引:每个维度一个索引值,逗号分割 ``` a=np.arange(24).reshape(2,3,4) a array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) a[0,0,3]#索引第四个元素 3 ``` 多维数组的切片:每个维度一个切片值,逗号分割(有几个冒号,则生成的数组有几个维度) ``` a=np.arange(24).reshape(2,3,4) a array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) a[:,2,1]#索引9,和21,有几个冒号,则生成的数组有几个维度 array([ 9, 21]) #下面两种索引的值是一样的,但是冒号个数不同,维度不一样 a[:,:,1:2] array([[[ 1], [ 5], [ 9]], [[13], [17], [21]]]) a[:,:,1]#生成二维的切片数组 array([[ 1, 5, 9], [13, 17, 21]]) ``` 使用步长跳跃来切片: ``` a=np.arange(24).reshape(2,3,4) a[:,:,1:3:1] array([[[ 1, 2], [ 5, 6], [ 9, 10]], [[13, 14], [17, 18], [21, 22]]]) ``` #五.ndarray数组数组的运算: ###数组与标量之间的运算:数组与标量之间的运算作用于数组的每一个元素 ``` import numpy as np from numpy import * a=arange(24).reshape(2,3,4) print(a) [[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]] import numpy as np from numpy import * a=arange(24).reshape(2,3,4) a.mean() 11.5 import numpy as np from numpy import * a=arange(24).reshape(2,3,4) a/a.mean()#对每个元素都进行该操作 array([[[0. , 0.08695652, 0.17391304, 0.26086957], [0.34782609, 0.43478261, 0.52173913, 0.60869565], [0.69565217, 0.7826087 , 0.86956522, 0.95652174]], [[1.04347826, 1.13043478, 1.2173913 , 1.30434783], [1.39130435, 1.47826087, 1.56521739, 1.65217391], [1.73913043, 1.82608696, 1.91304348, 2. ]]]) ``` ###numpy的一元函数: 关于shape和size ``` import numpy as np c =np.ones([2,3]) np.shape(c) #返回tuple,表示形状 c.shape #同上,没有shape()成员函数 np.size(c) #返回size,即元素总的个数 c.size #同上,... #另外,torch中求shape或者size,可以转换到numpy中来算,比如,假设tensor是个张量, tensor.numpy().size #返回tensor中元素的个数 ``` 总结,关于torch和numpy的size,shape: size和shape在numpy中是成员变量(而不是成员函数),size表示元素总个数,shape表示ndarray的数组的形状,size()和shape()是numpy的全局函数,意义与size,shape一致; size()在torch中,是tensor的成员函数,返回tensor的形状(改变tensor的形状用tensor=tensor.view(2,3)或者tensor=tensor.reshape(),均是需要拷贝),shape在torch中,是tensor的一个成员变量; tensor中,都没有size()和shape()的全局函数,即没有torch.shape()和torch.size() ``` import torch import numpy as np b=torch.ones([2,3]) #print(torch.shape(b)) #错误,torch中没有shape()方法 print(b.shape) #正确,shape是tensor的成员变量,故b.shape()是错误的 #print(torch.size(b)) #错误,torch中没有size()方法 print(b.size()) #正确,size()是tensor的成员函数,返回的是形状(rows,cols)而不是总的元素个数,因此,b.size不会报错,返回的是该函数,而不是size变量 #numpy中的size成员变量指的是元素的总个数,不是形状 #可以记为,在torch中,只有tensor有一个size()方法和一个shape变量,在ndarray中,size和shape是变量,ndarray没有任何成员函数size(),shape();在numpy中,有size()和shape()方法 b=b.view(1,-1) #等效于b=b.reshape(1,-1)#系统会自动根据总元素个数把-1替换掉 #tensor转换到ndarray print(b.numpy().size) print(np.size(b.numpy())) print(b.numpy().shape) print(np.shape(b.numpy())) ``` 结果: ``` torch.Size([2, 3]) torch.Size([2, 3]) 6 6 (1, 6) (1, 6) ``` >np.abs(x)或np.fabs(x) : 计算数组各元素的绝对值 np.sqrt(x):计算数组各元素的平方根 np.square(x): 计算数组各元素的平方 np.log(x) np.log10(x) np.log2(x) : 分别表示数组各元素的自然对数、以10为底的对数、以2为底的对数 np.ceil(x) np.floor(x) : ceil中文为天花板,即朝正无穷大方向取整;floor中文为地板,即朝负无穷大方向取整。 np.rint(x) : 计算数组各元素的四舍五入值 np.modf(x) : 将数组各元素的小数和整数部分以两个独立数组形式返回 np.cos(x) np.cosh(x) np.sin(x) np.sinh(x) np.tan(x) np.tanh(x) : 计算数组各元素的普通型和双曲型三角函数 np.exp(x) :计算数组各元素的指数值 np.sign(x) :计算数组各元素的符号值,1(+),0,-1(-) ###numpy的二元函数: ``+ - * / ** ``: 两个数组各元素进行对应运算 np.maximun(x,y) 或np.fmax(x,y) : 元素级的最大值 ``` >>> np.fmax([2, 3, 4], [1, 5, 2]) array([ 2., 5., 4.]) >>> >>> np.fmax(np.eye(2), [0.5, 2]) array([[ 1. , 2. ], [ 0.5, 2. ]]) ``` np.minimun(x,y) 或np.fmin(x,y) : 元素级的最小值 np.mod(x, y) : 元素级的模运算 np.copysign(x, y) : 将数组y中各元素值的符号赋值给数组x对应的元素 > < >= <= == != : 算术比较,产生布尔型数组 #六.numpy提供的数据存取方法 ##数据的CSV文件保存 CSV(Comma-Separated Value,逗号分隔值) CSV是一种常见的文件格式,用来存储批量数据  上图右侧便是CSV文件的内容。 用法: ``` np.savetxt(frame, array, fmt='%.18e', delimiter=None) ``` frame:文件、字符串或产生器,可以是.gz或.bz2的压缩文件 array:存入文件的数组 fmt:写入文件的格式,例如:%d %.2d %.18e delimiter : 分隔字符串,默认是任何空格  经过上述两行代码操作,文件便已经被保存下来,打开保存的文件后如下图所示:  在np.savetxt('a.csv', a, fmt='%d', delimiter=',')中,参数'a.csv'表示的保存后的文件的文件名是a.csv;参数a指的是要保存的数组,参数fmt='%d'表示的是元素以整数类型保存,参数dilimiter=','表示元素间以‘,’分隔 注意:csv文件不支持保存多维数据。例如:  输入上述两行代码后,会报错:  ##数据的CSV文件读取 用法举例: ``` np.loadtxt(frame, dtype=np.float, delimiter=None, unpack=False) ``` frame : 文件、字符串或产生器,可以是.gz或.bz2的压缩文件 dtype: 数据类型,可选 delimiter : 分割字符串,默认是任何空格 unpack : 如果True,读入属性将分别写入不同变量 举例: 读取之前保存的a.csv文件   CSV文件的局限性:只能存取一维和二维数组,np.savetxt() np.loadtxt()只能存取一维和二维数组 ##多维数组的保存: 用法举例: ``` a.tofile(frame, sep='', format='%s') ``` frame : 文件、字符串 sep : 数据分割字符串,如果是空串,写入文件为二进制 format : 写入数据的格式 例子:  打开文件a.dat后,可以看到:  注意:如果sep='',即数据分隔字符串是空串,写入的文件为二进制。  查看文件b.dat的属性:  ##多维数组的读取: 用法举例: np.fromfile(frame, dtype=np.float, count=-1, sep='') frame : 文件、字符串 dtype : 读取的数据类型 count : 读入元素个数,‐1表示读入整个文件 sep : 数据分割字符串,如果是空串,写入文件为二进制 例子: 读取先前保存的文件a.dat  与下图对比:  我们发现,多维数组保存时,维度会转化为一维。 ##numpy的便捷文件存取: 用法举例: ``` np.save(fname, array) 或 np.savez(fname, array) ``` fname : 文件名,以.npy为扩展名,压缩扩展名为.npz rray : 数组变量 ``` np.load(fname) ``` fname: 文件名,以.npy为扩展名,压缩扩展名为.npz 例子:  查看文件a.npy:  读取文件:  总结: numpy库提供的数据存取方式有三种: CSV文件存取:适用于一维二维数组的存取 dat文件存取:适用与多维数组的存取 便捷文件存取:优点:适用于一维二维多维数组的存取,用法最为简单便捷。缺点:保存的文件为二进制文件,该文件里的内容为二进制数据,不利于查看。 #七.numpy的随机数,统计,梯度函数 ##numpy的随机数函数 numpy的random子库:np.random.*,主要有np.random.rand() np.random.randn() np.random.randint() rand(d0,d1,d2,……,dn) ###1.rand(d0,d1,d2,……,dn) : 以d0-dn作为维度,创建随机数组,浮点数,范围是[0,1),均匀分布 ``` import numpy as np a=np.random.rand(3,4) a array([[0.87340312, 0.53142508, 0.39082832, 0.46586324], [0.53417197, 0.02404137, 0.81318624, 0.49652126], [0.42879202, 0.33226915, 0.25924693, 0.37684525]] ``` ###np.random.randn(d0,d1,d2,……,dn) : 以d0-dn作为维度,创建随机数组,标准正态分布 ``` import numpy as np from numpy import * a=np.random.randn(2,3,4) a array([[[ 1.7511284 , -1.01064942, -0.35983204, -1.91155698], [ 0.12427668, -0.27154829, 1.4471842 , -0.86974719], [-1.89106845, 0.74167594, -2.25162774, -2.9822369 ]], [[-0.74117229, -0.90082238, -0.06387721, 0.85173897], [-0.06964638, 0.75300328, -1.04470201, -1.89285774], [ 0.22495269, 0.37949431, -0.47418848, 1.90216223]]]) ``` ###np.random.randint(low, high, shape) : 根据shape形状创建随机数数组,范围是[low, high)左开右闭 ``` import numpy as np a=np.random.randint(2,9,(4,3)) a array([[5, 8, 4], [5, 6, 3], [7, 3, 6], [7, 8, 4]]) #特别的,下面两条代码等效 a=np.random.randint(1,9,(8,))#产生一个一维数组,与np.random.randint(1,9,(8,1))是很不一样的 a=np.random.randint(1,9,(1,8)) ``` ###np.random.seed((s) : 随机数种子,s是给定的种子值,给定种子值,产生的随机数不变 ``` import numpy as np np.random.seed(3) a=np.random.randint(2,9,(4,3)) a array([[4, 2, 3], [5, 2, 2], [2, 7, 7], [5, 4, 5]]) ``` ###np.random.shuffle(a): 对数组a的每一纵列进行随机排列,数组a发生改变 ``` import numpy as np np.random.seed(3) a=np.random.randint(2,9,(4,3)) print(a) np.random.shuffle(a) a [[4 2 3] [5 2 2] [2 7 7] [5 4 5]] array([[2, 7, 7], [4, 2, 3], [5, 4, 5], [5, 2, 2]]) ``` ###np.random.permutation(a) :根据数组a的每一纵列进行随机排列,数组a不改变(与shuffle类似) ``` import numpy as np np.random.seed(3) a=np.random.randint(2,9,(4,3)) print(a) a=np.random.permutation(a) a [[4 2 3] [5 2 2] [2 7 7] [5 4 5]] array([[2, 7, 7], [4, 2, 3], [5, 4, 5], [5, 2, 2]]) ``` ###np.random.choice(a, size, replace,p):从**一维数组a**中以概率p抽取元素,形成size形状的新数组,replace表示是否可以重用元素,默认为True ``` import numpy as np p=np.array([0.7,0.01,0.01,0.05,0.02,0.01,0.0,0.2])#p也需要是一维的,通常可以用a/a.mean()来代替,因为是概率,故每个元素加起来要等于1才行 a=np.arange(8) print(a) np.random.choice(a,(2,4),True,p) [0 1 2 3 4 5 6 7] array([[7, 0, 0, 0], [0, 0, 0, 0]]) ``` uniform(low, high, size) : 产生具有均匀分布的数组,low起始值,high结束值,size形状 normal(loc,scale,size) : 产生具有正态分布的数组,loc均值,scale标准差,size形状 poisson(lam,size) : 产生具有泊松分布的数组,lam随机事件发生率,size形状 ##统计函数 已知数组a: ``` import numpy as np a=np.arange(15).reshape(3,5) a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) ``` ###np.sum(a, axis=None) : 根据给定轴axis计算数组a相关元素之和,axis整数或元组。 ``` import numpy as np a=np.arange(15).reshape(3,5) print(np.sum(a,axis=None)) print(np.sum(a,None)) print(np.sum(a)) 105 105 105 ``` ``` import numpy as np a=np.arange(15).reshape(3,5) print(a) print(np.sum(a,axis=0)) print(np.sum(a,axis=1)) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] [15 18 21 24 27] [10 35 60] ``` 结论: 当axis=None时,np.sum(a)表示数组a的所有元素总和 当axis=0时,表示的是数组a各纵列元素之和 当axis=1时,表示的是数组a各横列元素之和 ###mean(a, axis=None) :根据给定轴axis计算数组a相关元素的期望,axis整数或元组,与上面的sum类似: ``` import numpy as np a=np.arange(15).reshape(3,5) print(a) print(np.mean(a,axis=0)) print(np.mean(a,axis=1)) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] [5. 6. 7. 8. 9.] [ 2. 7. 12.] ``` ###average(a,axis=None,weights=None):根据给定轴axis计算数组a相关元素的加权平均值 weights=None时: ``` import numpy as np a=np.arange(15).reshape(3,5) print(a) np.average(a) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] 7.0 ``` ``` import numpy as np a=np.arange(15).reshape(3,5) print(a) print(np.average(a,0)) print(np.average(a,axis=1)) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] [5. 6. 7. 8. 9.] [ 2. 7. 12.] ``` weight != None 时: ``` import numpy as np a=np.arange(15).reshape(3,5) print(a) print(np.average(a,axis=0,weights=[1,2,3])) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] [ 6.66666667 7.66666667 8.66666667 9.66666667 10.66666667] ``` std(a, axis=None) : 根据给定轴axis计算数组a相关元素的标准差 var(a, axis=None) : 根据给定轴axis计算数组a相关元素的方差 min(a) max(a) : 计算数组a中元素的最小值、最大值 argmin(a) argmax(a) : 计算数组a中元素最小值、最大值的降一维后下标 unravel_index(index, shape) : 根据shape将一维下标index转换成多维下标 ptp(a) : 计算数组a中元素最大值与最小值的差 median(a) : 计算数组a中元素的中位数(中值) ##numpy的梯度函数: np.gradient(a) :计算数组a中元素的梯度,当a为多维时,返回每个维度梯度 梯度:连续值之间的变化率,即斜率 XY坐标轴连续三个X坐标对应的Y轴值:a, b, c,其中,b的梯度是: (c‐a)/2 ``` import numpy as np a=np.random.randint(0,20,(5,)) print(a) print(np.gradient(a)) [12 19 16 2 7] [ 7. 2. -8.5 -4.5 5. ] ``` 多维数组: ``` import numpy as np a=np.random.randint(10,30,(3,4)) print(a) print(np.gradient(a)) [[28 11 13 23] [28 11 28 12] [13 27 21 17]] [array([[ 0. , 0. , 15. , -11. ], [ -7.5, 8. , 4. , -3. ], [-15. , 16. , -7. , 5. ]]), array([[-17. , -7.5, 6. , 10. ], [-17. , 0. , 0.5, -16. ], [ 14. , 4. , -5. , -4. ]])] ``` 在上图中:上侧表示最外层维度(axis=0)的梯度,下侧表示第二层维度(axis=1)的梯度。 --------------------- 本文来自 谢旭庞 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qq_41149269/article/details/81238311?utm_source=copy
上一篇:
指针无处不在
下一篇:
windows10/ubuntu 加anaconda配置pytorch环境
0
赞
164 人读过
新浪微博
微信
腾讯微博
QQ空间
人人网
提交评论
立即登录
, 发表评论.
没有帐号?
立即注册
0
条评论
More...
文档导航
没有帐号? 立即注册