'''
NumPy 是 Python 科学计算的基础包。
它是一个提供多维数组对象的 Python 库, 各种派生对象(例如掩码数组和矩阵),
以及 用于对数组进行快速操作的各种例程,包括 数学、逻辑、形状操作、排序、选择、I/O、
离散傅立叶变换,基本线性代数,基本统计 操作、随机模拟等等。

NumPy 包的核心是 ndarray 对象。
NumPy 的主要对象是同构多维数组。
它是一个 元素表(通常是数字),所有类型都相同,由 a 索引 非负整数元组。 在 NumPy 中,维度称为 轴 。
比如一个点在3D空间中的坐标 [1, 2, 1]具有 一轴。 那个轴有 3 个元素,所以我们说它有一个长度 共 3 个。
'''

import numpy as np
#arange函数用于创建等差数组,类似range函数,但其返回值是一个数据
a = np.arange(5) #[0 1 2 3 4]
b = np.arange(1,3) #[1 2]
c = np.arange(1,4,2) #[1 3]
print(a,b,c)
#reshape()是数组array中的方法,作用是将数据重新组织
a = np.array([1,2,3,4,5,6])
print(a.reshape(2,3))
# >>>[[1 2 3]
#   [4 5 6]]
b = np.arange(6)
print(b.reshape(1,6)) #[[0 1 2 3 4 5]]
#shape是查看数据有多少行多少列
a = np.array([1,2,3])
print(a.shape[0]) #3 a最外围有三个元素
b = np.array([[1,2,3],[4,5,6]])
print(b.shape[0]) #2 b最外围有两个列表
print(b.shape[1]) #3 b最内围有3个元素
#ndim 空间维度
a = np.arange(6).reshape(2,3)
print(a.ndim) #2 查看空间维度
#dtype 描述数组中元素类型的对象。
a = np.arange(6).reshape(2,3)
print(a.dtype.name) #int32
#itemsize 数组每个元素的大小(以字节为单位)
a = np.arange(6).reshape(2,3)
print(a.itemsize) #4 32位机,一个数字占4个字节
#size表示数据大小
a = np.arange(6).reshape(2,3)
b = np.arange(6)
print(a.size,b.size) #6 6 两组都是6
#type(a) 判断数字类型
a = np.arange(6)
print(type(a)) #<class 'numpy.ndarray'>
#array创建一个数组
a = np.array([1,2,3])
print(a) #[1 2 3]
'''
数组创建
'''
import numpy as np
#一、使用 array()函数创建
a = np.array([1,2,3])
print(a,a.dtype) #[1 2 3] int32
b = np.array([1.2,3.3])
print(b,b.dtype) #[1.2 3.3] float64

# array不能同时调用多个参数n
c = np.array([1,2,3],[4,5,6])
print(c) #Field elements must be 2- or 3-tuples, got '4'

#array将序列序列转换为多维数组
d = np.array(([1,2,3],[4,5,6]))
print(d)
# >>>[[1 2 3]
#     [4 5 6]]
e = np.array(([1,2,3],[4,5,6],[7,8,9]))
print(e)
# >>>[[1 2 3]
#     [4 5 6]
#     [7 8 9]]
#arrgy()函数也可以在数组创建过程中,指定类型
f = np.array([1,2,3],dtype=float)
print(f) #[1. 2. 3.]

#zeros创建一个充满零的数组
print(np.zeros((1,2))) #[[0. 0.]]

# ones创建一个满是 1 的数组
print(np.ones((1,2))) #[[1. 1.]]

# empty创建一个数组,其初始内容是随机的,并取决于 内存状态
# print(np.empty((2,3)))

# arange功能 这类似于 Python 内置的 range
print(np.arange(2)) #[0 1]

#arange与浮点参数一起使用,通常是 无法预测获得的元素数量
#linspace接收作为参数的数字,导出我们想要的数量
print(np.linspace(1,7,6)) #[1.  2.2 3.4 4.6 5.8 7. ]
'''
打印数组
打印数组时,NumPy 以类似于嵌套的方式显示它 列表,但具有以下布局:

    最后一个轴从左到右打印,

    倒数第二个是从上到下打印的,

    其余的也从上到下打印,每个切片 由一个空行与下一个分隔。

然后将一维数组打印为行,二维数组打印为 矩阵和三维作为矩阵列表。 

'''
import numpy as np
a = np.arange(6)  # 1d array
print(a)
# >>>[0 1 2 3 4 5]

