(记录)Python机器学习——NumPy基础

一、安装NumPy

本地安装NumPy,进入命令行,输入pip install numpy即可。

NumPy在向量计算方面做了很多优化。核心数据结构是ndarray(全称是N-Dimension Arrary)是一个N维数组。ndarray是同质的。同质的意思就是说 N维数组里的所有元素必须是属于同一种数据类型的 。 (PS: python中的list是异质的) 。基本属性包含了shape,ndim,size,dtype。

shape:ndarray对象的形状,由一个tuple表示;

ndim:ndarray对象的维度;

size:ndarray对象中元素的数量;

dtype:ndarray对象中元素的数据类型,例如int64,float32等。

# 导入numpy并取别名为np
import numpy as np
# 构造ndarray,15个元素,3行5列
a = np.arange(15).reshape(3, 5)
# 打印a的shape,ndim,size,dtype
print(a.shape)
#shape是(3, 5)(代表3行5列);
print(a.ndim)
#ndim为2,行和列是2维的
print(a.size)
#size是15(因为矩阵总共有15个元素);
print(a.dtype)
#dtype是int32(因为矩阵中元素都是整数,并且用32位整型足够表示矩阵中的元素)。


二、实例化ndarray

最为常用的函数是array,zeros,ones以及empty。

(1)使用array函数实例化ndarray对象

使用NumPy中的array函数将list中的值作为初始值,来实例化一个ndarray对象。

a = np.array([2,3,4])

(2)使用zeros函数实例化ndarray对象

把ndarray的shape作为参数传进去即可。代码如下:

# 实例化ndarray对象a,a是一个3行4列的矩阵,矩阵中元素全为0
a = np.zeros((3, 4))

(3)使用ones函数实例化ndarray对象

# 实例化ndarray对象a,a是一个3行4列的矩阵,矩阵中元素全为1
a = np.ones((3, 4))

(4)使用empty函数用随机值作为初始值来实例化ndarray对象

# 实例化ndarray对象a,a是一个2行3列的矩阵,矩阵中元素全为随机值
a = np.empty((2, 3)) 

三、尝试

  • shape:为需要实例化出来的ndarray对象的shape

  • data:表示需要实例化出来的ndarray对象中元素的值。

例如:{'shape':[1, 2], 'data':[[1, 2]]}表示ndarray对象的形状为12列,第1行第1列的值为1,第1行第2列的值为2

测试输入: {'shape':[1, 2], 'data':[[1, 2]]}

预期输出: [[1 2]]



def print_ndarray(input_data):
    '''
    实例化ndarray对象并打印
    :param input_data: 测试用例,类型为字典类型
    :return: None
    '''

    #********* Begin *********#
    a=input_data#输入一个数组的data部分
    b = np.array(a['data'])
    print(b)
    #********* End *********#

一、改变ndarray对象的形状

(1)使用reshape函数不会改变原ndarray的形状,而是将源ndarray进行深拷贝并进行变形操作,最后再将变形后的数组返回出去。也就是说如果代码是np.reshape(a, (4, 3))那么a的形状不会被修改!


    import numpy as np
    a = np.zeros((3, 4))
    # 调用a的成员函数reshape将3行4列改成4行3列
    a = a.reshape((4, 3))

(2)使用resize函数:直接改变源ndarray的形状

    import numpy as np
    a = np.zeros((3, 4))
    # 将a从3行4列的二维数组变成一个有12个元素的一维数组
    a.resize(12)

(3)小技巧:一个68列的ndarray,然后想把它变形成有2列的ndarray(行的数量我懒得去想),此时我们可以在行的维度上传个-1即可。

import numpy as np

a = np.zeros((6, 8))

# 行的维度上填-1,会让numpy自己去推算出行的数量,很明显,行的数量应该是24
a = a.reshape((-1, 2))

PS-1虽好,可不能贪杯!如果代码改成a = a.reshape((-1, -1))NumPy会认为你是在刁难他,并向你抛出异常ValueError: can only specify one unknown dimension

