### Numpy (Numberical python) 数值统计模块 #### 矩阵 ##### 矩阵的性质 + 任何矩阵和单位矩阵相乘结果都为他自身 ##### 矩阵类型 + **同型矩阵** : 两个矩阵形状相同 + **对角矩阵** : 只有对角线上的元素有非 0 值 + **单位矩阵 E ** : 对角线的元素为 1, 其他元素为 0 + **对称矩阵** : 矩阵沿对角线值对称相等 + **方矩阵** + **全 0 矩阵** : 矩阵内值全为 0 + **行矩阵 (行向量)** : 矩阵只有一行 ##### 矩阵的运算 1. **矩阵的加/减法** + 两个矩阵同为**同型矩阵** + 操作 : 对应位上的元素进行运算 2. **矩阵的乘法** 1. **数与矩阵相乘** + 数与矩阵中每个值相乘 2. **矩阵间乘法** + `m*s 矩阵A 与 s*n 矩阵B 相乘`---> `m*n 矩阵` + `矩阵A * 矩阵B` : 矩阵 A 的行的元素 乘以 矩阵 B 的对应列的元素 得到的值再相加 + 要求 : 矩阵 A 的列 == 矩阵 B 的行 3. **矩阵的转置** + **转置** : 将A的所有元素绕着一条从第1行第1列元素出发的右下方45度的射线 (主对角线) 作**镜面反转**,即得到A的转置 4. **矩阵的逆矩阵** + 如果矩阵 A 和 矩阵 B 相乘等于 E (单位矩阵), 则称矩阵 A 是可逆的 + A 的 逆矩阵是 矩阵 B : `A-¹ = B` #### numpy 介绍 + numpy 可以存储和处理 **大型数组/矩阵** + numpy 提供了多维数组对象 **ndarray (n dim维度 array 数组) ** : 是一种**内存连续**的、存储**单一数据类型**、**可以存储多维数组**的对象 + 两种存储风格 1. C 语言存储风格 : 行优先存储 (默认) 2. F (Fortran) 语言风格存储 : 列优先存储 #### numpy 数组 ##### Numpy数组 常用属性 + `arr_name.ndim` : 维度信息 + `arr_name.shape` : 形状信息 + `arr_name.dtype` : 数据元素类型 + `arr_name.size` : 总元素数 + `np.pi` : 圆周率**pi = 3.141592653589793** + `arr_name.itemsize` : 数组中数据元素的字节数 + `arr_name.nbytes` : 数组中的所有数据消耗掉的字节数。不计算数组的开销,因此数组占用的实际空间将稍微大一点。 + 实例 ```python import numpy as np arr1 = np.array([1, 2, 3], dtype=int) print(arr1) # [1. 2. 3.] print(f"数组维度{arr1.ndim}") # 数组维度1 print(arr1.shape) # (3,) print(arr1.dtype) # int32 print(arr1.size) # 3 print(arr1.itemsize) # 4 print(arr1.nbytes) # 12 ``` ##### 数组的元素数据类型操作 1. 创建时通过 **dtype** 指定类型 2. 强制转换 : `np.bool(arr)`、`np.float(arr)`、`np.str(arr)`、`np.int(arr)` 3. 利用 **arr_name.astype(np.int)** 转换,可以转换为多种类型 ##### 常用数组函数 + 数组的创建 : `.array(p_object, dtype=None, copy=True, order='K', subok=False, ndmin=0)` + 参数 | 参数 | 描述 | | ------------ | ------------------------------------------------------------ | | **p_object** | 数组,任何显示数组接口的对象,*返回数组的方法*或*任何(嵌套)序列*。 | | **dtype** | 数据类型,可选参数.数据所需的数据类型,如果未给定则为在序列中保存对象所需的最小类型 | | **copy** | 布尔参数,可选参数.如果为true(默认),则复制对象 | | **order** | 可选参数,值为 **{'K', 'A', 'C', 'F'}**。指定阵列的内存布局,
 **K** : 默认,保存原 F 和 C 风格不变,否则自动选择 F 或 C 风格
 **A** : 如果输入是F而不是C,则F风格不变,否则为C风格
 **C** : C 语言存储风格
 **F** : Fortran 语言风格存储 | + 将多维数组展平为一维数组 : `arr_name.flatten(order='C')`, `a.ravel([order])` + 区别 + 按行展开数组的值时,修改 **flatten()** 不会影响原数组的值, 修改 **ravel()** 会修改原数组的值 ```python import numpy as np arr = np.arange(1, 17).reshape((4, 4)) """ [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16]] """ arr_flatten = arr.flatten() # [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] arr_ravel = arr.ravel() # [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] arr_flatten[0] = 1000 print(arr) """ [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16]] """ arr_ravel[0] = 1000 print(arr) """ [[1000 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [ 13 14 15 16]] """ ``` + 按列展开数组的值时,修改 **flatten()** 与 **ravel()** 都不会影响原数组的值 ```python import numpy as np arr = np.arange(1, 17).reshape((4, 4)) """ [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16]] """ arr_flatten = arr.flatten(order='F') # [ 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16] arr_ravel = arr.ravel(order='F') # [ 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16] arr_flatten[0] = 1000 print(arr) """ [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16]] """ arr_ravel[0] = 1000 print(arr) """ [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16]] """ ``` + 生成一维数组,返回给定间隔内的等间距值 : `.arange([start,] stop[, step,], dtype=None)` + 值是在半开区间`[start,stop)`内生成的 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **start** | 可选参数,默认为0,数值类型.间隔的开始。间隔包括此值。 | | **stop** | 数值类型,**必选参数**.间隔的结束,间隔不包括此值 | | **step** | 可选参数,数值类型.值之间的间距 | | **dtype** | 可选参数.输出数组的类型,如果不赋值,从其他输入参数推断数据类型。 | + `a.reshape(shape, order='C')` : 。将一维数组变成多维数组.返回包含具有新形状的相同数据的数组 + 常与 `arange()` 结合使用 + 生成一个固定类型的多维数组,使用前方给出参数填充数组 ```python import numpy as np print(np.arange(10).reshape(2, 5)) """ [[0 1 2 3 4] [5 6 7 8 9]] """ ``` + `np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)` : 在指定的间隔范围内返回均匀间隔的数字 (**等差数组**)。在**[start, stop)**范围内计算,返回**num**个(默认为50)均匀间隔的样本。一维数组 + 参数 | 参数 | 描述 | | ------------ | ------------------------------------------------------------ | | **start** | 返回序列的初始值 | | **stop** | 除非**endpoint**被设置为False,否则**stop**为序列的终点值。当**endpoint=False**,返回序列包含**num+1**个均匀间隔样本的最后一个样本以外的所有样本 | | **num** | 整型,可选参数.产生的样本总数。默认值为50。必须为非负值。 | | **endpoint** | bool 类型,可选参数.若为True,则**stop**为最后一个样本。否则,返回序列不包含**stop**。默认值为True。 | | **retstep** | bool 类型,可选参数.若为True,返回(samples, step),step为样本间的步长。 | | **dtype** | 返回序列的数据类型。如果dtype未给定,那么从其他输入参数推断其类型。 | | **axis** | 整型,可选参数。结果中存储样本的轴 | + 实例 ```python import numpy as np lin_num = np.linspace(10, 100, num=10) # 10 ~ 100 (包括 100) 生成 10 个数 print(lin_num) # [ 10. 20. 30. 40. 50. 60. 70. 80. 90. 100.] ``` + `logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)` : 创建对数等差数列数组,底数为base (**等比数组**)。一维数组 + 参数 | 参数 | 描述 | | ------------ | ------------------------------------------------------------ | | **start** | 必选参数,区间起始值为base的start次方。 | | **stop** | 必选参数,区间终止值为base的stop次方(是否取得到,需要设定参数endpoint)。 | | **num** | 可选参数,等分的个数 (生成的数组内数据的个数)。按照对数,即start和stop值进行等分。默认值为50. | | **endpoint** | 可选参数,若为True(默认),则可以取到区间终止值;否则取不到。 | | **base** | 公比 | | **dtype** | 可选参数,数据类型。若不指定数据类型,则通过其他参数判断 | | **axis** | 整型,可选参数。结果中存储样本的轴 | + 实例 ```python import numpy as np log_num = np.logspace(2, 3, 10, base=2) # 2^2 ~ 3^2 (不包括3^2) 之间 等比生成10个数 print(log_num) # [4. 4.32023896 4.66611616 5.0396842 5.44316 5.87893797 6.34960421 6.85795186 7.4069977 8. ] ``` + `np.zeros(shape, dtype=None, order='C')` : 全 0 数组,可以创建任意维度的数组,创建给定形状的ndarray,并将数组中所有元素填充为0 + 参数 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **shape** | 必选参数,维度,可以是任意纬度 | | **dtype** | 可选参数,数据类型。默认为np.float64 | | **order** | 可选参数, 数组按一定的顺序排列,默认为 **C**,{'C', 'F'}
 **C** : 按行排列
 **F** : 按列排列 | + 实例 ```python import numpy as np zero_arr = np.zeros((3, 4), dtype=float) print(zero_arr) """ [[0. 0. 0. 0.] [0. 0. 0. 0.] [0. 0. 0. 0.]] """ ``` + `np.ones(shape, dtype=None, order='C')` : 返回给定形状和类型的新数组,一个全1的n维数组. + 参数 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **shape** | 必选参数,维度,可以是任意纬度 | | **dtype** | 可选参数,数据类型。默认为np.float64 | | **order** | 可选参数, 数组按一定的顺序排列,默认为 **C**,{'C', 'F'}
 **C** : 按行排列
 **F** : 按列排列 | + 实例 ```python import numpy as np print(np.ones((2, 4))) """ [[1. 1. 1. 1.] [1. 1. 1. 1.]] """ ``` + `np.diag(v, k=0)` : 类似于对角矩阵,既可以以一维数组的形式**返回对角线元素**,也可以将一维数组**转换成方阵** + 参数 | 参数 | 描述 | | ----- | ------------------------------------------------------------ | | **v** | array_like.
 如果`v`是二维数组,则返回其第`k`个对角线的副本。
 如果`v`是一维数组,则返回一个二维数组,其中`v`在第`k`个对角线上 | | **k** | 整数,可选参数.**对角线的位置**,大于零位于对角线上面,小于零则在下面。 | + 实例 ```python import numpy as np print(np.diag((1, 2, 3))) # 返回一个 3x3 数组,对角线元素为 1, 2, 3 """ [[1 0 0] [0 2 0] [0 0 3]] """ diag_arr = np.arange(9).reshape(3, 3) print(diag_arr) """ [[0 1 2] [3 4 5] [6 7 8]] """ print(np.diag(diag_arr)) # 返回 数组的对角线 [0 4 8] print(np.diag(diag_arr, k=1)) # [1 5] print(np.diag(diag_arr, k=-1)) # [3 7] ``` + `np.eye(N, M=None, k=0, dtype=float, order='C')` : 返回一个二维数组,对角线上为 1,其他位置为零。 + 参数 | 参数 | 描述 | | :-------: | :----------------------------------------------------------: | | **N** | 整数,行数,输出中的行数 | | **M** | 整数,可选参数,输出中的列数。默认为 None。 | | **k** | 整数,可选参数,对角线索引:0(默认值)是指主要对角线,正值表示对角线的上边,负值表示到较低的对角线。
 k为正整数,指从第k个值开始的右上对角线
 k为负整数,指从第-k个值开始的左下对角线 | | **dtype** | 可选参数,数据类型。默认为浮点数 | | **order** | 可选参数, 数组按一定的顺序排列,默认为 **C**,{'C', 'F'}
 **C** : 按行排列
 **F** : 按列排列 | + 实例 ```python import numpy as np print(np.eye(4)) """ [[1. 0. 0. 0.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] """ ``` #### numpy random 方法 + `np.random.random(size)` : 生成0-1之间的随机浮点数,size可以为数组类型(2, 2) + 固定随机数 (保证多次运行产生随机数不变) : `np.random.seed(1)` 生成的随机数叫做伪随机数 + 实例 ```python import numpy as np # np.random.seed(1) print(np.random.random(5)) # [0.19812881 0.22344332 0.00308559 0.5842389 0.67662501] print(np.random.random((2, 3))) """ [[0.7775702 0.45005126 0.1029259 ] [0.77165046 0.28769795 0.72999339]] """ ``` + `np.random.randn(d0, d1, ..., dn)` : 从 **标准正态分布** 中返回一个或多个样本。 + 案例 ```python import numpy as np print(np.random.randn(2)) # [-0.61441249 0.44007701] ``` + `np.random.rand(d0, d1, ..., dn)` : 产生 0-1 之间**均匀分布 (在一定范围内,一个新数据落在任何子区域的概率是一致的) **的随机数,可传入可变长数字 + 实例 ```python import numpy as np print(np.random.rand(5)) # [0.55158559 0.58835226 0.57084476 0.16372193 0.22398622] print(np.random.rand(2, 3)) """ [[0.9423069 0.03469337 0.48966077] [0.80035928 0.64656614 0.23262355]] """ ``` + `np.random.stardard_normal(size=None)` : 从**标准正态分布**(均值= 0,stdev = 1)中抽取样本。 + 参数 : + **size** : 整数或整数元组,可选输出形状。如果给定的形状是例如 **(m,n,k)**,则绘制 **m * n * k** 个样本。默认为无,返回单个值。 + 与 **np.random.randn** 区别: + **randn** 返回shape为(*d0*, *d1*, *...*, *dn*)的标准正态分布(均值为0,标准差为1)的数组 + **stardard_normal** 它的shape由size参数指定,对于多维数组,size必须是元组形式 + 实例 ```python np.random.standard_normal((2, 3, 4)) """ array( [[[ 0.4114533 , 0.11426395, 1.43661828, -0.27262121], [ 1.90990117, 0.15856119, 0.08476711, 2.59285364], [-0.86035996, -0.89235802, -1.13702572, 0.50942391]], [[-0.21854179, -0.25182636, -0.1003288 , -0.37723832], [-0.29564125, 0.31380058, -0.38441272, -0.51012865], [ 0.06783913, -0.16966757, 1.07430531, -1.21000938]]] ) """ ``` + `np.random.randint(low, high=None, size=None, dtype='l')` : 从“低”(包含)到“高”(不含)返回随机整数。生成一个**整数**或**N维整数数组**, + 取数范围:若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数。 + 参数 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **low** | int 或 类似int的数组 从分布中得出的最低(带符号)整数(除非high = None,在这种情况下此参数比*最高*这样的整数) | | **high** | int 或 类似int的数组,可选如果提供,则在最大(有符号)整数上方绘制一个从分布中获取(如果`high = None`,请参见上面的行为)。如果为**数组**,则必须**包含整数值** | | **size** | **整数**或**整数元组**,可选**输出形状**。如果给定的形状是例如**(m,n,k)**,则绘制**m * n * k**个样本。默认为无,返回单个值。 | | **dtype** | 可选参数,数据类型,默认值为 **np.int** | + `np.random.uniform(low=0.0, high=1.0, size=None)` : 指定范围 **[low, high)** 随机小数数组,**均匀分布** + 参数 | 参数 | 描述 | | -------- | ------------------------------------------------------------ | | **low** | **可选参数**,float或者一组float的数组,默认是0 | | **high** | **必选参数**,float或者一组float的数组,默认是1 | | **size** | **整数**或**整数元组**,可选**输出形状**。如果给定的形状是例如**(m,n,k)**,则绘制**m * n * k**个样本。默认为无,返回单个值。 | ##### 常用 random 模 ##### 块说明 + 常用模块 | 函数 | 描述 | | ------------------------------------------------- | ------------------------------------------------------ | | `np.random.seed(x)` | 确定随机数生成的种子,(保证多次运行产生随机数不变) | | `np.random.permutation(x)` | 返回一个序列的**随机排列**或返回一个**随机排列的范围** | | `np.random.shuffle(x)` | 对一个序列进行随机排序 | | `np.random.binomial(n, p, size=None)` | 产生**二项分布**的随机数 | | `np.random.normal(loc=0.0, scale=1.0, size=None)` | 产生**正态 (高斯) 分布**的随机数 | | `np.random.beta(a, b, size=None)` | 产生 **beta 分布**的随机数 | | `np.random.chisquare(df, size=None)` | 产生 **卡方分布** 的随机数 | | `np.random.gamma(shape, scale=1.0, size=None)` | 产生 **gamma 分布** 的随机数 | + 模块参数 + `np.random.binomial(n, p, size=None)` : 产生**二项分布**的随机数 | 参数 | 描述 | | -------------- | ------------------------------------------------------------ | |  **n** | int型或者一个int型的数组,大于等于0,接受浮点数但是会被变成整数来使用。(**表示n次的试验**) | |  **p** | float或者一组float的数组,大于等于0且小于等于1.(**表示的试验成功的概率**) | |  **size** | 可选项,int或者int的元祖,表示的输出的大小,如果提供了size,例如(m,n,k),那么会返回m*n*k个样本。如果size=None,也就是默认没有的情况,当n和p都是一个数字的时候只会返回一个值,否则返回的是np.broadcast(n,p).size个样本 | + `np.random.normal(loc=0.0, scale=1.0, size=None)` : 产生**正态 (高斯) 分布**的随机数 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **loc** | float,概率分布的**均值**,对应着整个**分布的中心center** | | **scale** | float,概率分布的**标准差**,对应于**分布的宽度**,scale越大越矮胖,scale越小,越瘦高 | | **size** | **int型**或者一个**int型的数组**,输出的shape,默认为None,只输出一个值 | + `np.random.beta(a, b, size=None)` : 产生 **beta 分布**的随机数 | 参数 | 描述 | | -------- | ------------------------------------------------------------ | | **a** | **float型**或者一个**float型的数组**