b = np.arange(6).reshape(2,3)  # 2d array
print(b)
# >>> [[0 1 2]
#  [3 4 5]]

c = np.arange(12).reshape(2,2,3) # 3d array
print(c)
# >>>[[[ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]]]


#如果数组太大而无法打印,NumPy 会自动跳过 数组的中心部分,只打印角落
print(np.arange(10000)) #[ 0 1 2 ... 9997 9998 9999]
e = np.arange(10000).reshape(100,100)
print(e)
# >>>[[ 0 1 2 ... 97 98 99]
# [ 100 101 102 ... 197 198 199]
# [ 200 201 202 ... 297 298 299]
# ...
# [9700 9701 9702 ... 9797 9798 9799]
# [9800 9801 9802 ... 9897 9898 9899]
# [9900 9901 9902 ... 9997 9998 9999]]
 
'''
基本操作 
数组上的算术运算符按 应用 元素 。 一个新数组是 创建并填充结果。
'''
import numpy as np
a = np.arange(1,7) #[1 2 3 4 5 6]
b = np.array([10,20,30,40,50,60]) #[10,20,30,40,50,60]
print(b-a) #[ 9 18 27 36 45 54]
print(a**2) # [ 1  4  9 16 25 36]

#python numpy中三角函数中的数值是弧度,而计算器中的数值是角度
e = np.array([1,2])
print(np.sin(e)) #[0.84147098 0.90929743]
print(np.sin(30)) #-0.9880316240928618
print(np.sin(70*np.pi/180))  #0.9396926207859083
print(e<2) #[ True False]

#numpy中的矩阵叉乘用@或dot()函数(叉乘要满足第一个矩阵的列和第二个矩阵的行数是相等的), 点成用*
a = np.array([[1,2],
              [4,5]])
b = np.array([[1,0],
              [0,1]])
# print(a*b)
# >>>[[1 0]
#  [0 5]]
print(a@b)
print(a.dot(b))
# >>>[[1 2]
#  [4 5]]


#通过指定 axis参数,可以对应用轴进行操作
b = np.arange(12).reshape(3,4)
# print(b)
# >>>[[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
print(b.sum(axis=0)) #[12 15 18 21] 每列累计之和
print(b.sum(axis=1)) #[ 6 22 38] 每行累计之和

print(b.min(axis=0)) #[0 1 2 3] 每列最小
print(b.min(axis=1)) #[0 4 8] 每行最小

print(b.cumsum(axis=0)) #没列相加
# >>>[[ 0  1  2  3]
#  [ 4  6  8 10]
#  [12 15 18 21]]
''''
Numpy数学运算
'''
'''
一、初等函数
'''
#1、四则运算
import numpy as np

a = np.array([[0,1,2],
              [4,5,6]])
b = np.array([1,1,1])

print (np.add(a,b)) #add()相加函数
# >>>[[ 0  2  4]
#  [ 8 10 12]]

print (np.subtract(a,b)) #subtract()相减函数
# >>>[[-1  0  1]
#  [ 3  4  5]]

print (np.multiply(a,b)) #multiply()相除函数
# >>>[[0 1 2]
#  [4 5 6]]

print (np.divide(a,b)) #divide()相乘函数
# >>>[[0. 1. 2.]
#  [4. 5. 6.]]

#2、舍入函数
a = np.array([3.2,5.4,  45.09,  323,  38.6])
print (np.around(a)) #[  3.   5.  45. 323.  39.] around()保留个位数
print (np.around(a, decimals =  1)) #[  3.2   5.4  45.1 323.   38.6] 保留十位数
print (np.floor(a))  #[  3.   5.  45. 323.  38.] floor()向下取整
print (np.ceil(a))  #[  4.   6.  46. 323.  39.] ceil()向上取整

