主要涉及到python相关数据分析库的基础了解
参考资料:
其他:
一、Numpy 基础
1、numpy 介绍
numpy是python数值计算领域很重要的包。主要有以下特点:
ndarray,一个有效的多维有效数组,能提供以数组为导向的快速数值计算和灵活的广播功能(broadcasting)
什么是“灵活的广播功能”?
简单讲就是两个维度不同的矩阵进行按位加减操作时,进行的兼容操作
相关介绍:
不解,这是什么操作?
2、数组对象
n维数组对象或者ndarray是numpy的关键特征
>>> import numpy as np
>>> data = np.random.randn(2,3)
>>> data
array([[-0.63472407, -0.93065189, 0.52834126],
[-0.79213003, -0.25700294, 1.47626494]])
>>> data * 10
array([[-6.34724069, -9.30651888, 5.28341258],
[-7.9213003 , -2.57002942, 14.76264944]])
>>> data + data
array([[-1.26944814, -1.86130378, 1.05668252],
[-1.58426006, -0.51400588, 2.95252989]])
>>> data.shape
(2, 3)
>>> data.dtype
dtype('float64')
1、创建数组对象
data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
# arr1
# array([ 6. , 7.5, 8. , 0. , 1. ])
这里觉得很奇怪,为什么小数点后面是空格,而不是0?而且我发现[[1,2,3],[1,2]]这个数据居然不会报错,但是也很奇怪。
这个其实不奇怪,python中也有后面带有一个小数点的情况
返回数组的行数
返回一个元组,包含数组的行数和列数
一般在生成数组是,np.array()会自动匹配类型
有趣的是,我试过一个数组中加入字符串,也是可以的,只不过数组类型发生了变化,不是数字的而已。这是否说明这种数组类型,不仅可以处理数学操作,也可以实现一些其他数据类型的操作呢?
生成一个array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
同上
这个方法不能保证返回的数组中的数值都是0,有可能会返回某些垃圾数值,如下
array([[[ 0.00000000e+000, 0.00000000e+000],
[ 2.16538378e-314, 2.16514681e-314],
[ 2.16511832e-314, 2.16072529e-314]],
[[ 0.00000000e+000, 0.00000000e+000],
[ 2.14037397e-314, 6.36598737e-311],
[ 0.00000000e+000, 0.00000000e+000]]])
生成array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
其他创建数组的函数
asarray:将传入数据转换为对应格式的ndarray,如果已经是目标的ndarray,则不copy
ones、ones_like:根据执行的格式和dtype创建一个全是1的数组;格局传入的数组格式,创建一个格式相同的全一数组
empty、empty_like:创建新数组,只分配内存空间,但不填充任何值
eye、identity:创建N*N的单位矩阵(对角线为1,其余为0)
empty的例子前面出现过,其实是有值的,为什么说是没有值呢?另外,创建empty之后,如果输出值,有没有输出呢?
还有eye和identity应该有些差别吧?
2、ndarrays的数据类型
创建数据时,可以声明创建的数据类型
arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
dtype才是numpy能灵活处理其他外界数据的原因。
类型介绍:
转换数据类型:
转换数据类型
float_arr = arr.astype(np.float64)
在转换不同的数据类型时,需要格外注意,比如由float转为int时,会截断小数点后面的数值。
3、数组计算
数组之所以重要,是因为不用写for循环就能表达很多操作
# 相乘
arr * arr
# 相减
arr - arr
# 标量运算
1 / arr
arr ** 0.5
# 数组比较,返回布尔数组
arr2 > arr
4、基本的索引和切片
# arr array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[5:8] = 12
# array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
这里有个区别在numpy的array和python的list之间,list的切片是生成了一个新的list,修改是不会影响原本的list,但是array的切片创建的是一个视图,如果修改是会影响到原本的array的。
arr_slice = arr[5:8]
arr_slice[1] = 12345
# arr array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8, 9])
即便赋值给另一个变量,修改也会影响到原来的array的
如果需要复制的话,可以使用arr[5:8].copy
切片可以被赋值为数组,也可以被赋值为标量,当为标量的时候,所有切片数组中的元素都会变为标量的值。
索引很简单,就是普通理解的两种
arr2d[0][2]
arr2d[0, 2]
对于一个多维数组
# 前两行
arr2d[:2]
# 前两行,后两列
arr2d[:2, 1:]
# 全部行,第一列
arr2d[:, :1]
提取出来之后,当然也可以赋值为标量或者数组,但是仍然这只是视图,会影响到原array的。
5、布尔索引
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
假设每一个名字对应data中的一行,我们希望提取出‘Bob’的那些行
names == 'Bob'
# array([ True, False, False, True, False, False, False], dtype=bool)
然后就可以把这个布尔数组作为索引
注意:布尔数组的长度要和data数组的长度一样长
name != 'Bob'
data[~(names == 'Bob')]
第二种方式在反转已有的条件时,会很方便。
多个布尔条件用布尔运算符&,|,另外python的and和or不管用
mask = (names == 'Bob') | (names == 'Will')
这也太方便了吧!?
6、花式索引
arr[[4, 3, 0, 6]]
可以从数组中提取出第4、3、0、6行,然后组成新的数组,arr[[-3, -5, -7]]
也可以,允许从后面找
arr[[1, 5, 7, 2], [0, 3, 1, 2]]
可以从数组中提取第(1,0), (5,3), (7,1),(2,2)个数值,前者代表行数,后者代表列数,共四个数字,以数组的形式按顺序排列返回。
arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
这个较为复杂,首先[[1, 5, 7, 2]]
这一部分将[0, 3, 1, 2]行提取出来,然后[:, [0, 3, 1, 2]]
表示选中所有的行,但是列的顺序要按[0, 3, 1, 2]的顺序来排。
第二部分(变换列顺序)的使用感觉有些陌生
7、数组转置和轴交换
有两种方式,但注意的是转置是返回一个视图,而不是新的数组
arr.reshape((row, column))
arr.T
计算矩阵乘法的时候经常会用到,np.dot()
对于多维数组,transpose会接受由轴数字组成的tuple,来交换轴
刚开始这段还没看懂,稍微有点复杂
arr = np.arange(16).reshape((2, 2, 4))
arr
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
arr.transpose((1, 0, 2))
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
转换的方式是把索引按照轴数字来变换,原本轴数字应该是(0,1,2),看arr的第一行是没有发生变化的,因为它的前两个数字都是0,而最后一行也没变,是因为,前两个索引数字都是1。
arr
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
arr.swapaxes(1, 2)
# 交换轴2和轴一
array([[[ 0, 4],
[ 1, 5],
[ 2, 6],
[ 3, 7]],
[[ 8, 12],
[ 9, 13],
[10, 14],
[11, 15]]])
3、通用函数:快速点对点数组函数
在我的理解中,点对点的意思就是单独处理数组中的每个元素
1、一元通用函数
就是只处理一个数组的
import numpy as np
arr = np.arange(10)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.sqrt(arr)
# array([ 0. , 1. , 1.41421356, 1.73205081, 2. ,
# 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
np.exp(arr)
# array([ 1.00000000e+00, 2.71828183e+00, 7.38905610e+00,
# 2.00855369e+01, 5.45981500e+01, 1.48413159e+02,
# 4.03428793e+02, 1.09663316e+03, 2.98095799e+03,
# 8.10308393e+03])
这些函数可以接受一个可选参数作为输出,如果是原数组,就可以直接修改原数组。
# 不会改变原数组
np.sqrt(arr)
# 会改变原数组
np.sqrt(arr, arr)
常用一元函数
等等
2、二院通用函数
# 返回两个数组,分别是小数部分,整数部分
remainder, whole_part = np.modf(arr)
二元通用函数
比较
4、数组导向编程
向量化的数组运算比纯python同等程度的运算快很多
0、np.meshgrid(方法)
meshgrid函数用两个坐标轴上的点在平面上画网格。
import numpy as np
m, n = (5, 3)
x = np.linspace(0, 1, m)
# array([ 0. , 0.25, 0.5 , 0.75, 1. ])
y = np.linspace(0, 1, n)
# array([ 0. , 0.5, 1. ])
X, Y = np.meshgrid(x, y)
# X
# array([[ 0. , 0.25, 0.5 , 0.75, 1. ],
# [ 0. , 0.25, 0.5 , 0.75, 1. ],
# [ 0. , 0.25, 0.5 , 0.75, 1. ]])
# Y
# array([[ 0. , 0. , 0. , 0. , 0. ],
# [ 0.5, 0.5, 0.5, 0.5, 0.5],
# [ 1. , 1. , 1. , 1. , 1. ]])
np.linespace()方法很明显是将前面两个参数的距离按第三个参数的数值等分,然后得到一个数组。虽然我不知道np.meshgrid()到底什么意思,但它的效果就是把第一个数组的个数作为列数,然后把第二个数组的个数作为行数,然后把两个数组编程维度相同的矩阵,如上。
可以使用zip得到坐标点的数据
z = [i for i in zip(X.flat, Y.flat)]
[(0.0, 0.0),
(0.25, 0.0),
(0.5, 0.0),
(0.75, 0.0),
(1.0, 0.0),
(0.0, 0.5),
(0.25, 0.5),
(0.5, 0.5),
(0.75, 0.5),
(1.0, 0.5),
(0.0, 1.0),
(0.25, 1.0),
(0.5, 1.0),
(0.75, 1.0),
(1.0, 1.0)]
0、开始运算
points = np.arange(-5, 5, 0.01)
# 这里我才注意到,arrange好像和linspace没什么差别啊
xs, ys = np.meshgrid(points, points)
z = np.sqrt(xs ** 2 + ys ** 2)
然后还可以把图像画出来
plt.imshow(z, cmap=plt.cm.gray)
plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
plt.show()
numpy.where函数是一个向量版的三相表达式,x if condition else y
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
# [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]
这样的缺点是处理较大数组时比较慢,其次是不能处理多维数组
result = np.where(cond, xarr, yarr)
# array([ 1.1, 2.2, 1.3, 1.4, 2.5])
np.where的第二和第三个参数不必是数组,
np.where(arr > 0, 2, -2)
np.where(arr > 0, 2, arr)
2、数学和统计方法
一些能计算统计值的数学函数能基于整个数组,或者沿着一个axis,比如sum,mean
arr = np.random.randn(5, 4)
array([[-1.53575656, -1.39268394, -1.02284353, -1.03165049],
[ 0.53301867, 0.50258973, -0.49389656, 0.24610963],
[ 0.95377174, -1.57268184, 0.42969986, 1.22912566],
[ 0.73686692, -2.82328155, 0.48018497, -1.38046692],
[ 0.94164808, 0.19599722, -0.88779738, -0.87556277]])
示例
arr.mean()
np.mean(arr)
mean或sum这样的函数能接受axis作为参数,返回结果的维度更少
arr.sum()
# 计算各列之间的平均值
arr.mean(axis=1)
# 计算各行总和
arr.sum(axis=0)
cumsum和cumprod不做汇总,而是产生一个中间结果的数组
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
arr.cumsum()
# array([ 0, 1, 3, 6, 10, 15, 21, 28])
对于多维数组,累加函数返回的是同样大小的数组
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])
# 沿着行累加
arr.cumsum(axis=0)
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]])
# 沿着列累乘
arr.cumprod(axis=1)
array([[ 0, 0, 0],
[ 3, 12, 60],
[ 6, 42, 336]])
3、布尔数组的方法
sum可以用来计算布尔数组中有多少个true
arr = np.random.randn(100)
(arr > 0).sum()
还有any和all对布尔数组特别有用
bools = np.array([False, False, True, False])
# 数组中存ture就返回ture
bools.any()
# 数组中都是true才返回ture
boos.all()
4、排序
对于一维数组
arr = np.random.randn(6)
arr.sort()
多维数组可以按照axis排序
arr = np.random.randn(5,3)
arr.sort(1)
上面的方法会修改数组的顺序,如果使用np.sort()函数,则会生成一个新的排序后的结果。
5、唯一和其他集合逻辑
np.unique()返回不重复的值
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
np.unique(names)
array(['Bob', 'Joe', 'Will'], dtype='<U4')
np.inld()测试一个数组的值是否在另一个数组里,返回布尔数组
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])
array([ True, False, False, True, True, False, True], dtype=bool)
其他集合操作
intersectld(x,y):计算x和y中的重复元素