α(阿尔法)形态分布,必须是非负的 | | **b** | **float型**或者一个**float型的数组** | | **size** | **int型**或者一个**int型的数组**,输出的shape,默认为None,只输出一个值 | + `np.random.chisquare(df, size=None)` : 产生 **卡方分布** 的随机数 | 参数 | 描述 | | -------- | ------------------------------------------------------------ | | **df** | **float型**或者一个**float型的数组**
自由度数,必需大于0 | | **size** | **int型**或者一个**int型的数组**,输出的shape,默认为None,只输出一个值 | + `np.random.gamma(shape, scale=1.0, size=None)` : 产生 **gamma 分布** 的随机数 | 参数 | 描述 | | --------- | ------------------------------------------------------------ | | **shape** | **float型**或者一个**float型的数组**
γ (伽马)分布的形状。必须是非负的。 | | **scale** | **float型**或者一个**float型的数组**
γ (伽马)分布的尺度。必须是非负的。 | | **size** | **int型**或者一个**int型的数组**,输出的shape,默认为None,只输出一个值 | #### numpy 数组的操作\访问 + **数组名[行信息, 列信息]**(多种方法可以交叉使用) + 行信息: 下标、下标列表、布尔索引、切片 + 列信息: 下标、下标列表、布尔索引、切片 + **下标访问** : 返回的是降低一次维度之后的数 ```python import numpy as np np.random.seed(1) arr = np.random.randint(1, 100, 8) print(arr) # [38 13 73 10 76 6 80 65] print(arr[0]) # 38 print(arr[0:1]) # [38] arr1 = np.random.randint(1, 100, (2, 3)) print(arr1) """ [[17 2 77] [72 7 26]] """ print(arr1[0]) # [17 2 77] print(arr1[0:1]) # [[17 2 77]] ``` + **数组的切片** : `数组名[横轴起始: 横轴结束, 竖轴起始: 竖轴结束]` 返回的是数组,不会降低维度 ```python import numpy as np arr = np.arange(20).reshape(4, 5) print(arr) """ [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14] [15 16 17 18 19]] """ print(arr[0, 1:5]) # 第 0 行 第 1-4 列的值 [1 2 3 4] print(arr[1, 1:5]) # 第 1 行 第 1-4 列的值 [6 7 8 9] print(arr[1:3, 0]) # 第 0 列 第 1-2 行的值 [ 5 10] ``` + 使用**布尔数组**的索引访问 + 一维数组 ```python np.random.seed(1) arr = np.random.randint(1, 100, 8) # print(arr) # [38 13 73 10 76 6 80 65] arr_bool = arr % 2 != 0 print(arr[arr_bool]) # [13 73 65] ``` + 多维数组 ```python arr1 = np.random.randint(1, 100, (2, 3)) print(arr1[arr1 % 2 != 0]) # [ 7 99 37] arr2 = np.arange(16).reshape(4, 4) # 布尔索引 arr2_bool = [True, False, False, True] print(arr2[:, arr2_bool]) """ [[ 0 3] [ 4 7] [ 8 11] [12 15]] """ ``` + **数组运算符** + 方法 | 运算符 | 描述 | | --------------------------- | ----------------------------------------------------------- | | `+` ==> `np.add(x, y)` | 数组中数据逐位相加 | | `-` ==> `np.subtract(x, y)` | 数组中数据逐位相减 | | `*` ==> `np.multiply(x, y)` | 矩阵 A 的行的元素 乘以 矩阵 B 的对应列的元素 得到的值再相加 | | `/` ==> `np.divide(x, y)` | | | `**` ==> `np.sqrt(x)` | 平方根 | | `>` | 数组比较,返回布尔值 | | `<` | 数组比较,返回布尔值 | | `%` | 取余判断,返回布尔数组 | + 数组特殊运算方法 + 方法 | 方法 | 描述 | | ---------------------------------------- | ------------------------------------------------------------ | | `sum()` | 将所有元素相加 | | `min()` | 找出最小元素 | | `max()` | 找出最大元素 | | `cumsum()` | 逐位相加求和并放入新数组 | | `np.abs(x)`、`np.fabs(x)` | 计算数组各元素的绝对值 | | `np.square(x)` | 计算数组各元素的平方 | | `np.sqrt(x)` | 平方根 | | `np.log(x)`、`np.log10(x)`、`np.log2(x)` | 计算数组各元素的**自然对数**、10底对数和2底对数 | | `arr_name.T` | **转置** `.T ` 将A的所有元素绕着一条从第1行第1列元素出发的右下方45度的射线作镜面反 | | `np.transpose()` | 颠倒 (调换数组的行列值的索引值,类似于求矩阵的转置) | + 实例 ```python import numpy as np arr = np.arange(20).reshape(4, 5) arr1 = np.arange(20, 40).reshape(4, 5) """ arr : [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14] [15 16 17 18 19]] arr1 : [[20 21 22 23 24] [25 26 27 28 29] [30 31 32 33 34] [35 36 37 38 39]] """ print(sum(arr, arr1)) """ [[50 55 60 65 70] [55 60 65 70 75] [60 65 70 75 80] [65 70 75 80 85]] """ print(f"arr最大值: {np.max(arr)}, arr1 最大值: {np.max(arr1)}") # arr最大值: 19, arr1 最大值: 39 print(f"arr最小值: {np.min(arr)}, arr1 最小值: {np.min(arr1)}") # arr最小值: 0, arr1 最小值: 20 print(f"arr逐位相加: {np.cumsum(arr)}") """ arr逐位相加: [ 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190] """ print(f"arr1逐位相加: {np.cumsum(arr1)}") """ arr1逐位相加: [ 20 41 63 86 110 135 161 188 216 245 275 306 338 371 405 440 476 513 551 590] """ ```