numpy用法小结
前言
个人感觉网上对numpy的总结感觉不够详尽细致,在这里我对numpy做个相对细致的小结吧,在数据分析与人工智能方面会有所涉及到的东西在这里都说说吧,也是对自己学习的一种小结!
numpy用法的介绍
安装部分我就不说了,装个pip,使用命令pip install numpy就可以安装了,在Ubuntu中可能会出现没有权限的提示,直接加上sudo即可,以下讲解都是建立在python3平台的讲解,python2类似,python3中安装的时候使用sudo pip3 install numpy即可。
首先,numpy是个求解数学矩阵,做矩阵计算
1.genfromtxt
numpy numpy.genfromtxt(""),这里我们讲解下,genfromtxt函数的意思是读取文件信息,用来处理数据信息,可以处理数据文件
举个例子:
import numpy world_alcohol = numpy.genfromtxt("world_alcohol.txt",delimiter = ",",dtype = str) print(type(world_alcohol)) print(world_alcohol) print(help(numpy.genfromtxt))
打印结果如下:
<class 'numpy.ndarray'> [['Year' 'WHO region' 'Country' 'Beverage Types' 'Display Value'] ['1986' 'Western Pacific' 'Viet Nam' 'Wine' '0'] ['1986' 'Americas' 'Uruguay' 'Other' '0.5'] ..., ['1987' 'Africa' 'Malawi' 'Other' '0.75'] ['1989' 'Americas' 'Bahamas' 'Wine' '1.5'] ['1985' 'Africa' 'Malawi' 'Spirits' '0.31']] Help on function genfromtxt in module numpy.lib.npyio: genfromtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, names=None, excludelist=None, deletechars=None, replace_space='_', autostrip=False, case_sensitive=True, defaultfmt='f%i', unpack=None, usemask=False, loose=True, invalid_raise=True, max_rows=None) Load data from a text file, with missing values handled as specified. Each line past the first `skip_header` lines is split at the `delimiter` character, and characters following the `comments` character are discarded. Parameters ---------- fname : file, str, pathlib.Path, list of str, generator File, filename, list, or generator to read. If the filename extension is `.gz` or `.bz2`, the file is first decompressed. Note that generators must return byte strings in Python 3k. The strings in a list or produced by a generator are treated as lines. dtype : dtype, optional Data type of the resulting array. If None, the dtypes will be determined by the contents of each column, individually. comments : str, optional The character used to indicate the start of a comment. All the characters occurring on a line after a comment are discarded delimiter : str, int, or sequence, optional The string used to separate values. By default, any consecutive whitespaces act as delimiter. An integer or sequence of integers can also be provided as width(s) of each field. -- More --
我解释一下上面的用法,genfromtxt传入了三个参数,第一个参数是数据文件,名为world_alcohol.txt,该数据文件有需要的同学可以加我好友私聊我,或者把你的请求发邮箱至i_love_sjtu@qq.com
然后delimiter是分隔符,由于数据集中的数据是用逗号分隔的,所以设定参数delimiter=',',dtype是获取数据类型,数据集中的类型为str
print(type(world_alcohol))打印数据文件的数据类型
print(world_alcohol)打印数据集
print(help(numpy.genfromtxt))打印genfromtxt用法
加入skip_header,跳转至以1开头的数据
import numpy world_alcohol = numpy.genfromtxt("world_alcohol.txt",delimiter=",",dtype=str,skip_header=1) print(world_alcohol)
打印结果如下:
[['1986' 'Western Pacific' 'Viet Nam' 'Wine' '0'] ['1986' 'Americas' 'Uruguay' 'Other' '0.5'] ['1985' 'Africa' "Cte d'Ivoire" 'Wine' '1.62'] ..., ['1987' 'Africa' 'Malawi' 'Other' '0.75'] ['1989' 'Americas' 'Bahamas' 'Wine' '1.5'] ['1985' 'Africa' 'Malawi' 'Spirits' '0.31']]
2.shape
xxx.shape 显示的功能是查看矩阵或者数组的维数
举个例子:
import numpy vector = numpy.array([5,10,15,20]) matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) print(vector) print(matrix) print(vector.shape) print(matrix.shape)
打印结果如下:
[ 5 10 15 20] [[ 5 10 15] [20 25 30]] (4,) (2, 3) [Finished in 0.6s]
显示出当前vector的维度是一维矩阵
matrix的维度是2行3列
3.索引
一维数组的索引:与Python的列表索引功能相似
先举个例子:
import numpy world_alcohol = numpy.genfromtxt("world_alcohol.txt",delimiter=",",dtype=str,skip_header=1) uruguay_other_1986 = world_alcohol[1,4] third_country = world_alcohol[2,2] print(uruguay_other_1986) print(third_country)
打印结果如下:
0.5 Cte d'Ivoire
uruguay_other_1986取值的时候取的是第一个列表中的第四个值(从0开始算)
third_country取值的时候取的是第二个列表中的第二个值(从0开始算)
4.切片
举例子:
import numpy vector = numpy.array([5,10,15,20]) print(vector[0:3])
打印结果如下:
[ 5 10 15]
这个和python中切片效果一样,取的是左闭右开的界线
下一个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) print(matrix[:,1])
打印结果如下:
[10 25 40]
:表示选取所有的行 逗号隔开 然后取列 取第一列(从0开始计算)
下一个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) print(matrix[:,0:2])
打印结果如下:
[[ 5 10] [20 25] [35 40]]
这个意思是:表示选取所有的行 逗号隔开 然后取列 这里用到了切片 取的是从第零列开始到第二列(小于2) 实际上取的就是前两列
下一个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) print(matrix[1:3,0:2])
打印结果如下:
[[20 25]
[35 40]]
这个意思是我们选取的行是第一行到第三行(小于3) 这里用到了切片 然后取列 这也用到了切片 取的是从第零列开始到第二列(小于2) 实际上取的就是前两列
5.布尔类型的相关判断
举个例子:
import numpy vector = numpy.array([5,10,15,20]) vector == 10
打印结果如下:
>>array([False, True, False, False], dtype=bool)
返回一个布尔型结果 判断了该矩阵中是否有值等于10
== 相当于对矩阵中的每一个元素都进行了一个判断
下一个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) matrix == 25
打印结果如下:
array([[False, False, False],
[False, True, False],
[False, False, False]], dtype=bool)
解释的原理和上述一样
下一个例子:
import numpy vector = numpy.array([5,10,15,20]) equal_to_ten = (vector == 10) print(equal_to_ten) print(vector[equal_to_ten])
打印结果如下:
[False True False False]
[10]
意思是 vector == 10 直接对矩阵的值做了个判断 把布尔类型的矩阵传递给equal_to_ten
然后的话打印结果为布尔类型的矩阵 这个布尔类型是一个索引 我们打印这个vector[布尔类型的索引]即可找回原值 返回真实值
下一个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) second_conlumn_25 = (matrix[:,1] == 25) print(second_conlumn_25) print(matrix[second_conlumn_25, :])
打印结果如下:
[False True False]
[[20 25 30]]
意思是 :表示选取所有的行 逗号隔开 然后取列 取的是第一列(从0开始) 然后直接对这一列的值进行判断 判断这一列
中的元素是否等于25 并将其布尔类型的值传递给second_conlumn_25
然后打印出的second_conlumn_25的结果为一个布尔类型的列表
而把second_conlumn_25当作索引值 我们去寻找有25的这一行 逗号隔开 :表示直接选取这一行的数据 然后打印出来
下一个例子:
import numpy vector = numpy.array([5,10,15,20]) equal_to_ten_and_five = (vector == 10) & (vector == 5) print(equal_to_ten_and_five)
打印结果如下:
[False False False False]
意思是查找当前的这个矩阵中的数既等于10又等于5的数 显然不存在 所以全部输出False
下一个例子:
import numpy vector = numpy.array([5,10,15,20]) equal_to_ten_or_five = (vector == 10) | (vector == 5) print(equal_to_ten_or_five)
打印结果如下:
[ True True False False]
意思是查找当前的这个矩阵中的数等于10或者等于5的数 显然不存在 所以输出True True False False
6.dtype与astype
dtype 输出的是矩阵中的数据类型
举个例子:
import numpy vector = numpy.array([5,10,15,20]) print(vector.dtype)
打印结果如下:
int32
如果我们想转换矩阵中的数据类型 我们应该使用astype进行转换
举个例子:
import numpy vector = vector.astype(float) print(vector.dtype)
打印结果如下:
float64
这样就OK了!!!
7.min与max
min求解该矩阵中的最小值
举个例子:
import numpy vector = numpy.array([5,10,15,20]) vector.min()
打印结果如下:
>>5
max求解该矩阵中的最大值
举个例子:
import numpy vector = numpy.array([5,10,15,20]) vector.max()
打印结果如下:
>>20
8.sum
sum 可以指定了一个维度 对行或者列求和
举个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) matrix.sum(axis=1)
打印结果如下:
>>array([ 30, 75, 120])
指定了一个维度 对行求和
下个例子:
import numpy matrix = numpy.array([[5,10,15],[20,25,30],[35,40,45]]) matrix.sum(axis=0)
打印结果如下:
>>array([60, 75, 90])
指定了一个维度 axis = 0 行号为0 相当于对列求和
9.reshape
reshape给数组一个新的形状而不改变其数据
举个例子:
import numpy as np print(np.arange(15)) a = np.arange(15).reshape(3,5) print(a)
打印结果如下:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]]
np是指定了numpy的别名,np.arange依次造出十五个元素 变成了一个向量的形式,reshape函数表明,我们要生成一个3行5列这样的矩阵
此时我们输入如下语句:
print(a.shape)
将会打印出如下结果:
(3, 5)
10.ndim
ndim中的dim是英文dimension维度的缩写,表示打印出矩阵的维度
举个例子:
import numpy as np a = np.arange(15).reshape(3,5) print(a.ndim)
打印结果如下:
>>2
打印出当前矩阵的维度为2
11.size
size打印出矩阵的元素个数
举个例子:
import numpy a = np.arange(15).reshape(3,5) print(a.size)
打印结果如下:
>>15
12.zeros
初始化一个矩阵,可以传入参数行和列,生成一个零矩阵
举个例子:
import numpy as np np.zeros((3,4))
打印结果如下:
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
初始化一个矩阵,生成一个三行四列的零矩阵
13.ones
初始化一个矩阵,可以传入参数行和列,还可以传入数据类型dtype
举个例子:
import numpy as np np.ones((2,3,4),dtype=np.int32)
打印结果如下:
array([[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]])
构造出一个三维矩阵 矩阵中的元素均为1 然后我们用dtype指定元素类型为int32
14.arange
arange通过定义起点 终点 步长 然后我们构造出了一个数组 右边界不可以取等号,取的是左闭右开区间
举个例子:
import numpy as np np.arange(10,30,5)
打印结果如下:
array([10, 15, 20, 25])
15.random
random构造出一个矩阵 产生的值默认在-1-1之间
举个例子:
import numpy as np np.random.random((2,3))
打印结果如下:
array([[ 0.77296788, 0.00748236, 0.59905565],
[ 0.05577331, 0.08520327, 0.58034632]])
16.linspace
举个例子:
from numpy import pi np.linspace(0,2*pi,100)
打印结果如下:
array([ 0. , 0.06346652, 0.12693304, 0.19039955, 0.25386607, 0.31733259, 0.38079911, 0.44426563, 0.50773215, 0.57119866, 0.63466518, 0.6981317 , 0.76159822, 0.82506474, 0.88853126, 0.95199777, 1.01546429, 1.07893081, 1.14239733, 1.20586385, 1.26933037, 1.33279688, 1.3962634 , 1.45972992, 1.52319644, 1.58666296, 1.65012947, 1.71359599, 1.77706251, 1.84052903, 1.90399555, 1.96746207, 2.03092858, 2.0943951 , 2.15786162, 2.22132814, 2.28479466, 2.34826118, 2.41172769, 2.47519421, 2.53866073, 2.60212725, 2.66559377, 2.72906028, 2.7925268 , 2.85599332, 2.91945984, 2.98292636, 3.04639288, 3.10985939, 3.17332591, 3.23679243, 3.30025895, 3.36372547, 3.42719199, 3.4906585 , 3.55412502, 3.61759154, 3.68105806, 3.74452458, 3.8079911 , 3.87145761, 3.93492413, 3.99839065, 4.06185717, 4.12532369, 4.1887902 , 4.25225672, 4.31572324, 4.37918976, 4.44265628, 4.5061228 , 4.56958931, 4.63305583, 4.69652235, 4.75998887, 4.82345539, 4.88692191, 4.95038842, 5.01385494, 5.07732146, 5.14078798, 5.2042545 , 5.26772102, 5.33118753, 5.39465405, 5.45812057, 5.52158709, 5.58505361, 5.64852012, 5.71198664, 5.77545316, 5.83891968, 5.9023862 , 5.96585272, 6.02931923, 6.09278575, 6.15625227, 6.21971879, 6.28318531])
指定一个区间 我们要生成100个数 指定了一个值 起点值为0 终点值为2*pi
linspace意思就是在区间里面造出100个值 这100个值间隔是平均的
再举一个例子:
from numpy import pi np.sin(np.linspace(0,2*pi,100))
打印结果如下:
array([ 0.00000000e+00, 6.34239197e-02, 1.26592454e-01, 1.89251244e-01, 2.51147987e-01, 3.12033446e-01, 3.71662456e-01, 4.29794912e-01, 4.86196736e-01, 5.40640817e-01, 5.92907929e-01, 6.42787610e-01, 6.90079011e-01, 7.34591709e-01, 7.76146464e-01, 8.14575952e-01, 8.49725430e-01, 8.81453363e-01, 9.09631995e-01, 9.34147860e-01, 9.54902241e-01, 9.71811568e-01, 9.84807753e-01, 9.93838464e-01, 9.98867339e-01, 9.99874128e-01, 9.96854776e-01, 9.89821442e-01, 9.78802446e-01, 9.63842159e-01, 9.45000819e-01, 9.22354294e-01, 8.95993774e-01, 8.66025404e-01, 8.32569855e-01, 7.95761841e-01, 7.55749574e-01, 7.12694171e-01, 6.66769001e-01, 6.18158986e-01, 5.67059864e-01, 5.13677392e-01, 4.58226522e-01, 4.00930535e-01, 3.42020143e-01, 2.81732557e-01, 2.20310533e-01, 1.58001396e-01, 9.50560433e-02, 3.17279335e-02, -3.17279335e-02, -9.50560433e-02, -1.58001396e-01, -2.20310533e-01, -2.81732557e-01, -3.42020143e-01, -4.00930535e-01, -4.58226522e-01, -5.13677392e-01, -5.67059864e-01, -6.18158986e-01, -6.66769001e-01, -7.12694171e-01, -7.55749574e-01, -7.95761841e-01, -8.32569855e-01, -8.66025404e-01, -8.95993774e-01, -9.22354294e-01, -9.45000819e-01, -9.63842159e-01, -9.78802446e-01, -9.89821442e-01, -9.96854776e-01, -9.99874128e-01, -9.98867339e-01, -9.93838464e-01, -9.84807753e-01, -9.71811568e-01, -9.54902241e-01, -9.34147860e-01, -9.09631995e-01, -8.81453363e-01, -8.49725430e-01, -8.14575952e-01, -7.76146464e-01, -7.34591709e-01, -6.90079011e-01, -6.42787610e-01, -5.92907929e-01, -5.40640817e-01, -4.86196736e-01, -4.29794912e-01, -3.71662456e-01, -3.12033446e-01, -2.51147987e-01, -1.89251244e-01, -1.26592454e-01, -6.34239197e-02, -2.44929360e-16])
指定一个区间 我们要生成100个数 指定了一个值 起点值为0 终点值为2*pi
linspace意思就是在区间里面造出100个值 这100个值间隔是平均的 然后最后我们对这个值取正弦即可
17.floor与ravel
举个例子:
import numpy as np a = np.floor(10*np.random.random((3,4))) print(a) print('------') print(a.ravel()) print('------') a.shape = (6,2) print(a) print('------') print(a.T)
打印结果如下:
[[ 4. 9. 0. 4.] [ 8. 5. 4. 9.] [ 1. 9. 2. 6.]] ------ [ 4. 9. 0. 4. 8. 5. 4. 9. 1. 9. 2. 6.] ------ [[ 4. 9.] [ 0. 4.] [ 8. 5.] [ 4. 9.] [ 1. 9.] [ 2. 6.]] ------ [[ 4. 0. 8. 4. 1. 2.] [ 9. 4. 5. 9. 9. 6.]]
random.random((3,4))是建立一个3行4列的一个区间范围在-1~1的矩阵
然后我们如果觉得值太小了 就可以在np这里*10 floor操作是向下取整
ravel 是将一个矩阵拉平成一个向量 即用向量的形式表示这个矩阵
而a.shape(6,2)又将一个向量转换为一个6*2的矩阵
a.T表示求矩阵a的一个转置矩阵 行和列进行变换
如果一个向量中的元素个数已知 我们已经确定了其中的行数或者列数 其实此时另外一个数已经默认确定了 我们不想去计算那个列数或者行数
是多少时 我们应该怎么办呢 我们如果已经确定了其中的行数或者列数 我们只需要在另外一个位置写上-1就好了 此时计算机会自动帮你计算好这个值
18.hstack与vstack
np.hstack((a,b)) 将a矩阵和b矩阵进行横向拼接
np.vstack((a,b))将a矩阵和b矩阵进行纵向拼接
举个例子:
import numpy as np a = np.floor(10*np.random.random((2,12))) print(a) print('------') print(np.hsplit(a,3)) print('------') print(np.hsplit(a,(3,4))) a = np.floor(10*np.random.random((12,2))) print('------') print(a) np.vsplit(a,3)
打印结果如下:
[[ 5. 1. 3. 4. 6. 5. 4. 5. 4. 8. 2. 2.] [ 4. 9. 2. 6. 8. 9. 5. 9. 6. 5. 5. 7.]] ------ [array([[ 5., 1., 3., 4.], [ 4., 9., 2., 6.]]), array([[ 6., 5., 4., 5.], [ 8., 9., 5., 9.]]), array([[ 4., 8., 2., 2.], [ 6., 5., 5., 7.]])] ------ [array([[ 5., 1., 3.], [ 4., 9., 2.]]), array([[ 4.], [ 6.]]), array([[ 6., 5., 4., 5., 4., 8., 2., 2.], [ 8., 9., 5., 9., 6., 5., 5., 7.]])] ------ [[ 1. 8.] [ 7. 4.] [ 0. 5.] [ 9. 1.] [ 6. 5.] [ 4. 5.] [ 1. 2.] [ 0. 1.] [ 3. 6.] [ 2. 7.] [ 7. 8.] [ 7. 6.]] [array([[ 1., 8.], [ 7., 4.], [ 0., 5.], [ 9., 1.]]), array([[ 6., 5.], [ 4., 5.], [ 1., 2.], [ 0., 1.]]), array([[ 3., 6.], [ 2., 7.], [ 7., 8.], [ 7., 6.]])]
hsplit是对行进行切分 a表示待切分的行参数 3表示切分成三份
np.hsplit(a,(3,4)) 传入元组 指定位置进行切割
vsplit是对列进行切分 a表示待切分的行参数 3表示切分成三份
19.view与copy
view是浅复制
举个例子:
import numpy as np a = np.arange(12) b = a print(b is a) b.shape = 3,4 print(a.shape) print(id(a)) print(id(b))
打印结果如下:
True (3, 4) 3144967327792 3144967327792
我们可以发现a与b的地址是相同的,这个就是所谓的深复制
让我再看看下面这个例子:
import numpy a = np.arange(12) c = a.view() print(c is a) c.shape = 2,6 print(a.shape) c[0,4] = 1234 print(a) print(id(a)) print(id(c))
打印结果如下:
False (12,) [ 0 1 2 3 1234 5 6 7 8 9 10 11] 2391025174608 2391025175008
我们可以看出浅复制不会复制a的地址到c,改变c的值不会影响到a
再看下一个写法:
import numpy as np a = np.arange(12) d = a.copy() d is a
打印结果如下:
False
从结果我们可以看出,copy也是属于浅拷贝
20.argmax
argmax 索引最大值的位置
举个例子:
import numpy as np data = np.sin(np.arange(20)).reshape(5,4) print(data) ind = data.argmax(axis=0) print(ind) data_max = data[ind,range(data.shape[1])] print(data_max)
打印结果如下:
[[ 0. 0.84147098 0.90929743 0.14112001] [-0.7568025 -0.95892427 -0.2794155 0.6569866 ] [ 0.98935825 0.41211849 -0.54402111 -0.99999021] [-0.53657292 0.42016704 0.99060736 0.65028784] [-0.28790332 -0.96139749 -0.75098725 0.14987721]] [2 0 3 1] [ 0.98935825 0.84147098 0.99060736 0.6569866 ]
argmax 索引最大值的位置
data.argmax(axis=0) axis=0意思是指定列去索引 找出最大值返回索引值的位置
21.tile
tile 对当前的行和列进行扩展
举个例子:
import numpy as np a = np.arange(0,40,10) print(a) b = np.tile(a,(3,5)) print(b)
打印结果如下:
[ 0 10 20 30] [[ 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30] [ 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30] [ 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30 0 10 20 30]]
我们可以看出,矩阵由原来的一维扩展到了三行五列
22.sort与argsort
sort 对当前的数组按照行的维度进行排序(因为axis=1)
argsort 是对值的索引进行排序 默认是值从小到大 然后按照值排序获取索引 输出索引
举个例子:
import numpy as np a = np.array([[4,3,5],[1,2,4]]) print(a) print('------') b = np.sort(a,axis=1) print(b) a.sort(axis=1) print('------') print(a) a = np.array([4,3,1,2]) j = np.argsort(a) print('------') print(j) print('------') print(a[j])
打印结果如下:
[[4 3 5] [1 2 4]] ------ [[3 4 5] [1 2 4]] ------ [[3 4 5] [1 2 4]] ------ [2 3 1 0] ------ [1 2 3 4]
以上是我在运用中所用到的一些函数及用法,欢迎大家指正批评,如果有需要改进的地方,还希望不吝赐教,如果觉得本文对你有用,别忘记关注订阅推荐博主,谢谢大家的支持!!!
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。