#取余
a = np.array([4,5,6])
b = np.array([2,2,2])
print(a//b) #[2 2 3] 除余取整
print(a%b) #[0 1 0] 取余

'''
高等函数
'''
#1三角函数 sin cos tan
np.set_printoptions(precision=3,suppress=True) #设置输出格式,精度为3
a = np.array([0,30,45,60,90])
# numpy上面的sin()函数自动计算的是弧度,需要换算,通过乘 pi/180 转化为角度
print (np.sin(a*np.pi/180))
print (np.cos(a*np.pi/180))
print (np.tan(a*np.pi/180))

#2.幂函数 power
a = np.array([1,2,3])
print(np.power(a,2)) #[1 4 9]

#3.绝对值 abs 开方sqrt,平方square,指数exp 对数log
c = np.array([[-1,-5,-2],
              [-7,3,9]])
print(np.abs(c))
# >>>[1 4 9]
# [[1 5 2]
#  [7 3 9]]

k = np.array([10,100,1000])
print(np.log10(k)) #[1. 2. 3.]

#符号函数sign
'''
sign(x)或者Sign(x)叫做符号函数,在数学和计算机运算中,其功能是取某个数的符号(正或负):
当x>0,sign(x)=1;
当x=0,sign(x)=0;
当x<0, sign(x)=-1
'''
g = np.array([-1,0,3,-7,7,0])
print(np.sign(g)) #[-1  0  1 -1  1  0]

 

'''
统计函数
'''
#1.最大最小值
#获取元素
import numpy as np
a = np.array([[4,6,5],
              [9,0,4],
              [1,5,3]])
print (a.min(1),    np.min(a,1)) #[4 0 1] [4 0 1]  最小值,沿行

print (a.max(1),    np.max(a,1))   #[6 9 5] [6 9 5]  最大值沿行

print (a.ptp(1),    np.ptp(a, axis=1))  #[2 9 4] [2 9 4]   最大与最小值的差,沿行

#获取索引
a = np.array([[70,10,90],
              [60,10,20],
              [10,50,30]])
print (np.argmax(a))  #获得展开后的最大值下标索引
print (a.flatten())   #展开数组
print (np.argmax(a, axis =  0)) #列的最大值索引
print (np.argmin(a, axis =  1)) #沿行的最小值索引

#算术平均
import numpy as np
a = np.array([[1,2,3],
              [3,4,5],
              [4,5,6]])
print(np.mean(a)) #整体平均数
print (np.mean(a, axis =  0)) #每列平均数
print (np.mean(a, axis =  1)) #每行平均数

#加权平均
a = np.array([1,2,3,4])
print (np.average(a)) # 不指定权重时相当于 mean 函数
wts = np.array([4,3,2,1])
print (np.average(a,weights = wts))
# 如果 returned 参数设为 true,则返回权重的和
print (np.average([1,2,3,  4],weights =  [4,3,2,1], returned =  True))

# 方差 var()函数/标准差std()函数
#标准差 :std = sqrt(mean((x - x.mean())**2))
print(np.std([1, 2, 3, 4]))
#方差:var = mean((x - x.mean())** 2)
print (np.var([1,2,3,4]))
'''
线性运算
'''
# dot:相当于矩阵的内积(叉乘,第一个行列式的列数要等于第二个行列式的行数)
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[11,12],[13,14]])
print(np.dot(a,b))
# >>>[[37 40]
#  [85 92]]

#vdot:将数组展开计算内积
a = np.array([[1, 2],
              [3, 4]])
b = np.array([[11, 12],
              [13, 14]])
# 1*11 + 2*12 + 3*13 + 4*14 = 130
print(np.vdot(a, b)) #130

#inner:对应行相乘求和
a = np.array([[1, 2],
              [3, 4]])
b = np.array([[11, 12],
              [13, 14]])
print(np.inner(a,b))
'''
索引、切片和迭代
'''
#一维 数组可以被索引、切片和迭代, 很像 列表 和其他 Python 序列
import numpy as np
a = np.arange(9).reshape(3,3)
print(a[0]) #[0 1 2]
print(a[0][0]) #0

b = np.array([0,1,2,3,4])
print(b[0]) #0
print(b[:3]) #[0 1 2]

#替换
c = np.array([5,6,7,8,9])
c[:3:2] = 100
print(c) #[100   6 100   8   9]

#倒置
print(c[::-1]) #[  9   8 100   6 100]

#可以for循环
# for i in c:
#     print(i)

#多维 数组的每个轴可以有一个索引。 这些指数 以逗号分隔的元组给出:

# fromfunction()函数用于创建一个函数列表
def func(x,y):
    print('x:',x)
    print('y:',y)
    print('x+y:',x+y)
    return 0
b = np.fromfunction(func,(2,2),dtype=int)
print(b)
# >>>x: [[0 0]
#  [1 1]]
# y: [[0 1]
#  [0 1]]
# x+y: [[0 1]
#  [1 2]]

e = np.array([[ 0,  1,  2,  3],
            [10, 11, 12, 13],
            [20, 21, 22, 23],
            [30, 31, 32, 33],
            [40, 41, 42, 43]])
