python学习笔记--Numpy模块(二)

目录

  • 传送门
  • 数组拼接
    • 垂直拼接(np.vstack)
    • 水平拼接
  • 索引与切片
    • 一维数组索引与切片
    • 二维数组索引与切片
    • 修改数组中的值
  • 将条件逻辑作为数组操作
  • 基础数组常用方法
    • 前置
    • sum
    • mean
    • max,min
    • argmax,argmin
    • std,var
    • ptp
    • cumsum
    • median
  • NaN与inf
    • NaN和inf的介绍
    • NaN的特性
    • NaN的处理
  • Numpy读取本地文件

传送门

Numpy模块(一).

数组拼接

在使用拼接前, 先创建两个数组

import numpy as np

arr = np.arange(12).reshape(2, 6)
arr1 = np.arange(12, 24).reshape(2, 6)
print(arr)
print(arr1)


# 返回结果
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
 
[[12 13 14 15 16 17]
 [18 19 20 21 22 23]]

垂直拼接(np.vstack)

使用垂直拼接, 拼接两个数组

arr2 = np.vstack((arr, arr1))  # 垂直拼接, 行堆叠数组
print(arr2)

#返回结果
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]

水平拼接

使用水平拼接, 拼接两个数组

arr3 = np.hstack((arr, arr1))
print(arr3)  # 水平拼接, 列堆叠数组

#返回结果
[[ 0  1  2  3  4  5 12 13 14 15 16 17]
 [ 6  7  8  9 10 11 18 19 20 21 22 23]]
  • 注意:水平拼接需要对应行数一致,垂直拼接需要对应列数一致。

索引与切片

一维数组索引与切片

先创建一维数组

import numpy as np

arr = np.arange(10)
print(arr)

# 返回结果:
[0 1 2 3 4 5 6 7 8 9]

一维数组切片其实和list的切片很类似


print(arr[2])  # 取下标为2的值, 下标从0开始
# 返回结果
2

print(arr[:2])  # 取前两个数值
# 返回结果
[0 1]

print(arr[7:]) # 取后面三个值
# 返回结果
[7 8 9]

print(arr[-1])  # 取最后一个值
# 返回结果
9

print(arr[1::2])  #取[1,3,5,7,9]
# 返回结果
[1 3 5 7 9]

print(arr[::-1])  # 倒序取值
# 返回结果
[9 8 7 6 5 4 3 2 1 0]

二维数组索引与切片

先创建二维数组

import numpy as np

arr = np.arange(24).reshape(4, 6)
print(arr)

# 返回结果
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]

其实简单的看二维数组, 它跟列表嵌套列表很像"[[ ], [ ], [ ],[ ]]", 因此取值也跟这种列表嵌套列表的方式一样。

print(arr[1])  # 取第二行
# 返回结果
[ 6  7  8  9 10 11]

print(arr[1][1]) # 取第二行的第二个数
#返回结果
7

但是数组中有更加方便的取值方式, 利用逗号分隔即可, 即"[行, 列]"

print(arr[1, :])  # 取第二行, 由于是取整行的数据, 因此列写个:即可
# 返回结果
[ 6  7  8  9 10 11]

print(arr[1, 1])  # 取第二行的第二个数
# 返回结果
7

print(arr[1:3, :])  # 取第2~3连续行
# 返回结果
[[ 6  7  8  9 10 11]
 [12 13 14 15 16 17]]

print(arr[1:3, 1:5])  # 取第2~3连续行并且第2~4连续列
# 返回结果
[[ 7  8  9 10]
 [13 14 15 16]]

print(arr[1:4:2, :]) # 取第2和第4行
#返回结果
[[ 6  7  8  9 10 11]
 [18 19 20 21 22 23]]

数组中还有一个神奇索引, 如果我要取第1和第3行, 就可以利用神奇索引来完成

print(arr[(1,3), :])  #使用数组的神奇索引可以直接指定要取的行, 但是需要用()或[]括住, 效果与arr[1:4:2, :]是相等的
# 返回结果
[[ 6  7  8  9 10 11]
 [18 19 20 21 22 23]]

但是如果行和列都是用了神奇索引, 那它最后取出的不是一个子矩阵, 而是坐标点.

print(arr[(1, 2), (3, 4)])  
# 返回结果
[ 9 16]

原因是它的执行顺序问题,这里arr[(1, 2), (3, 4)] 可以看为2个坐标(1, 3)和(2, 4)。首先根据(1, 3) 就是找到行索引为1,列索引3的值,也就是9; 然后根据 (3, 4)找到行索引为2,列索引为4的值, 也就是16。 因此最后得出的结果是(9, 16)
python学习笔记--Numpy模块(二)_第1张图片

修改数组中的值

沿用上面的数组继续使用

arr[:, 1] = 0   # 将第2列所有的值都改为0
print(arr)
#返回结果
[[ 0  0  2  3  4  5]
 [ 6  0  8  9 10 11]
 [12  0 14 15 16 17]
 [18  0 20 21 22 23]]

