NumPy(Numerical Python)是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多(该结构也可以用来表示矩阵(matrix)),支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
使用以下代码,安装numpy,
pip install numpy
我们将使用jupyter notebook进行以下操作。
numpy.array()方法用来创建数组(一维或多维)。例如,
base_array = np.array([1, 2, 3]) # 创建一个一维数组
base_array # 展示数组
# 创建多维数组,一个中括号为一维,我们只需数出最左边有多少个左括号就可以获得维数
base_narray = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) # 创建一个三维数组
base_narray
注意,numpy创建的数组和python中的数组(列表)的数据格式不同。
python_array = [1, 2, 3]
type(python_array[0]) # 数据类型为int
type(base_array[0]) # 数据类型为int64(或int32)
我们可以通过ndim和shape属性查看数组的维数和形态,
base_array.ndim # 结果为1
base_narray.ndim # 结果为3
base_array.shape # 结果为(3,)
base_narray.shape # 结果为(2, 2, 3)
注意,base_narray的结果(2, 2, 3)第一个2为该三维数组有两个二维数组,第二个2意为每个二维数组中有两个一维数组,3意为每个一维数组中有三个元素。
数组的切片是我们之后常会用到的操作,我们首先创建一个三维数组,
base_slice = np.array([[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], [[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]])
base_slice
创建好的数组形态如下,
array([[[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]])
我们可以使用类似python列表取元素的方法,获取其中的指定下标对应的元素,
base_slice[1] # 取三维数组中下标为1的二维数组
结果为,
array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]])
base_slice[1][0] # 在下标为1的二维数组中取下标为0的一维数组
结果如下,
array([11, 12, 13, 14, 15])
base_slice[1][0][4] # 在下标为1的二维数组中的下标为0的一维数组中取下标为4的元素
结果如下,
15
同样,数组的切片操作类似python列表的切片。对于每一个维度的切片需要用:
隔开,
base_slice[:1,:,:] # 从下标为0的二维数组截取到下标为1的二维数组,不包括下标为1的二维数组
结果为,
array([[[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]]])
base_slice[:1,1:,:] # 在上面切片的基础上,从下标为1的一维数组截取到最后
结果为,
array([[[ 6, 7, 8, 9, 10]]])
base_slice[:1,1:,3:] # 在上面切片的基础上,从下标为3的元素截取到最后
结果为,
array([[[ 9, 10]]])
我们在切片的基础上还可以选定切片间隔,同样是通过:
进行分割,
base_slice[:1,1:,::2] # 设定元素切片间隔为2
结果为,
array([[[ 6, 8, 10]]])
与python切片的规则相同,如果切片间隔为正数,则开始索引必须小于结束索引;如果切片间隔为负数,则开始索引必须大于结束索引。
我们可以将多维数组变为低维数组,
data_shape = np.array([[1, 2, 3], [5, 5, 6], [7, 7, 9], [10, 11, 12]])
我们需要使用reshape()方法将数组变形,
data_shape.reshape(12,) # 将二维数组变为一维数组
结果为,
array([ 1, 2, 3, 5, 5, 6, 7, 7, 9, 10, 11, 12])
我们也可以使用-1让计算机自动计算数组个数,
data_shape.reshape(-1,)
结果与上面相同。
data_shape.reshape(2, 6) # 将数组变为两个二维数组,每个二维数组中包含6个元素
结果为,
array([[ 1, 2, 3, 5, 5, 6],
[ 7, 7, 9, 10, 11, 12]])
我们也可以将其中的任意一个参数设置为-1,让计算机自动计算,但是不能同时为-1。如果设定的参数无法除尽,则计算机页无法识别。
我们可以使用astype()方法,修改数组中元素的数据类型,例如,
data_type = np.array([1, 2, 0.6, 10])
data_type.astype(np.float)
结果为,
array([ 1. , 2. , 0.6, 10. ])
numpy对算数方法进行了重写,使得我们可以更加简单的对数组进行计算,例如,
data_com = np.array([1, 2, 3, 4, 5, 6])
data_com ** 2 # 对数组中的每个元素进行平方
结果为,
array([ 1, 4, 9, 16, 25, 36], dtype=int32)
我们可以自定义方法进行数组计算,numpy会对数组中的每一个元素分别进行对应计算,
def logit(x):
return 1/(1 + np.e ** (-x)
logit(data_com)
结果为,
array([0.73105858, 0.88079708, 0.95257413, 0.98201379, 0.99330715,
0.99752738])
对于数组之间的加法,只要数组结构相同,可以进行计算,例如,
a = np.array([1, 2])
b = np.array([3, 4])
a + b
结果为,
array([4, 6])
我们可以对数组进行判断,会得到一个布尔数组,
cal_array = np.array([1, 2, 3, 4, 5, 6])
cal_array[:] > 3
结果为,
array([False, False, False, True, True, True])
我们使用这样一个布尔数组对数组进行筛选,系统会返回True的元素,
cal_array[cal_array[:] > 3]
结果为,
array([4, 5, 6])
numpy可以进行简单的数据处理,
data_score = np.genfromtxt("score.csv", delimiter=",") # 读取score.csv文件,以逗号为分隔符
data_score
结果为,
array([[ 90., 80., 100., 60., 80., 60.],
[ 95., 76., 60., 90., 65., 20.],
[ 70., 69., 70., 65., 90., 90.],
[ 92., 73., 89., 82., 60., 57.],
[ 72., 30., 60., 90., 50., 20.],
[ 70., 90., 100., 86., 100., 30.]])
取出第一列的所有数据,
data_score[:,0]
结果为,
array([90., 95., 70., 92., 72., 70.])
取出第一行的所有数据,
data_score[0]
结果为,
array([ 90., 80., 100., 60., 80., 60.])
numpy同样支持聚合函数的操作,
data_score.mean(axis=1) # axis参数为1表示按行统计平均值
结果为,
array([78.33333333, 67.66666667, 75.66666667, 75.5 , 53.66666667,
79.33333333])
data_score.mean(axis=0) # axis参数为0表示按列统计平均值
结果为,
array([81.5 , 69.66666667, 79.83333333, 78.83333333, 74.16666667,
46.16666667])
pandas是一个可编程的ETL(Extract Transform Load)工具,支持多数据源并内置了丰富的选择变换函数。
我们刚才使用numpy对数据进行操作的时候,numpy无法显示行号和列号,在实际工作中会给我们带来很大的不便。pandas对numpy进行了封装,使我们操作起来更加人性化。
pandas有两种基本数据类型,一维数组(Series)和二维数组(DataFrame)。
我们使用pandas.Series()方法创建一维数组,我们可以添加index参数为数据添加索引,
s = pd.Series([1, 2, 3], index=["20207", "20208", "20209"])
结果为,
20207 1
20208 2
20209 3
dtype: int64
之后,我们可以通过索引名对数据进行选取,
s["20207":"20209"]
结果为,
20207 1
20208 2
20209 3
dtype: int64
我们使用pandas.DataFrame()方法创建二维数组,
df = pd.DataFrame({"数学":[1, 2, 3, 4, 5], "语文":[6, 7, 8, 9, 10]})
df
列名为数学和语文的二维数组。
我们同样可以使用列名(索引名)对数据进行选取,
df["数学"]
结果为,
0 1
1 2
2 3
3 4
4 5
Name: 数学, dtype: int64
我们对score.csv文件中的数据进行操作,
df_score = pd.read_csv("score.csv") # 读取csv文件
df_score[df_score["数学"] > 90] # 将数学成绩大于90的选出来
df_score[df_score["性别"] == "女"] # 等同于select * from score where 性别="女"
df_score[df_score["性别"].str.contains("女")] # 等同于select * from score where 性别 like "%女%"
df_score[(df_score["数学"] > 90) & (df_score["音乐"] > 60)] # 等同于select * from score where 数学 > 90 and 音乐 > 60,使用“&”符号代表and
df_score[(df_score["数学"] > 90) | (df_score["音乐"] > 60)] # 等同于select * from score where 数学 > 90 or 音乐 > 60,使用“|”符号代表or
df_score.loc[:,:] # 使用loc选取数据
df_score.loc[1:3,"数学":"英语"] # 选取下标从1到3(包含3)且列名从数学到英语的数据
df_score.loc[df_score["性别"].str.contains("女"), ["音乐", "体育"]] # 等同于select 音乐,体育 from score where 性别 like "%女%",loc第一个写筛选条件,第二个写要选取的列
使用pandas对数据进行删除,并不会对源数据产生影响,因此,一般作为选取数据的另一种方法,很少使用。
df_score.drop([1, 2]) # 删除index是1和2的行
df_score["数学"].apply(lambda x: x + 2) # 使用lambda函数对数学列的数据进行处理,同样不会对源数据产生影响,需要对源数据重新赋值
df_score["数学"] = df_score["数学"].apply(lambda x: x + 2) # 对源数据重新赋值
def add_score(x):
return x + 2
df_score["数学"] = df_score["数学"].apply(lambda x: add_score(x)) # 使用自定义函数对数据进行处理
df_score.loc[df_score["性别"].str.contains("女"), "性别"] = 2 # 将性别为女的所有数据的性别值改为2
df_score["总分"] = df_score.sum(axis=1) # 新增总分列
df_score.sort_values(by="总分", ascending=False) # 将数据按照总分列降序排列
df_score.info() # 获取数据信息
df_score.sum(axis=1) # 将数据进行加总