NumPy(Numerical Python的简称):
是Python数值计算最重要的基础包。大多数提供科学计算的包都是用NumPy的数组作为构建基础。
学习链接:
1. 数据分析入门书籍的笔记: 《利用Python进行数据分析·第2版》.
2. Numpy中文网(非官网): numpy. 非常全, 值得收藏!!!
3. Numpy英文网: numpy.
目录
1 思维导图-Numpy
在学习《利用Python进行数据分析·第2版》这本书籍过程中,有许多知识点需要我们编程实战,所以本人在学习编程过程中结合自己的学习情况,整理了这本书《第4章 NumPy基础:数组和矢量计算》的思维导图,提供给大家一起学习。
ps:每当有新的关于numpy的技巧知识点,我都会加到思维导图中。
2 Numpy基础
在实战编写过程中,我觉得以下知识点对以后进行数据处理与分析很重要,结合自己的写的程序进行一 一分析。
2.1 Ndarray&Dataframe转换
很多时候大家都会忽略这个板块,其实在numpy与list、dataframe之间的转换运用的很多,如果处理不好会很大程度上耽误大家编写程序的效率。
1 :Ndarray转换成Dataframe
# Ndarray转换成Dataframe
mat = np.random.randn(4,4)
df = pd.DataFrame(mat)
df.columns = ['a', 'b', 'c', 'd'] # 修改DataFrame的列名
结果:
a b c d
0 0.080014 -2.550228 0.058949 -0.339278
1 -0.830083 0.425779 1.243784 -0.130639
2 -1.397484 -0.188971 -1.213122 1.042182
3 1.948449 -0.689353 -0.730035 -0.108117
2 :Dataframe转换成Ndarray
将Dataframe转换成Ndarray时,最常见用np.array()、df.values、df.as_matrix()方法。
# Dataframe转换成Ndarray
df = pd.DataFrame(
{'A':[1,2,3],
'B':[4,5,6],
'C':[7,8,9]})
data_1 = df.values
data_2 = df.as_matrix()
data_3 = np.array(df)
结果:
[[1 4 7]
[2 5 8]
[3 6 9]]
返回的data_1、data_2、data_3数据类型都为:<class ‘numpy.ndarray’>
2.2 数组的索引和切片
下图为:二维数组的索引方式(轴0作为行,轴1作为列)。
1 :索引单个元素:
获取下列中ndarray数据结构类型的arr中的数字3有两种方法:arr[0][2]、arr[0, 2]。
arr = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
data_1 = arr[0][2] # 选取单个元素
data_2 = arr[0, 2] # 选取单个元素
1 :索引切片:
获取上图中的蓝色方块的值:
arr = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
data_1 = arr[:2, 1:]
data_2 = arr[2, :]
data_3 = arr[:, :2]
data_4 = arr[1, :2]
值得注意的是有两点:
1:“a:” 包括a切片的索引。
2:":a" 表示不包括a切片的索引,从起点0开始,到a切片前结束。
3:“m:n” 表示从切片m开始,到切片n-1结束。
2.3 数组重塑
在编程实战中,数组重塑常见的方法有:
1:reshape( )函数
2:shape、直接改变数组形状。
1:使用reshape( )函数:
arr = np.array([
[1, 2, 3, 4],
[4, 5, 6, 7],
[7, 8, 9, 10]])
arr_1 = arr.reshape(-1, 1) # 重塑一列
arr_2 = arr.reshape(1, -1) # 重塑一行
arr_3 = arr.reshape(2, 6) # 重塑一行
作为参数的形状的其中的一维可以是-1,它表示该维度的大小由数据本身推断而成。例如:arr.reshape(-1, 1)表示重塑成一列,行索引由数据本身推断而成。
程序结果:
[[ 1]
[ 2]
[ 3]
[ 4]
[ 4]
[ 5]
[ 6]
[ 7]
[ 7]
[ 8]
[ 9]
[10]]
[[ 1 2 3 4 4 5 6 7 7 8 9 10]]
[[ 1 2 3 4 4 5]
[ 6 7 7 8 9 10]]
2:使用shape、直接改变数组形状:
直接修改shape属性值为:(4, 3)
arr = np.array([
[1, 2, 3, 4],
[4, 5, 6, 7],
[7, 8, 9, 10]])
arr.shape = (4, 3) # 重塑成4行,3列
结果:
[[ 1 2 3]
[ 4 4 5]
[ 6 7 7]
[ 8 9 10]]
同时,也可以使用-1,某个轴的值是-1时,会自动计算这个轴的长度。
arr = np.array([
[1, 2, 3, 4],
[4, 5, 6, 7],
[7, 8, 9, 10]])
arr.shape = (2, -1) # 重塑成2行
结果:
[[ 1 2 3 4 4 5]
[ 6 7 7 8 9 10]]
值得注意的是使用reshape( )函数进行数组重塑是产生一个新的数组,而使用shape是在原数组上操作,也就是改变的是原数组。
2.4 数组的拆分与合并
1 数组的拆分:
arr = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
arr_1 = np.split(arr, 2, axis=1) # 纵向分2部分
arr_2 = np.split(arr, 3, axis=0) # 横向分3部分
arr_3 = np.array_split(arr, 2, axis=1) # 纵向分3部分
arr_4 = np.vsplit(arr, 3) # 横着分3组
arr_5 = np.hsplit(arr,2) # 竖着分2组
结果:
print(arr_1)
print(arr_1[0]) # 获取拆分后的第一组(共两组)
'''结果:'''
[array([[ 1, 2],
[ 5, 6],
[ 9, 10]]), array([[ 3, 4],
[ 7, 8],
[11, 12]])]
[[ 1 2]
[ 5 6]
[ 9 10]]
2 数组的合并:
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
a1 = np.vstack((arr1, arr2))
a2 = np.hstack((arr1, arr2))
结果:
[[1 2 3]
[4 5 6]]
[1 2 3 4 5 6]
numpy提供许多数组合并的方法,这里还有一种常用的合并的方法,即concatenate方法。
arr1 = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8]])
arr2 = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8]])
b1 = np.concatenate((arr1, arr2), axis=0) #在纵轴上合并
b2 = np.concatenate((arr1, arr2), axis=1) #在纵轴上合并
结果:
[[1 2 3 4]
[5 6 7 8]
[1 2 3 4]
[5 6 7 8]]
[[1 2 3 4 1 2 3 4]
[5 6 7 8 5 6 7 8]]
2.5 数组的统计方法
可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。sum、mean以及标准差std等聚合计算(aggregation,通常叫做约简(reduction))既可以当做数组的实例方法调用,也可以当做顶级NumPy函数使用。
1 测试:
a = np.arange(9).reshape((3, 3))
print(a)
r1 = np.amin(a, axis=0) # 每列轴最小值
r2 = np.amin(a, axis=1) # 每行轴最小值
r3 = np.amax(a, axis=0) # 每列轴最大值
r4 = np.amax(a, axis=1) # 每列轴最大值
1 结果:
[[0 1 2]
[3 4 5]
[6 7 8]]
[0 1 2]
[0 3 6]
[6 7 8]
[2 5 8]
2 测试:
r1 = np.median(a, axis=0) # 沿列轴计算中值
r2 = np.median(a, axis=1) # 沿行轴计算中值
r3 = np.mean(a, axis=0) # 沿列轴计算平均值
r4 = np.mean(a, axis=1) # 沿行轴计算平均值
2 结果:
[3. 4. 5.]
[1. 4. 7.]
[3. 4. 5.]
[1. 4. 7.]
3 测试:
r1 = np.std(a, axis=0) # 沿列轴计算标准差
r2 = np.std(a, axis=1) # 沿行轴计算标准差
3 结果:
[2.44948974 2.44948974 2.44948974]
[0.81649658 0.81649658 0.81649658]
4 测试:
r1 = np.var(a, axis=0) # 沿列轴计算方差
r2 = np.var(a, axis=1) # 沿行轴计算方差
4 结果:
[6. 6. 6.]
[0.66666667 0.66666667 0.66666667]
5 测试:
arr1 = [[1, 2, 3], [4, 5, 6]]
arr2 = [[10, 20, 70], [50, 20, 10]]
arr1 = np.array(arr1)
arr2 = np.array(arr2)
correlation = np.corrcoef(arr1, arr2)
5 结果:
相关系数矩阵=
[[ 1. 1. 0.93325653 -0.96076892]
[ 1. 1. 0.93325653 -0.96076892]
[ 0.93325653 0.93325653 1. -0.79701677]
[-0.96076892 -0.96076892 -0.79701677 1. ]]
6 测试:
correlation = np.cov(arr1, arr2)
6 结果:
协方差矩阵相关系数=
[[ 1.00000000e+00 1.00000000e+00 3.00000000e+01 -2.00000000e+01]
[ 1.00000000e+00 1.00000000e+00 3.00000000e+01 -2.00000000e+01]
[ 3.00000000e+01 3.00000000e+01 1.03333333e+03 -5.33333333e+02]
[-2.00000000e+01 -2.00000000e+01 -5.33333333e+02 4.33333333e+02]]
2.6 排序
1 使用sort():
跟Python内置的列表类型一样,NumPy数组也可以通过sort方法就地排序,多维数组可以在任何一个轴向上进行排序,只需将轴编号传给sort即可。
list1 = [[4,3,2],
[2,1,4]]
array=np.array(list1)
array.sort(axis=1) # axis=1,说明是按照行进行排序,也就是说,每一行上的元素实现了递增
array.sort(axis=0) # axis=0,说明是按照列进行排序,也就是说,每一列上的元素实现了递增
结果:
[[2 3 4]
[1 2 4]]
[[2 1 2]
[4 3 4]]
2 使用lexsort():
也可以使用numpy.lexsort() 用于对多个序列进行排序。把它想象成对电子表格进行排序,每一列代表一个序列,排序时优先照顾靠后的列。
a = [1, 5, 1, 4, 3, 4, 4]
b = [9, 4, 0, 4, 0, 2, 1]
data = np.lexsort((b, a)) # b在前,a在后,即是先按照a的元素进行比较,在不确定结果后按b进行比较。
开始时,a中的最小值为两个1,其索引分别为0,2,再比较b中相应索引上的值,即9,0。
对应的最小应是:1,0,而其在a中的索引为2,所以排序后返回的结果第一个值为索引2
下一个最小应是:1,9,而其在a中的索引为0,所以排序后返回的结果第一个值为索引0
结果:
[2 0 4 6 5 3 1]
ps:
1:除了上面还有其他排序函数:argsort、partition、sorted
2:在pandas中还可以找到一些其他跟排序有关的数据操作(比如根据一列或多列对表格型数据进行排序
3 案例实战1-numpy
测试使用numpy的ndarray,描述比python的list优势。
import numpy as np
from time import *
my_arr = np.arange(1000000) # 用numpy定义数组
my_list = list(range(1000000)) # 用list定义列表
begin_time = time()
for _ in range(10): # 用numpy定义的数组执行元素相乘2(重复10遍)
my_arr2 = my_arr * 2
end_time =time()
run_time = end_time - begin_time
print('Numpy运行时间:%f'%run_time)
begin_time = time()
for _ in range(10): # 用list定义的列表执行元素相乘2(重复10遍)
my_list = [x * 2 for x in my_list]
end_time =time()
run_time = end_time - begin_time
print('list运行时间:%f'%run_time)
结果:
Numpy运行时间:0.073958
list运行时间:2.821386
从结果可以看出,进行同样的运算,运用Numpy的array数组可以大大提高运算效率,节约程序运算时间。
4 案例实战2-numpy
实现数独:
先拿【3*3】的数独下🔪
链接: 数独怎么玩.
实现过程:
# -*- coding: utf-8 -*-
# @Time : 2020/3/30 18:10
# @Author : Zudy
'''
1.数独游戏[3*3]
输入残缺的矩阵【3*3】并进行补全。
'''
import numpy as np
class Gongge_9(object):
def __init__(self, data):
self.data = data
def read_counts(self):
data = self.data
for i in range(np.shape(data)[0]):
self.__row(data[i, :])
self.__col(data[:, i])
return data
# 行判断
def __row(self, data):
data_np = data
t = np.sum(data_np == 0) # 判断数组中为0的个数
if t == 0:
pass
elif t == 1:
data_ = np.where(data_np == 0) # data_(0,2)
# print(data_)
if 1 in data_np and 2 in data_np:
value = 3
elif 1 in data_np and 3 in data_np:
value = 2
else:
value = 1
data[data_[0]] = value
else:
pass
# 列判断
def __col(self, data):
data_np = data
t = np.sum(data_np == 0) # 判断数组中为0的个数
if t == 0:
pass
elif t == 1:
data_ = np.where(data_np == 0) # data_(0,2)
# print(data_)
if 1 in data_np and 2 in data_np:
value = 3
elif 1 in data_np and 3 in data_np:
value = 2
else:
value = 1
data[data_[0]] = value
else:
pass
if __name__ == '__main__':
print('空格按0输入,且每个数以‘,’号空开')
in_count = list(eval((input('请输入要读取得列表:')))) #获取9宫格
# in_count = [1,2,0,0,0,2,2,0,0]
in_data = np.array(in_count).reshape(3, 3) # 转化成3*3的矩阵
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('你输入的9宫格为:')
print(in_data)
#定义一个对象
data_test = Gongge_9(in_data)
data_ = data_test.read_counts()
print('填补完数字后的9宫格为:')
print(data_)
测试结果:
空格按0输入,且每个数以‘,’号空开
请输入要读取得列表:1,2,0,0,0,2,2,0,0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
你输入的9宫格为:
[[1 2 0]
[0 0 2]
[2 0 0]]
填补完数字后的9宫格为:
[[1 2 3]
[3 1 2]
[2 3 1]]
5 案例实战3-numpy
实现[9*9]数读
具体算法步骤可以查看:
链接: 用Matlab实现[9*9]数读.
这里直接上Python代码:
# -*- coding: utf-8 -*-
# @Time : 2020/4/6 22:35
# @Author : Zudy
'''
《暴力数独》
定义:任意输入一个【9*9】的残缺矩阵,
横、竖以及每个[3*3]的小方块都是
[1,2,3,4,5,6,7,8,9]中的数据任意排列。
使每行和每列,和【3*3】数字不重复。
'''
import numpy as np
import math
class ViolenceNumbers():
def __init__(self, data):
self.data = data
self.__text(num = 1)
self.__print_data()
def __text(self, num):
r_c = np.shape(self.data)
row = r_c[0]
col = r_c[1]
y = math.ceil(num / row) # 获取坐标 y
x = num - (y - 1)*row # 获取坐标 x
if num > row * col:
return self.data
else:
if self.data[x - 1][y - 1] != 0:
self.__text(num + 1)
else:
for a in range(1, 10):
# 从1-9中选取数字填补到0的值
judge = self.__row_test(x-1, y-1, a) * \
self.__line_test(x-1, y-1, a) * \
self.__house_test(x-1, y-1, a, num) # 判断是否全部为零
if judge == 1:
self.data[x - 1][y - 1] = a
self.__text(num + 1)
else:
pass
def __row_test(self, x, y, a):
# 模块判断一:每行
if a in self.data[x, :]:
out_put = 0
else:
out_put = 1
return out_put
def __line_test(self, x, y, a):
# 模块判断二:每列
if a in self.data[:, y]:
out_put = 0
else:
out_put = 1
return out_put
def __house_test(self, x, y, a, num):
# 模块判断三:每宫
data_ = self.__judge(num)
if a in data_:
out_put = 0
else:
out_put = 1
return out_put
def __judge(self, num):
# 返回【3*3】每宫的矩阵
if (num % 9) in [1, 2, 3] and (num // 9 + 1) in [1, 2, 3]:
data_ = self.data[0:3, 0:3]
elif (num % 9) in [4, 5, 6] and (num // 9 + 1) in [1, 2, 3]:
data_ = self.data[3:6, 0:3]
elif (num % 9) in [7, 8, 9] and (num // 9 + 1) in [1, 2, 3] or num in [9, 18, 27]:
data_ = self.data[6:9, 0:3]
elif (num % 9) in [1, 2, 3] and (num // 9 + 1) in [4, 5, 6]:
data_ = self.data[0:3, 3:6]
elif (num % 9) in [4, 5, 6] and (num // 9 + 1) in [4, 5, 6]:
data_ = self.data[3:6, 3:6]
elif (num % 9) in [7, 8, 9] and (num // 9 + 1) in [4, 5, 6] or num in [36, 45, 54]:
data_ = self.data[6:9, 3:6]
elif (num % 9) in [1, 2, 3] and (num // 9 + 1) in [7, 8, 9]:
data_ = self.data[0:3, 6:9]
elif (num % 9) in [4, 5, 6] and (num // 9 + 1) in [7, 8, 9]:
data_ = self.data[3:6, 6:9]
elif (num % 9) in [7, 8, 9] and (num // 9 + 1) in [7, 8, 9] or num in [63, 72, 81]:
data_ = self.data[6:9, 6:9]
return data_
def __print_data(self):
print('填补完后:')
print(self.data)
if __name__ == '__main__':
data = [[0, 0, 3, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 4, 0, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 5, 0],
[0, 0, 7, 0, 3, 6, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 4, 2],
[2, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 7, 0, 9, 0, 0],
[5, 8, 0, 0, 1, 0, 0, 0, 0]]
data_np = np.array(data)
print('原始数据:')
print(data_np)
ViolenceNumbers(data_np)