arr[:, (1,3)] = 1  # 将第2列和第4列的值都改为1
print(arr)
#返回结果
[[ 0  1  2  1  4  5]
 [ 6  1  8  1 10 11]
 [12  1 14  1 16 17]
 [18  1 20  1 22 23]]

在数组中,索引还可以使用比较运算,该方法被称为布尔索引

print(arr[arr<10])  # 筛选出小于10的值
# 返回结果
[0 1 2 1 4 5 6 1 8 1 1 1 1 1]

arr[arr<10] = 2  # 将小于10的值都改为2
print(arr)
# 返回结果
[[ 2  2  2  2  2  2]
 [ 2  2  2  2 10 11]
 [12  2 14  2 16 17]
 [18  2 20  2 22 23]]

将条件逻辑作为数组操作

numpy.where()函数是三元表达式 x if condition else y 的向量化版本。

  • np.where(condition, [x, y]) # 当满足条件,执行x,否则执行y
# <10的值变为0, 大于10变为10
print(np.where(arr<10, 0, 10))
# 返回结果
[[ 0  0  0  0  0  0]
 [ 0  0  0  0 10 10]
 [10  0 10  0 10 10]
 [10  0 10  0 10 10]]

# arr中<8的变为0, 其他的不变
print(np.where(arr<8, 0, arr))  # 传入arr本身就等同于值不变
# 返回结果
[[ 0  0  0  0  0  0]
 [ 0  0  0  0 10 11]
 [12  0 14  0 16 17]
 [18  0 20  0 22 23]]

# arr中小于5的都变为5, 大于10的都变为10, 两者都不满足的就不变
print(arr.clip(5, 15))  
# 返回结果
[[ 5  5  5  5  5  5]
 [ 5  5  5  5 10 11]
 [12  5 14  5 15 15]
 [15  5 15  5 15 15]]

基础数组常用方法

方法 描述
sum 沿着轴向计算所有元素的累和,0长度的数组,累和为0
mean 数学平均,0长度的数组平均值为NaN
max,min 最大值和最小值
argmax,argmin 最大值和最小值的位置
std,var 标准差和方差
ptp 极值
cumsum 从0开始元素累积和
median 中值

前置

先创建一个数组, 用于试验

import numpy as np

arr = np.arange(12).reshape(3, 4)
print(arr)

# 返回结果
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

sum

sum:沿着轴向计算所有元素的累和,0长度的数组,累和为0

arr.sum()
#或
np.sum(arr)  # 两个方式是相等的
# 返回结果
66

print(np.sum(arr, axis=0))  # 求行轴向的累加和
# 返回结果
[12 15 18 21]

print(np.sum(arr, axis=1))  # 求列轴向的累加和
#返回结果
[ 6 22 38]

mean

数学平均,0长度的数组平均值为NaN

print(np.mean(arr))  # 求平均值
# 返回结果

print(np.mean(arr, axis=0))  # 求行轴向的平均值
# 返回结果
[4. 5. 6. 7.]

print(np.mean(arr, axis=1))  # 求列轴向的平均值
# 返回结果
[1.5 5.5 9.5]

max,min

最大值和最小值

print(np.max(arr))  # 求最大值
# 返回结果
11

print(np.min(arr))  # 求最小值
# 返回结果
0