二、尝试

测试输入: [[1, 2, 3], [4, 5, 6]] 预期输出: [1, 2, 3, 4, 5, 6]

import numpy as np

def reshape_ndarray(input_data):
    '''
    将ipnut_data转换成ndarray后将其变形成一位数组并打印
    :param input_data: 测试用例,类型为list
    :return: None
    '''

    #********* Begin *********#
    a=np.array(input_data) #实例化一个数组对象
    print(a.reshape(-1))
    #********* End *********#

一、运算

(1)算术运算

    import numpy as np
    a = np.array([0, 1, 2, 3])
    # a中的所有元素都加2,结果为[2, 3, 4, 5]
    b = a + 2
    # a中的所有元素都减2,结果为[-2, -1, 0, 1]
    c = a - 2
    # a中的所有元素都乘以2,结果为[0, 2, 4, 6]
    d = a * 2
    # a中的所有元素都平方,结果为[0, 1, 4, 9]
    e = a ** 2
    # a中的所有元素都除以2,结果为[0, 0.5, 1, 1.5]
    f = a / 2
    # a中的所有元素都与2比,结果为[True, True, False, False]
    g = a < 2

(2)矩阵运算

    import numpy as np
    a = np.array([[0, 1], [2, 3]])
    b = np.array([[1, 1], [3, 2]])
    # a与b逐个元素相加,结果为[[1, 2], [5, 5]]
    c = a + b
    # a与b逐个元素相减,结果为[[-1, 0], [-1, 1]]
    d = a - b
    # a与b逐个元素相乘,结果为[[0, 1], [6, 6]]
    e = a * b
    # a的逐个元素除以b的逐个元素,结果为[[0., 1.], [0.66666667, 1.5]]
    f = a / b
    # a与b逐个元素做幂运算,结果为[[0, 1], [8, 9]]
    g = a ** b
    # a与b逐个元素相比较,结果为[[True, False], [True, False]]
    h = a < b

使用@和dot函数来实现矩阵乘法。

    import numpy as np
    A = np.array([[1, 1], [0, 1]])
    B = np.array([[2, 0], [3, 4]])
    # @表示矩阵乘法,矩阵A乘以矩阵B,结果为[[5, 4], [3, 4]]
    print(A @ B)
    # 面向对象风格,矩阵A乘以矩阵B,结果为[[5, 4], [3, 4]]
    print(A.dot(B))
    # 面向过程风格,矩阵A乘以矩阵B,结果为[[5, 4], [3, 4]]
    print(np.dot(A, B))

(3)简单统计

summinmaxargminargmax等函数来实现简单的统计功能

    import numpy as np
    a = np.array([[-1, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 13]])
    # 计算a中所有元素的和,结果为67
    print(a.sum())
    # 找出a中最大的元素,结果为13
    print(a.max())
    # 找出a中最小的元素,结果为-1
    print(a.min())
    # 找出a中最大元素在a中的位置,由于a中有12个元素,位置从0开始计,所以结果为11
    print(a.argmax())
    # 找出a中最小元素在a中位置,结果为0
    print(a.argmin())

有的时候,我们在统计时需要根据轴来统计。举个例子,公司员工的基本工资,绩效工资,年终奖的信息如下:

工号 基本工资 绩效工资 年终奖
1 3000 4000 20000
2 2700 5500 25000
3 2800 3000 15000

这样一个表格很明显,可以用ndarray来存储。

import numpy as np

info = np.array([[3000, 4000, 20000], [2700, 5500, 25000], [2800, 3000, 15000]])

info实例化之后就有了维度和轴的概念,很明显info是个二维数组,所以它的 维度是2 。维度为2换句话来说就是info两个轴:0号轴与1号轴(轴的编号从0开始算)。轴所指的方向如下图所示:

如果想要统计下这3位员工中基本工资、绩效工资与年终奖的最小值与最大值(也就是说分别统计出每一列中的最小与最大值)。我们可以沿着0号轴来统计。想要实现沿着哪个轴来统计,只需要修改axis即可。

