【Python数据挖掘】Numpy使用手册二

474 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

🔥 本文由 程序喵正在路上 原创,在稀土掘金首发!
💖 系列专栏:数据挖掘
🌠 首发时间:2022年8月30日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

四、ndarray运算

1. 逻辑运算

如果我们想要操作符合某一条件的数据时,该怎么做呢?

import numpy as np

stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))

# 重新生成8只股票10个交易日的涨跌幅数据
stock_change = np.random.normal(0, 1, (8, 10))
stock_change = stock_change[0:5, 0:5]
# 需求一:逻辑判断,如果涨跌幅大于0.5就标记为True,否则为False
stock_change > 0.5

image.png

# 需求二:BOOL赋值,将满足条件的设置为指定的值-布尔索引
stock_change[stock_change > 0.5] = 1
stock_change

image.png

通用判断函数

  • np.all()

    # 判断stock_change[0:2, 0:5]是否全部是上涨的
    np.all(stock_change[0:2, 0:5] > 0)
    
    False
    
  • np.any()

    # 判断前5只股票这段期间是否有上涨的
    np.any(stock_change[0:5, :] > 0)
    
    True
    

np.where(三元运算符)

通过使用 np.where 能够进行更加复杂的运算

  • np.where(布尔值,True的位置的值,False的位置的值)

    # 判断前4个股票前4天的涨跌幅,大于0的置为1,否则为0
    temp = stock_change[:4, :4]
    np.where(temp > 0, 1, 0)
    

image.png

  • 复合逻辑需要结合 np.logical_andnp.logical_or 使用

    # 判断前4个股票前4天的涨跌幅,大于0.5且小于1的,换为1,否则为0
    np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0)
    

image.png

# 判断前4个股票前4天的涨跌幅,大于0.5或者小于-0.5的,换为1,否则为0
np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0)

image.png

2. 统计计算

如果想要知道涨幅或者跌幅最大的数据,应该怎么做?

(1)统计指标

在数据挖掘 / 机器学习领域,统计指标的值也是我们分析问题的一种方式,常用的指标如下:

  • np.min(a[, axis, out, keepdims]) Return the minimum of an array or minimum along an axis
    返回数组的最小值或沿轴的最小值
  • np.max(a[, axis, out, keepdims]) Return the maximum of an array or maximum along an axis
    返回数组的最大值或沿轴的最大值
  • np.median(a[, axis, out, overwrite_input, keepdims]) Compute the median along the specified axis
    沿指定轴计算中值
  • np.mean(a[, axis, dtype, out, keepdims]) Compute the arithmetic mean along the specified axis
    沿指定轴计算算术平均值
  • np.std(a[, axis, dtype, out, ddof, keepdims]) Compute the standard deviation along the specified axis
    沿指定轴计算标准偏差
  • np.var(a[, axis, dtype, out, ddof, keepdims]) Compute the variance along the specified axis
    沿指定轴计算方差

(2)股票涨跌幅统计运算

进行统计的时候,axis 轴的取值并不一定,Numpy 中不同的 API 轴的值都不一样,在这里,axis=0 代表列,axis=1 代表行去进行统计

import numpy as np

# 接下来对于这4只股票的4天数据,进行一些统计运算
temp = stock_change[:4, :4]

# 指定行去统计
print("前4只股票前4天的最大涨幅为{}".format(np.max(temp, axis=1)))
# 使用min,std,mean
print("前4只股票前4天的最大跌幅为{}".format(np.min(temp, axis=1)))
print("前4只股票前4天的波动程度为{}".format(np.std(temp, axis=1)))
print("前4只股票前4天的平均涨跌幅为{}".format(np.mean(temp, axis=1)))

image.png

如果需要统计出哪一只股票在某个交易日的涨幅最大或者最小?

  • np.argmax(temp, axis=)
  • np.argmin(temp, axis=)
# 获取股票指定哪一天的涨幅最大
print("前4只股票前4天内涨幅最大为{}".format(np.argmax(temp, axis=1)))
print("前4天1天内涨幅最大的股票为{}".format(np.argmax(temp, axis=0)))