arr[0,0] = 50  # 将数组中第一个数改为50
print(arr)
print(np.max(arr, axis=0))  # 求行轴向的最大值
# 返回结果
[[50  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
 
[50  9 10 11]

argmax,argmin

最大值和最小值的位置
这里沿用上面的数组, 上面的数组中第一个数值为50, 索引位置是0

print(np.argmax(arr))  # 最大值的索引位置
# 返回结果
0

print(np.argmax(arr, axis=0))  # 以行轴方向找最大值的位置
# 返回结果, 结果中的0和2, 指的是每一列的最大值的索引位置, 如第1列最大值是50,因此索引为0; 第二列最大值为9, 因此索引为2, 以此类推.
[0 2 2 2]

std,var

标准差和方差

print(np.std(arr))  # 求标准差
# 返回结果
12.532180798071641

print(np.var(arr)) # 求方差
# 返回结果
157.05555555555557

ptp

极差

print(np.ptp(arr))  # 求极值
# 返回结果
49

print(np.ptp(arr, axis=0))
# 返回结果
[46  8  8  8]

cumsum

从0开始元素累积和
用回最初的数组: arr = np.arange(12).reshape(3, 4)

print(np.cumsum(arr))  # 相当于0+1+2+3+4+5...+N  每次相加都会输出一个结果,最后输出为一个一维数组
# 返回结果
[ 0  1  3  6 10 15 21 28 36 45 55 66]

median

中值

  • 注意, median是np的方法只能用np.median()调用, 不能使用arr.median()
print(np.median(arr))  # 求数组的中值
# 返回结果
5.5

print(np.median(arr, axis=0))  # 以行轴向求中值
# 返回结果
[4. 5. 6. 7.]

NaN与inf

NaN和inf的介绍

先创建一个数组

import numpy as np

arr = np.arange(16).reshape(4, 4)
print(arr)

# 返回结果
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]

用上面的数组除0

print(arr/0) 
# 返回结果
[[nan inf inf inf]
 [inf inf inf inf]
 [inf inf inf inf]
 [inf inf inf inf]]
  • NaN:not a number表示不是一个数字
  • inf:inf表示正无穷,-inf表示负无穷

再看看上面的返回结果, 0/0=NaN, 但是其余数值除0得到的是inf, 这是因为在这里0是相当于无穷小, 类似函数y=1/x,当x→0时,y→∞;反之亦然。

NaN的特性

NaN在numpy中属于float类型, 如果想要将数组的某个值改为NaN, 则需要将数组改为float类型; inf也是同理。

arr1 = arr.astype("float")  # 改变数组类型为float
arr1[1,2] = np.nan  # 将索引坐标为(1,2)的值改为NaN
print(arr1)
# 返回结果
[[ 0.  1.  2.  3.]
 [ 4.  5. nan  7.]
 [ 8.  9. 10. 11.]
 [12. 13. 14. 15.]]

NaN有个特性,两个NaN之间是不相等的

np.nan == np.nan
# 返回结果
False

基于此特性, 可以通过比较数组自身判断一个数组中NaN的个数

print(arr1 != arr1)  # 将数组与自身比较, 如果遇到NaN就会返回True
# 返回结果
[[False False False False]
 [False False  True False]
 [False False False False]
 [False False False False]]

在上面的返回结果中,只有NaN显示为True,然后在Python中,True==1,False==0,因此可以通过np.count_nonzero()方法, 它可以计算出数组中非0的个数,

print(np.count_nonzero(arr1!=arr1))
# 返回结果
1

不过这里其实有个更直白的,在Numpy中有个np.isnan()方法, 它就是用来判断数组中的元素是否是NaN

print(np.isnan(arr1)  # 判断数组中的元素是否是NaN
# 返回结果
[[False False False False]
 [False False  True False]
 [False False False False]
 [False False False False]]

# 然后配合使用np.count_nonzero()即可统计
np.count_nonzero(np.isnan(arr1))  # 统计NaN个数
# 返回结果
1

另外,NaN与任何数相加都是NaN

np.nan + 1
# 返回结果
nan

NaN的处理

在Numpy中,为了避免处理后NaN的值会对整体的数值有较大的影响,通常我们会将其替换成中值或者均值即可。

# 读取每一列
for i in range(arr1.shape[1]):  # 获取数组的形状,得到列数
    # 取出每一列
    arr_col = arr1[:, i]
    # 获取每列的nan的个数
    nan_num = np.count_nonzero(np.isnan(arr_col))
    
    # 判断nan个数为0的, 不作处理; 取出不为0的
    if nan_num != 0:
        # 取出不是nan的值, 求其平均值
        not_nan_col = arr_col[arr_col == arr_col]
        # 计算平均值
        col_mean = np.mean(not_nan_col)
        # 给NaN复制
        arr_col[arr_col != arr_col] = col_mean
        print(arr1)

# 返回结果
[[ 0.          1.          2.          3.        ]
 [ 4.          5.          8.66666667  7.        ]
 [ 8.          9.         10.         11.        ]
 [12.         13.         14.         15.        ]]

Numpy读取本地文件

Numpy提供了np.loadtxt(fname) 方法, 可以读取本地文件,其参数如下:

  • fname 文件路径
  • dtype 数据类型
  • delimiter 分隔符
  • skiprows 跳过行
  • comment 如果行的开头为 # 就会跳过该行
  • usecols 是指使用(0,2)两列
  • unpack 每一列当成一个向量输出,而不是合并在一起
  • converters 对数据预处理。比如{0:func}第0列进行func函数预处理
"""获取文件中的最高价和最低价"""
import numpy as np

HighPrice, LowPrice = np.loadtxt("AAPL.csv", delimiter=",", usecols=(0, 1), unpack=True)

print(HighPrice)  # 高高价列
print(LowPrice)  # 最低价列

print(f"max={np.max(HighPrice)}")  # 两年内最高价
print(f"min={np.min(LowPrice)}")  # 两年内最低价
"""计算周一~周五的平均价格"""
# 由于文件中有日期, 无法转换为float类型, 因此需要用到converts参数, 创建一个函数并对数据进行预处理
import datetime
def datenum(s):
	"""
	创建函数, 将'%Y-%m-%d'格式的日期转换为周的天数,
	但返回的数字是从0开始的, 因此0=>周一, 1=>周二
	""""
    return datetime.datetime.strptime(s, "%Y-%m-%d").weekday()

# print(datenum("2020-05-15"))  # 返回结果:4, 对应就是周五

# 读取文件
date, closePrice  = np.loadtxt("AAPL02.csv", delimiter=",", usecols=(0, -1), unpack=True, converters={0: datenum})
# print(date)  # 打印周天数
# print(closePrice) # 打印价格

# 分组显示并且求平均值
for i in range(5):
    print(closePrice[date==i].mean())

你可能感兴趣的:(Numpy,Python学习日记,数据分析)