print(e[1,1]) #11
print(e[0:4, 2]) #e[0:4(截取列的长度), 2(第几列)]
print(e[1:2,2]) #e[1:2(截取哪几行),2(第几个数)]

#当提供的索引少于轴数时,缺失的 索引被认为是完整的切片 :
# print(e[-1] )  #[40 41 42 43] 等同于 e[-1, :])

g = np.array([[[  0,  1,  2],  # a 3D array (two stacked 2D arrays)
               [ 10, 12, 13]],
               [[100, 101, 102],
               [110, 112, 113]]])
print(g.shape) #(2, 2, 3) 最外围两个元素,每个元素有2轴,3纵

#迭代 多维数组是关于 第一轴
for low in g:
    print(low)
# >>>[[ 0  1  2]
#  [10 12 13]]
# [[100 101 102]
#  [110 112 113]]

#但是,如果要对数组中的每个元素执行操作 数组,可以使用 flat属性是 迭代器 遍历数组的所有元素
for element in g.flat:
    print(element,end='\t') #0    1    2    10    12    13    100    101    102    110    112    113    
'''
形状操作
'''
#改变数组的形状
#数组的形状由沿每个轴的元素数量决定
import numpy as np
a = np.floor(10*np.random.random((3,4))) #np.random.random((3,4))随机生成一个3行四列的0-1浮点数 floor()向下取整
print(a)
print(a.shape)

#ravel()将多维数组转变为一维数组
print(a.ravel())


#reshape函数返回其 具有修改形状的参数,而 resize方法修改数组 本身
k = np.array([1,2,3,4,5,6])
print(k.reshape((2, 3)))
'''
将不同的数组堆叠在一起
'''
import numpy as np
# a = np.floor(10*np.random.random((3,2)))
# print(a)
b = np.array([[1,2,3],
             [4,5,6]])
c = np.array([[7,8,9],
             [10,11,12]])
#vstack()将数组上下叠加,hstack()将数组左右叠加(只适用于二维数组)
print(np.vstack((b,c)))
# >>>[[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]
print(np.hstack((b,c)))
# >>>[[ 1  2  3  7  8  9]
#  [ 4  5  6 10 11 12]]

#功能 column_stack将一维数组作为列堆叠到二维数组中。 它相当于 hstack仅适用于二维数组
g = np.array([[1,2,3,4],[1,2,3,4]])
h = np.array([[5,6,7,8],
              [9,10,11,12]])
print(np.column_stack((g,h)))
# >>>[[ 1  2  3  4  5  6  7  8]
#  [ 1  2  3  4  9 10 11 12]]
'''
将一个数组拆分成几个较小的数组
'''
#使用 hsplit,你可以拆分一个 沿其水平轴的数组,
# 或者通过指定数量 要返回的相同形状的数组,或通过指定后面的列 应该发生的分裂
import numpy as np
a = np.floor(10*np.random.random((2,8)))
print(np.hsplit(a,2))

#vsplit沿垂直方向分裂 轴
print(np.vsplit(a,2))

# array_split允许 一个指定沿哪个轴拆分
print(np.array_split(a,2,axis=0)) #沿列分裂
'''
副本和视图
'''
#在操作和操作数组时,有时会复制它们的数据 进入一个新数组,有时不是,有三种情况
#没有复制  简单赋值不会复制对象或其数据。
import numpy as np
a = np.array([[ 0,  1,  2,  3],
              [ 4,  5,  6,  7],
              [ 8,  9, 10, 11]])
b = a            # no new object is created
print(b is a)           #True   a and b are two names for the same ndarray object

#视图或浅拷贝  不同的数组对象可以共享相同的数据。 这 view方法 创建一个查看相同数据的新数组对象。
c = a.view()
print(c is a) #False
print(c.base is a)  #True           # c is a view of the data owned by a
print(c.flags.owndata) #False
c = c.reshape((2, 6))  # a's shape doesn't change
print(a.shape) #(3, 4)
c[0, 4] = 1234         # a's data changes
print(a)
# >>>[[   0    1    2    3]
#  [1234    5    6    7]
#  [   8    9   10   11]]

#深拷贝 这 copy方法制作数组及其数据的完整副本。
d = a.copy()  # a new array object with new data is created
print(d is a) #False
print(d.base is a)  #False  d doesn't share anything with a
d[0, 0] = 9999
print(a)
# >>>([[   0,   10,   10,    3],
#        [1234,   10,   10,    7],
#        [   8,   10,   10,   11]])