import numpy as np

info = np.array([[3000, 4000, 20000], [2700, 5500, 25000], [2800, 3000, 15000]])

# 沿着0号轴统计,结果为[2700, 3000, 15000]
print(info.min(axis=0))

# 沿着0号轴统计,结果为[3000, 5500, 25000]
print(info.max(axis=0))

PS:当没有修改axis时,axis的值默认为None。意思是在统计时会把ndarray对象中所有的元素都考虑在内。

二、尝试

测试输入: [[0.2, 0.7, 0.1], [0.1, 0.3, 0.6]] 预期输出: [1 2]

import numpy as np


def get_answer(input_data):
    '''
    将input_data转换成ndarray后统计每一行中最大值的位置并打印
    :param input_data: 测试用例,类型为list
    :return: None
    '''

    #********* Begin *********#
    a = np.array(input_data)
    print(a.argmax(axis=1))# 沿着1号轴统计
    #********* End *********#

一、简单随机数生成

NumPyrandom模块下提供了许多生成随机数的函数,如果对于随机数的概率分布没有什么要求,则通常可以使用random_samplechoicerandint等函数来实现生成随机数的功能。

(1)random_sample

用于生成区间为[0, 1]的随机数,需要填写的参数size表示生成的随机数的形状,比如size=[2, 3]那么则会生成一个23列的ndarray,并用随机值填充。

    import numpy as np
    '''
    结果可能为[[0.32343809, 0.38736262, 0.42413616]
              [0.86190206, 0.27183736, 0.12824812]]
    '''
    print(np.random.random_sample(size=[2, 3]))

 (2)choice

如果想模拟像掷骰子、扔硬币等这种随机值是离散值,而且知道范围的可以使用choice实现。choice的主要参数是asizereplacea是个一维数组,代表你想从a中随机挑选;size是随机数生成后的形状。假如模拟5次掷骰子,replace用来设置是否可以取相同元素,True表示可以取相同数字;False表示不可以取相同数字,默认是True。

    import numpy as np
    '''
    掷骰子时可能出现的点数为1, 2, 3, 4, 5, 6,所以a=[1,2,3,4,5,6]
    模拟5此掷骰子所以size=5
    结果可能为 [1 4 2 3 6]
    '''
    print(np.random.choice(a=[1, 2, 3, 4, 5, 6], size=5,replace=False))

(3)randint

randint的功能和choice差不多,只不过randint只能生成整数,而choice生成的数与a有关,如果a中有浮点数,那么choice会有概率挑选到浮点数。