image.png

3. 数组间运算

(1)场景

image.png 数据:

[[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]]

(2)数组与数的运算

arr = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
arr + 1

image.png

arr / 2 

image.png

# 对比python列表的运算,看出区别
a = [1, 2, 3, 4, 5]
a * 3

image.png

(3)数组与数组的运算

arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
arr2 = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
arr1 + arr2  # 两个数组这样是不能进行运算的

image.png

(4)广播机制

执行 broadcast 的前提在于,两个 ndarray 执行的是 element-wise 的运算,Broadcast 机制的功能而是为了方便不同形状的 ndarraynumpy 库的核心数据结构)进行数学运算

当操作两个数组时,numpy 会逐个比较它们的 shape (构成的元组 tuple),只有在下述情况下,两个数组才能够进行数组与数组的运算

  • 维度相等
  • shape(其中相对应的一个地方为 1

例如:

维度相等
Image (3d array):  256 x 256 x 3
Scale (1d array):   		   3
Result (3d array): 256 x 256 x 3

其中相对应的一个地方为 1
A      (4d array):  9 x 1 x 7 x 1
B      (3d array):      8 x 1 x 5
Result (4d array):  9 x 8 x 7 x 5

其中相对应的一个地方为 1
A      (2d array):  5 x 4
B      (1d array):      1
Result (2d array):  5 x 4

维度相等,其中相对应的一个地方为 1
A      (3d array):  15 x 3 x 5
B      (3d array):  15 x 1 x 1
Result (3d array):  15 x 3 x 5

最终结果是取最大维度

如果是下面这样,则不匹配:

A      (1d array):  10
B      (1d array):  12

A      (2d array):  	2 x 1
B      (3d array):  8 x 4 x 3

思考:下面两个 ndarray 是否能够进行运算?

arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]]) 
arr2 = np.array([[1], [3]]) 
arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]]) # 2 x 6
arr2 = np.array([[1], [3]]) # 2 x 1
# 维度相等,其中相对应的一个地方为 1,可以进行运算
arr1 + arr2

image.png

4. 矩阵运算

现在再次回到最开始的学生成绩问题:

image.png 思考:如何能够直接得出每个学生的成绩呢?

(1)什么是矩阵

矩阵,英文 matrix,和 array 的区别是:矩阵必须是二维的,但是 array 可以是多维的

  • np.mat() 将数组转换成矩阵类型

    a = np.array([[80, 86],
    [82, 80],
    [85, 78],
    [90, 90],
    [86, 82],
    [82, 90],
    [78, 80],
    [92, 94]])
    
    np.mat(a)
    

image.png

(2)矩阵乘法运算

矩阵乘法的两个关键:

  • 形状改变
  • 运算规则

形状改变:

(M行,N列)x (N行,L列)= (M行,L列)

必须符合上面的式子,否则运算出错!

运算规则:

Am x p 的矩阵,Bp x n 的矩阵,那么称 m x n 的矩阵 CAB 的乘积,记作 C = AB,其中矩阵 C 中的第 i 行第 j 列元素可以表示为下式:

image.png 例如:

image.png 上式:(2,3)x(3,2)=(2,2)

左上 —— A第1行 x B第1列 右上 —— A第1行 x B第2列 左下 —— A第2行 x B第1列 右下 —— A第2行 x B第2列

直接得出每个学生的成绩:

a = np.array([[80, 86],  # (8 x 2)
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])

b = np.array([[0.3],  # (2 x 1)
              [0.7]])

a_mat = np.mat(a)
b_mat = np.mat(b)
a_mat * b_mat

image.png

(3)矩阵乘法API

  • np.matmul
  • np.dot
a = np.array([[80, 86],  # (8 x 2)
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])

b = np.array([[0.3],  # (2 x 1)
              [0.7]])

np.matmul(a,b)

image.png

np.dot(a,b)

