#%% md
## ndarray
#%% md
##### ndarray的特性
#%% md
###### 多维性
#%%
import numpy as np
#%%
arr = np.array(5) #创建一个ndarray数组
print('arr的维度是:', arr.ndim)
#%%
arr = np.array([1, 2, 3])
print(arr)
print('arr的维度是:', arr.ndim)
#%%
arr = np.array([[1, 2, 3],[4, 5, 6]])
print(arr)
print('arr的维度是:', arr.ndim)
#%% md
###### 同质性
#%%
# 所有元素类型强制相同
arr = np.array([1, 2, 'hallo']) #不同数据类型会被强制转换成字符串
print(arr)
print(arr.dtype)
#%%
arr = np.array([1, 2.5])
print(arr)
print(arr.dtype)
arr = arr.astype("i8") #调整数据类型
print(arr)
print(arr.dtype)
#%% md
##### ndarray的属性
#%%
# shape 数组的形状
# ndim 维度数量
# size 总元素个数
# dtype 元素类型
# T 转置(行转列,列转行)
# flags 内存存储方式:是否连续存储
# npytes 数组总内存占用量
# itemsize 单个元素占用的内存字节数(高级优化)
#%%
arr1 = np.arange(1, 10)
print(arr1)
print("元素的形状",arr1.shape)
print("元素的维度",arr1.ndim)
print("元素的类型",arr1.dtype)
print("内存存储方式:",arr1.flags)
print("单个元素占用的内存字节数:",arr1.itemsize)
print("数组本身的类型:",type(arr)) #数组的类型都是numpy.ndarray
#%%
arr2 = np.array([[1, 2, 3],[4, 5, 6]])
print(arr2)
print("元素的转置:\n",arr2.T)
#%% md
##### ndarray的创建
#%%
arr = np.array([1, 2, 3])
print(arr.ndim)# 维度
arr = np.arange(1,4,2) # (开头,结尾,步长)
print(arr)
#%%
list1 = [1, 2, 3, 4, 5, 6]
arr = np.array(list1, dtype=np.float16)
print(arr)
print(arr.dtype)
print(arr.shape)
arr1 = arr.reshape(2, 3)
print(arr1)
print(arr1.shape)
#%%
arr1 = np.copy(arr) # 直接使用 = 号会导致指针指向同一个地址,copy的数据是新地址
print(arr1)
#%%
arr = np.zeros((2, 3))
print("np.zeros",arr)
arr = np.ones((5, 3))
print("np.ones",arr)
arr = np.empty((2, 3))
print("np.empty",arr)
#%%
arr = np.empty_like(arr1)
print("empty_like",arr)
arr2 = np.zeros_like(arr1)
print(arr2)
arr2 = np.full((2, 6), 2025)
print(arr2)
#%%
arr = np.arange(0, 20, 2) #最后一个是步长
print(arr)
arr = np.linspace(0, 20, 11) #最后一个是取多少个数
print(arr)
arr = np.logspace(0, 6, 3, base=2) #给base开平方
print(arr)
#%% md
#### 矩阵
#%%
# 向量 0维
# 向量 1维
# 矩阵 2维
# 张量 3维
#%%
# 特殊矩阵
arr = np.eye(3, 4, dtype=int) #特殊矩阵在横纵坐标相同的位置生成1
print(arr)
#%%
# 对角矩阵
arr = np.diag([1, 2, 4, 3]) #在主对角线上生成数列
print(arr)
#%%
# 随机数生成(0 ~ 1)
arr = np.random.rand(2, 4)
print(arr)
#%%
# 生成指定范围的随机数
arr = np.random.uniform(2, 10, (2, 3)) # 第一,二个数确定随机范围,括号确定矩形形状
print(arr)
#%%
# 指定范围的随机整数
arr = np.random.randint(2, 10, (2, 3))
print(arr)
#%%
# 生成随机数列(正态分布)(-3 ~ 3)
arr = np.random.randn(2, 4)
print(arr)
#%%
# 设置随机种子
# 可以用一个种子数固定生成的随机数据,一个相同的种子名对应数据相同
np.random.seed(20)
arr = np.random.randint(1, 10, (2, 5))
print(arr)
#%% md
##### 数据类型
#%%
# int, uint, bool, float
# 复数类型
# complex64 (两个32浮点数)
# complex128 (两个64浮点数)
# 初始化数据类型,三种方法
arr = np.array([2, 0, 1, 0], dtype=bool)
print(arr)
arr = np.array([2, 0, 1, 0], dtype="int32")
print(arr.dtype)
arr = np.array([2, 0, 1, 0], dtype=np.float16)
print(arr.dtype)
#%%
# 修改数据类型
# astype
arr = np.array([2, 0, 1, 0], dtype=np.float16)
arr = arr.astype(np.int8)
print(arr.dtype)
print(arr)
#%% md
##### 索引与切片
#%%
# 基本索引
# 行列切片
# 连续切片
# 使用slice切片
# 布尔索引
# 一维数组
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,26, 27, 28, 29, 30, ])
print(arr[20]) # 基本索引
print(arr[2:4]) # 行列切片,左包右不包
print(arr[:])
print(arr[arr>12]) # 布尔索引
print(arr[(arr>10) & (arr<18)])
print(arr[slice(2, 3, 1)])# 布尔索引# 使用slice切片
#%%
# 二维数组
arr = np.random.randint(2, 100, (3, 6))
print(arr)
print(arr[1, 3]) #基础索引
print("arr[1:2,3:5]:",arr[1:2,3:5]) #第一个控制哪几行,第二个控制哪几列
print("arr[2][arr[2]>20]:",arr[2][arr[2]>20]) #bool索引
print("arr[:,3]:",arr[:,3])
#%% md
##### 数据的运算
#%%
#算数运算
# 一一对应相加
a = np.array([1, 2, 3])
b = np.array([4, 5, 5])
print(a + b)
print(a - b)
print(a * b)
print(a / b)
#%%
# 原生的加法是向后延长添加
c = [1, 3, 4]
d = [2, 5, 7]
print(c + d)
for i in range(3):
d[i] += c[i]
print(d)
#%%
a = np.array([[1, 3, 4],[2, 4, 5]])
b = np.array([[28, 29, 30,],[23, 52, 21]])
print(a + b)
print(a - b)
print(a * b)
print(a / b)
#%%
a = np.array([[1, 3, 4],[2, 4, 5],[2, 4, 6]])
print(a + 4)
print(a * 2)
#%%
# 广播机制:1,判断能不能广播
# 格式相同对应相加,对应不上直接报错
a = np.array([[1, 3, 4],[2, 4, 5],[2, 4, 6]])
b = np.array([2, 4, 6])
c = np.array([[1],[2],[2]])
print(a + b) #b扩充成3*3相加
print(a + c) #c扩充成3*3相加
print(b + c) #b,c扩充成3*3相加
#%%
# 矩阵的运算
a = np.array([[2, 4, 5],[1, 3, 4],[2, 4, 6]])
b = np.array([[1, 3, 4],[2, 4, 6],[2, 4, 5]])
print(a * b)
#%%
'''
2 4 5
1 3 4
2 4 6
1 3 4
2 4 6
2 4 5
'''
print(a @ b)
# 第[1][1]个位置的数,是让a的第一行乘以b的第一列再相加得到第一个数20
# 第[n][m]个位置的数,是让a的第n行乘以b的第m列再相加得到
# 用原生代码实现a @ b
for i in range(3):
for j in range(3):
sum_num = 0
for m in range(3):
c = b[m][j] * a[i][m]
sum_num += c
print(sum_num, end=" ")
print()
#%% md
#### 常用函数
###### 基本数学函数
#%%
# 基本数学
# np.sqrt(x) # 计算x的平方根
print(np.sqrt(5))
print(np.sqrt([1, 4, 9]))
# np.exp(x) # 计算e的x次方
print(np.exp(1))
# np.log(x) # 计算自然对数(以e为底)
print(np.log(np.e))
# np.sin(x) # 计算正弦值
print(np.sin(np.pi/2))
# np.abs(x) # 计算绝对值
print(np.abs(-5))
# np.power(a, b) # 计算a的b次幂
print(np.power(2, 3))
# np.round(x, n) # 对x进行四舍五入,保留n位小数
print(np.round(3.1415926, 2))
#%% md
##### 统计
#%%
# 统计
# np.sum(x) # 求和
print(np.sum([1, 2, 3])) # 输出: 6
# np.mean(x) # 平均值
print(np.mean([1, 2, 3])) # 输出: 2.0
# np.median(x) # 中位数
print(np.median([1, 2, 3])) # 输出: 2.0
# np.std(x) # 标准差
print(np.std([1, 2, 3])) # 输出: 0.816496580927726
# np.var(x) # 方差
print(np.var([1, 2, 3])) # 输出: 0.6666666666666666
# np.min(x) # 最小值
print(np.min([1, 2, 3])) # 输出: 1
# np.max(x) # 最大值
print(np.max([1, 2, 3])) # 输出: 3
# np.percentile(x, q) # 计算第q百分位数
print(np.percentile([1, 2, 3], 50)) # 输出: 2.0
# 比较
# np.greater(a, b) # 返回一个布尔数组,表示a中的元素是否大于b中对应的元素
print(np.greater([1, 2, 3], [2, 2, 2])) # 输出: [False False True]
# np.less(a, b) # 返回一个布尔数组,表示a中的元素是否小于b中对应的元素
print(np.less([1, 2, 3], [2, 2, 2])) # 输出: [ True False False]
# np.equal(a, b) # 返回一个布尔数组,表示a中的元素是否等于b中对应的元素
print(np.equal([1, 2, 3], [2, 2, 2])) # 输出: [False True False]
# np.logical_and(a, b) # 对两个布尔数组执行逻辑与操作
print(np.logical_and([True, False, True], [False, True, True])) # 输出: [False False True]
# np.where(condition, x, y) # 根据条件选择x或y中的元素
print(np.where([True, False, True], [1, 2, 3], [4, 5, 6])) # 输出: [1 5 3]
# 去重
# np.unique(x) # 返回数组x中的唯一值
print(np.unique([1, 2, 2, 3, 3, 3])) # 输出: [1 2 3]
# np.isin(a, b) # 判断a中的元素是否在b中出现过,返回布尔数组
print(np.isin([1, 2, 3], [2, 3, 4]))
#%%
# 其他
# np.concatenate((a, b)) # 沿现有轴连接数组
print(np.concatenate(([1, 2], [3, 4]))) # 输出: [1 2 3 4]
# np.split(x, indices) # 将数组x分割成多个子数组
print(np.split([1, 2, 3, 4, 5, 6], [3])) # 输出: [array([1, 2, 3]), array([4, 5, 6])]
# np.reshape(x, shape) # 改变数组x的形状
# 有返回值,原数组不做改变,如果改变前后维度和数量一样返回None值
print(np.reshape([1, 2, 3, 4, 5, 6], (2, 3))) # 输出: [[1 2 3]
# [4 5 6]]
# np.copy(x) # 复制数组x
arr = np.array([1, 2, 3])
arr_copy = np.copy(arr)
print(arr_copy) # 输出: [1 2 3]
# np.isnan(x) # 测试数组元素是否为NaN
print(np.isnan([np.nan, 1, 2])) # 输出: [ True False False]
# 排序
# np.sort(x) # 返回排序后的数组副本
print(np.sort([3, 1, 2])) # 输出: [1 2 3]
# x.sort() # 就地排序数组x
arr = np.array([3, 1, 2])
arr.sort()
print(arr) # 输出: [1 2 3]
# np.argsort(x) # 返回数组元素从小到大的索引值
print(np.argsort([3, 1, 2])) # 输出: [1 2 0]
# np.lexsort(keys) # 根据键列表执行间接排序
keys = (['c', 'a', 'b'], [1, 2, 3])
print(np.lexsort(keys)) # 输出: [1 2 0]
#%% md
#### 数组间操作
#%% md
##### 数组的拼接
#%%
t1 = np.arange(10).reshape((2, 5))
t2 = np.arange(10,20).reshape((2, 5))
print(t1)
print(t2)
t3 = np.vstack((t1, t2))
t4 = np.hstack((t1, t2))
print(t3)
print(t4)
#%% md
##### 数组的切割
#%%
arr = np.arange(12).reshape(3, 4)
print("原始数组:")
print(arr)
"""
原始数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
"""
# 1. 按列拆分(axis=1),拆成2份
arr1, arr2 = np.split(arr, 2, axis= 1)
print("\n按列拆成2份:")
print("arr1:\n", arr1)
print("arr2:\n", arr2)
# 2. 按行拆分(axis=0),按指定位置拆分(如在索引1和2处拆分)
arr3, arr4, arr5 = np.split(arr, [1, 2], axis=0)
print("\n按行在索引1、2处拆分:")
print("arr3:\n", arr3)
print("arr4:\n", arr4)
print("arr5:\n", arr5)
#%%
h1, h2 = np.hsplit(arr, 2)
print("\n水平拆分结果:")
print(h1)
# 垂直拆分(按行)
v1, v2, v3 = np.vsplit(arr, 3)
print("\n垂直拆分结果:")
print(v1)
print(v2)
print(v3)
#%%
t =np.arange(12,24).reshape(3,4)
print(t)
t[[1,2],:]=t[[2,1],:] #行交换
print(t)
t[:, [0,2]] = t[:, [2,0]] #列交换
print(t)
#%% md
##### 复制与视图`
#%%
a = np.array([[1, 2, 3],[4, 5, 6]])
b = a
print(b)
# a=b 只是给a添加了一个引索
b[1][0] = 6
print(a)
#%%
a = np.array([[1, 2, 3],[4, 5, 6]])
a=b.copy() #复制,a和b互不影响
print(b)
a=b[:]
print("结束")
# 视图的操作,一种切片,会创建新的对象a,但是a
# 的数据完全由b保管,他们两个的数据变化是一致的