randint的参数有3个,分别为lowhighsize。其中low表示随机数生成时能够生成的最小值,high表示随机数生成时能够生成的最大值减1。也就是说randint生成的随机数的区间为[low, high)。假如模拟5次掷骰子,代码如下:

    import numpy as np
    '''
    掷骰子时可能出现的点数为1, 2, 3, 4, 5, 6,所以low=1,high=7
    模拟5此掷骰子所以size=5
    结果可能为 [6, 4, 3, 1, 3]
    '''
    print(np.random.randint(low=1, high=7, size=5)

(4)概率分布随机数生成

高斯分布又称为正态分布,其分布图形如下:

上图中横轴为随机变量的值(在这里可以看成是产生的随机值),纵轴表示随机变量对应的概率(在这里可以看成是随机值被挑选到的概率)。想要实现根据高斯分布来产生随机值,可以使用normal函数。

    import numpy as np
    '''
    根据高斯分布生成5个随机数
    结果可能为:[1.2315868, 0.45479902, 0.24923969, 0.42976352, -0.68786445]
    从结果可以看出0.4左右得值出现的次数比较高,1和-0.7左右的值出现的次数比较低。
    '''
    print(np.random.normal(size=5))

normal函数除了size参数外,还有两个比较重要的参数就是locscale,它们分别代表高斯分布的均值方差loc影响的分布中概率最高的点的位置,假设loc=2,那么分布中概率最高的点的位置就是2。下图体现了loc对分布的影响,其中蓝色f分布的loc=0,红色分布的loc=5

scale影响的是分布图形的胖瘦,scale越小,分布就越又高又瘦,scale越大,分布就越又矮又胖。下图体现了scale对分布的影响,其中蓝色分布的scale=0.5,红色分布的scale=1.0

所以,想要根据均值为1,方差为10的高斯分布来生成5个随机值,代码如下:

import numpy as np

print(np.random.normal(loc=1, scale=10, size=5))

(5)随机种子

计算机产生的随机数是由随机种子根据一定的计算方法计算出来的数值。所以只要计算方法固定,随机种子固定,那么产生的随机数就不会变!

如果想要让每次生成的随机数不变,那么就需要设置随机种子(随机种子其实就是一个0232−1的整数)。设置随机种子很长简单,调用seed函数并设置随机种子即可。

import numpy as np
# 设置随机种子为233
np.random.seed(seed=233)
data = [1, 2, 3, 4]
# 随机从data中挑选数字,结果为4
print(np.random.choice(data))
# 随机从data中挑选数字,结果为4

(6)索引

ndarray的索引其实和pythonlist的索引极为相似。元素的索引从0开始。

    import numpy as np
    # a中有4个元素,那么这些元素的索引分别为0,1,2,3
    a = np.array([2, 15, 3, 7])
    # 打印第2个元素
    # 索引1表示的是a中的第2个元素
    # 结果为15
    print(a[1])
    # b是个2行3列的二维数组
    b = np.array([[1, 2, 3], [4, 5, 6]])
    # 打印b中的第1行
    # 总共就2行,所以行的索引分别为0,1
    # 结果为[1, 2, 3]
    print(b[0])
    # 打印b中的第2行第2列的元素
    # 结果为5
    print(b[1][1])

(7)遍历

ndarray的遍历方式与pythonlist的遍历方式也极为相似

    import numpy as np
    a = np.array([2, 15, 3, 7])
    # 使用for循环将a中的元素取出来后打印
    for element in a:
        print(element)
    # 根据索引遍历a中的元素并打印
    for idx in range(len(a)):
        print(a[idx])
    # b是个2行3列的二维数组
    b = np.array([[1, 2, 3], [4, 5, 6]])
    # 将b展成一维数组后遍历并打印
    for element in b.flat:
        print(element)
    # 根据索引遍历b中的元素并打印
    for i in range(len(b)):
        for j in range(len(b[0])):
            print(b[i][j])

(8)切片

假设想要将下图中紫色部分切片出来,就需要确定行的范围和列的范围。由于紫色部分行的范围是02,所以切片时行的索引范围是0:3(索引范围是左闭右开);又由于紫色部分列的范围也是02,所以切片时列的索引范围也是0:3(索引范围是左闭右开)。最后把行和列的索引范围整合起来就是[0:3, 0:3](,左边是行的索引范围)。当然有时为了方便,0可以省略,也就是[:3, :3]

    import numpy as np
    # a中有4个元素,那么这些元素的索引分别为0,1,2,3
    a = np.array([2, 15, 3, 7])
    '''
    将索引从1开始到最后的所有元素切片出来并打印
    结果为[15  3  7]
    '''
    print(a[1:])
    '''
    将从倒数第2个开始到最后的所有元素切片出来并打印
    结果为[3  7]
    '''
    print(a[-2:])
    '''
    将所有元素倒序切片并打印
    结果为[ 7  3 15  2]
    '''
    print(a[::-1])
    # b是个2行3列的二维数组
    b = np.array([[1, 2, 3], [4, 5, 6]])
    '''
    将第2行的第2列到第3列的所有元素切片并打印
    结果为[[5 6]]
    '''
    print(b[1:, 1:3])
    '''
    将第2列到第3列的所有元素切片并打印
    结果为[[2 3]
          [5 6]]
    '''
    print(b[:, 1:3])

猜你喜欢

转载自blog.csdn.net/qq_43659681/article/details/130175361
今日推荐