image.png

拓展解法:

a @ b

image.png

5. 合并、分割

合并、分割的用处:

实现数据的切分和合并,将数据进行切分合并处理

(1)合并

  • numpy.hstack(tup) Stack arrays in sequence horizontally (column wise)
  • numpy.vstack(tup) Stack arrays in sequence vertically (row wise)
  • numpy.concatenate((a1, a2, ...), axis=0)

实例:

  • np.hstack()
a = np.array((1, 2, 3))
b = np.array((2, 3, 4))
np.hstack((a, b))

image.png

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

image.png

  • np.vstack()
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
np.vstack((a, b))

image.png

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

image.png

  • np.concatenate()
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
np.concatenate((a, b), axis=0)

image.png

np.concatenate((a, b.T), axis=1) # 。T 进行转置

image.png

比如我们将两部分股票的数据拼接在一起:

stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))

a = stock_change[:2, 0:4]
b = stock_change[4:6, 0:4]
# axis=1时,按照数组的列方向拼接在一起
# axis=0时,按照数组的行方向拼接在一起
np.concatenate([a, b], axis=0)

image.png

np.concatenate([a, b], axis=1)

image.png

np.vstack((a, b))

image.png

np.hstack((a, b))

image.png (2)切割

  • numpy.split(ary, indices_or_sections, axis=0)
    Split an array into mutiple sub-arrays
x = np.arange(9.0)
x

image.png

np.split(x, 3)

image.png

x = np.arange(8.0)
x

image.png

np.split(x, [3, 5, 6, 10])

image.png

6. IO操作与数据处理

大多数数据并不是我们自己构造的,而是存在文件当中,需要我们用工具来获取

但是,Numpy 其实并不适合用来读取和处理数据,因此我们这里了解相关 API,以及 Numpy 不方便的地方即可

(1)Numpy读取

  • genfromtxt(fname[, dtype, comments, ...]) Load data from a text file, with missing values handed as specified

准备一个 “test.csv” 文件,内容如下

id,value1,value2,value3
1,123,1.4,23
2,110,,18
3,,2.1,19

image.png

data = np.genfromtxt("test.csv",delimiter=",")
data

image.png 可以看到,读取结果有缺失值

(2)如何处理缺失值

什么是缺失值?

什么时候 Numpy 中会出现 nan:当我们读取本地的文件为 float 的时候,如果有缺失 (或者为 None),就会出现 nan

缺失值处理

那么,如果我们单纯地把数据中的 nan 替换为 0,合适吗?会带来什么样的影响?

比如,全部替换为 0 后,替换之前的平均值如果大于 0,替换之后的均值肯定会变小,所以更一般的方式是把缺失的数值替换为均值(中值)或者是直接删除有缺失值的一行

所以:

  • 如何计算一组数据的中值或者是均值
  • 如何删除有缺失数据的那一行(列)在 pandas 中介绍
# data中存在nan值,如何操作把其中的nan填充为每一列的均值
data = array([[  nan,   nan,   nan,   nan],
       [  1. , 123. ,   1.4,  23. ],
       [  2. , 110. ,   nan,  18. ],
       [  3. ,   nan,   2.1,  19. ]])

处理逻辑:

def fill_nan_by_column_mean(t):
    for i in range(t.shape[1]):
        # 计算nan的个数
        nan_num = np.count_nonzero(t[:, i][t[:, i] != t[:, i]])
        
        if nan_num > 0:
            now_col = t[:, i]
            # 求和
            now_col_not_nan = now_col[np.isnan(now_col) == False].sum()
            # 和/个数
            now_col_mean = now_col_not_nan / (t.shape[0] - nan_num)
            # 赋值给now_col
            now_col[np.isnan(now_col)] = now_col_mean
            # 赋值给t,即更新t的当前列
            t[:, i] = now_col
    return t

fill_nan_by_column_mean(data)

image.png

看了上面的处理过程,你肯定觉得太麻烦了吧,等我们学了 pandas 之后就好处理了