1. 使用numpy快速处理数据

numpy简介

NumPy是 SciPy、Pandas 等数据科学的基础库。它所提供的数据结构比 Python 自身的“更高级、更高效”,可以这么说,NumPy 所提供的数据结构是 Python 数据分析的基础。

numpy处理数据的优势

Python 数组结构中的列表 list,它实际上相当于一个数组的结构。而NumPy 中一个关键数据类型就是关于数组的,那为什么还存在这样一个第三方的数组结构呢?
在标准的 Python 中,用列表 list 保存数组的数值。由于列表中的元素可以是任意的对象,所以列表中 list 保存的是**对象的指针**。虽然在 Python 编程中隐去了指针的概念,但是数组有指针,Python 的列表 list 其实就是数组。这样如果我要保存一个简单的数组[0,1,2],就需要有 3 个指针和 3 个整数的对象,这样对于 Python 来说是非常不经济的,
浪费了内存和计算时间。

为什么要用 NumPy 数组结构而不是 Python 本身的列表 list?这是因为列表 list 的元素在
系统内存中是**分散存储**的,而 NumPy 数组存储在一个**均匀连续的内存块**中。这样数组计算遍历所有的元素,不像列表 list 还需要对内存地址进行查找,从而节省了计算资源。另外在内存访问模式中,缓存会直接把字节块从 RAM 加载到 CPU 寄存器中。因为数据连续的存储在内存中,NumPy 直接利用现代 CPU 的矢量化指令计算,加载寄存器中的多个连续浮点数。另外 NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算
资源,大大提升了计算效率。

当然除了使用 NumPy 外,你还需要一些技巧来提升内存和提高计算资源的利用率。一个
重要的规则就是:**避免采用隐式拷贝,而是采用就地操作**的方式。举个例子,如果我想让一
个数值 x 是原来的两倍,可以直接写成 x*=2,而不要写成 y=x*2。
这样速度能快到 2 倍甚至更多。

在 NumPy 里有两个重要的对象:
ndarray(N-dimensional array object)解决了多维数组问题,而 ufunc(universal
function object)则是解决对数组进行处理的函数。

ndarry对象

创建数组

import numpy as np

# 创建一个一维数组
arr1d = np.array([1, 2, 3, 4, 5])

# 创建了一个两行三列的二维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6]])

# 创建了一个包含3行3列的二维数组,其中所有元素都是0。
zeros = np.zeros((3, 3))

# 创建了一个包含2行2列的二维数组,其中所有元素都是1
ones = np.ones((2, 2))

# 创建了一个包含3行3列的二维数组,其中的元素是从0到1之间的随机数。
random = np.random.rand(3, 3)

# 输出展示
print(arr1d)
print("=====================================")
print(arr2d)
print("=====================================")
print(zeros)
print("=====================================")
print(ones)
print("=====================================")
print(random)

# 结果如下
[1 2 3 4 5]
=====================================
[[1 2 3]
 [4 5 6]]
=====================================
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
=====================================
[[1. 1.]
 [1. 1.]]
=====================================
[[0.31500279 0.4626591  0.54188889]
 [0.14735868 0.91149474 0.29843077]
 [0.6449905  0.16356251 0.78886381]]

展示结果为浮点数?

在展示结果中,0后面的点表示这些数字是浮点数,而不是整数。NumPy中的默认数据类型是浮点数。因此,当创建全为0的数组时,默认会使用浮点数类型。浮点数可以表示小数和大数,而整数只能表示整数值。

如果想要创建一个全为整数的数组,可以指定数据类型为整数类型。例如,可以使用np.zeros((3, 3), dtype=int)来创建一个全为整数0的数组。同样地,对于全为1的数组,可以使用np.ones((2, 2), dtype=int)来指定整数数据类型。这样创建的数组将不再显示小数点。

.shape

shape_arr1d = arr1d.shape
print(shape_arr1d)
# 结果如下
(5,)

.shape 方法来获取 arr1d 数组的形状信息,(5,)表示这是一个长度为 5 的一维数组。

.shape 方法在获取数组的形状信息时非常有用,特别是当处理多维数组时。它可以告诉您数组在每个维度上的大小,从而帮助您理解和操作数组的结构和维度。

.dtype

.dtype 方法用于获取 NumPy 数组的数据类型(data type)。

在 NumPy 中,数组是由相同类型的元素组成的。这个数据类型可以是整数、浮点数、布尔值、字符串等。.dtype 方法返回数组中元素的数据类型。

dtype_arr2d = arr2d.dtype
print(dtype_arr2d)
# 结果如下
int32

在创建 arr2d 数组时,数组中的元素都是整数,且整数的默认数据类型是 int32(32位整数)。

更新数组内数据

更新 NumPy 数组的数据,可以使用索引来访问特定位置的元素,并将其赋值为新的值。示例代码如下:

arr = np.array([1, 2, 3, 4, 5])
arr[2] = 10
print(arr)

上述代码将数组 arr 中索引为 2 的元素(第三个元素)的值更新为 10
执行上述代码后,输出结果为:

[ 1  2 10  4  5]

结构化数组

如果你想统计一个班级里面学生的姓名、年龄,以及语文、英语、数学成绩该怎么办?当然
你可以用数组的下标来代表不同的字段,比如下标为 0 的是姓名、下标为 1 的是年龄等,
但是这样不显性。
实际上在 C 语言里,可以定义结构数组,也就是通过 struct 定义结构类型,结构中的字段
占据连续的内存空间,每个结构体占用的内存大小都相同,那在 NumPy 中是怎样操作的
呢?

# coding=utf-8

import numpy as np

# 定义结构化数据类型
dt = np.dtype({
    'names': ['name', 'age', 'chinese', 'math', 'english'],
    'formats': ['S32', 'i', 'i', 'i', 'f']})

# 创建结构化数组
students = np.array([("ZhangFei",32,75,100, 90),("GuanYu",24,85,96,88.5),
 ("ZhaoYun",28,85,92,96.5),("HuangZhong",29,65,85,100)],
 dtype=dt)

print("============================")
ages = students[:]['age']
chineses = students[:]['chinese']
maths = students[:]['math']
englishs = students[:]['english']
print("ages:", ages)
print("chineses:", chineses)
print("maths:", maths)
print("englishs:", englishs)

使用字典来定义结构化数据类型 dt。字典中包含两个键:‘names’ 和 ‘formats’。‘names’ 键对应一个列表,其中包含了字段的名称,按顺序指定为 [‘name’, ‘age’, ‘chinese’, ‘math’, ‘english’]。‘formats’ 键对应一个列表,其中包含了字段的数据类型,按顺序指定为 [‘S32’, ‘i’, ‘i’, ‘i’, ‘f’]。

‘S32’ 表示字段使用 32 个字节的字符串数据类型。
‘i’ 表示字段使用整数数据类型。
‘f’ 表示字段使用浮点数数据类型。
然后,我们使用这个定义好的结构化数据类型 dt 来创建了一个结构化数组 students,数组中的每个元素是一个包含不同字段值的元组。
通过切片
操作 students[:][‘age’] 获取了结构化数组 students 中所有学生的年龄字段。students[:] 表示选择所有的行,而 [‘age’] 表示选择指定字段 ‘age’。将结果赋值给变量 ages

运行结果如下:

============================
ages: [32 24 28 29]
chineses: [75 85 85 65]
maths: [100  96  92  85]
englishs: [ 90.   88.5  96.5 100. ]
添加数据到结构化数组

首先创建一个新的结构化数组 new_student,其中包含了要添加的学生的姓名、年龄和成绩等信息。然后,使用 np.append 将新的学生数据添加到 students 数组中。

new_student = np.array(('David', 22, 91, 89, 87.0), dtype=dt)
students = np.append(students, new_student)

运行结果如下:

new_student = np.array(('David', 22, 91, 89, 87.0), dtype=dt)
students = np.append(students, new_student)
print(students)

.mean 计算平均值

print("平均年龄:", np.mean(ages))

运行结果如下:

平均年龄: 28.25

ufunc 运算

ufunc 是 universal function 的缩写,它能对数组中每个元素进行函数操作。NumPy 中很多 ufunc 函数计算速度非常快,因为都是采用 C 语言实现的。

常用ufunc函数汇总
np.add(): 逐元素地将两个数组相加。
np.subtract(): 逐元素地将一个数组减去另一个数组。
np.multiply(): 逐元素地将两个数组相乘。
np.divide(): 逐元素地将一个数组除以另一个数组。
np.power(): 对数组中的每个元素进行幂运算。
np.sqrt(): 对数组中的每个元素进行平方根运算。
np.exp(): 对数组中的每个元素进行指数运算。
np.log(): 对数组中的每个元素取自然对数。
np.sin(): 对数组中的每个元素进行正弦运算。
np.cos(): 对数组中的每个元素进行余弦运算。
np.tan(): 对数组中的每个元素进行正切运算。
np.maximum(): 逐元素地比较两个数组,并返回对应位置上较大的值。
np.minimum(): 逐元素地比较两个数组,并返回对应位置上较小的值。
np.absolute(): 对数组中的每个元素取绝对值。
np.sum(): 计算数组中所有元素的和。
np.mean(): 计算数组中所有元素的平均值。
np.median(): 计算数组中所有元素的中位数。
np.std(): 计算数组中所有元素的标准差。
np.sort(): 对数组进行排序。
np.unique(): 返回数组中的唯一值。

连续数组的创建

NumPy 可以很方便地创建连续数组,比如我使用 arange 或 linspace 函数进行创建:

x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)

以上是创建等差数组的两种方式。但是两种创建的方式是不同的。
arange() 类似内置函数 range(),通过指定初始值、终值、步长来创建等差数列的一维数
组,默认是不包括终值的。
linspace 是 linear space 的缩写,代表线性等分向量的含义。linspace() 通过指定初始
值、终值、元素个数来创建等差数列的一维数组,默认是包括终值的。
运行结果如下:

[1 3 5 7 9]
[1. 3. 5. 7. 9.]

np.arange() 方法创建的数组默认的数据类型是整数类型(int),而 np.linspace() 方法创建的数组默认的数据类型是浮点数类型(float)。

*当使用 np.arange() 创建数组时,可以通过指定 dtype 参数来显式指定数据类型。例如,可以使用 np.arange(1, 10, 2, dtype=float) 来创建一个浮点数类型的数组。
同样地,当使用 np.linspace() 创建数组时,默认情况下会生成浮点数类型的数组。如果需要创建整数类型的数组,可以通过指定 dtype 参数为整数类型。例如,可以使用 np.linspace(1, 9, 5, dtype=int) 来创建一个整数类型的数组。
因此,总结起来,np.arange() 方法创建的数组默认为整数类型,np.linspace() 方法创建的数组默认为浮点数类型。

两种方法都可以通过指定 dtype 参数来显式设置所需的数据类型。

统计函数

如果你需要了解一批数据的特性,则可以最大值、最小值、平均值,是否符合正态分布,方差、标准差等数学特性来认识这组数据。

.amax()

np.amax(): 该函数用于计算数组中的最大值。它接受以下参数:
array: 要计算最大值的数组。
axis (可选): 沿指定轴计算最大值。如果未提供此参数,则计算整个数组的最大值。
keepdims (可选): 指定是否保持结果的维度。默认为 False,结果是一个降维的数组。

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

# 计算整个数组的最大值
max_value = np.amax(arr)
print(max_value)

# 沿行的方向计算最大值
max_row = np.amax(arr, axis=1)
print(max_row)

# 沿列的方向计算最大值,并保持结果的维度
max_column = np.amax(arr, axis=0, keepdims=True)
print(max_column)

结果如下:

6
[3 6]
[[4 5 6]]

当 keepdims=True 时,函数的返回结果将保持与原始数组相同的维度,其中被求取的轴将保留为长度为 1 的维度。
如果我们将 keepdims=False 或省略 keepdims 参数,默认为 False,则结果将是一个一维数组,即使在计算的轴上也没有保留维度。

.amin()

.amin() 函数与.amax()函数使用方法类似。

.ptp() 统计最大值与最小值之差
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.ptp(a))
print(np.ptp(a, axis=0)) # 沿着列计算最大值与最小值的差值
print(np.ptp(a, axis=1)) # 沿着行计算最大值与最小值的差值
print(np.ptp(a, axis=1, keepdims=True)) # 沿着行计算最大值与最小值的差值,并保持结果的维度

结果如下:

8
[6 6 6]
[2 2 2]
[[2]
 [2]
 [2]]
.percentile() 统计数组的百分位数 p
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.percentile(a, 50))
print(np.percentile(a, 50, axis=0))
print(np.percentile(a, 50, axis=1))
print(np.percentile(a, 50, axis=1, keepdims=True))
统计数组中的中位数 median()、平均数 mean()

使用方法与其他统计函数类似。

统计数组中的加权平均值 average()

numpy.average(a, axis=None, weights=None, returned=False)
参数说明:

a:要计算加权平均值的数组。
axis(可选):指定沿着哪个轴计算加权平均值,默认为 None,表示对整个数组进行计算。
weights(可选):用于指定每个元素的权重,可以是与输入数组 a 形状相同的数组或标量。
returned(可选):若为 True,则返回一个元组,其中第一个元素为加权平均值,第二个元素为权重之和。
arr = np.array([1, 2, 3, 4, 5])
weights = np.array([0.1, 0.2, 0.3, 0.2, 0.1])

weighted_average = np.average(arr, weights=weights)
print(weighted_average)

输出结果为:

2.9
统计数组中的标准差 std()、方差 var()
arr = np.array([1, 2, 3, 4, 5])

std_value = np.std(arr)
print(std_value)
var_value = np.var(arr)
print(var_value)

输出结果为:

1.4142135623730951
2.0

NumPy 排序

sort(a, axis=-1, kind=‘quicksort’, order=None)

NumPy 排序函数提供了不同的排序类型,用于指定排序的方式。

默认排序(kind='quicksort')
快速排序(kind='quicksort')
归并排序(kind='mergesort')
堆排序(kind='heapsort')
插入排序(kind='insertion')
选择排序(kind='selection')
希尔排序(kind='shell')

在 NumPy 的排序函数中,可以通过 kind 参数来指定排序类型。默认情况下,kind=‘quicksort’。

总结

在这里插入图片描述

关键词

ndarray对象,.shape数组的形状,.dtype数组数据类型,统计函数,结构化数组,指定类型排序

练习题:统计全班的成绩

假设一个团队里有 5 名学员,成绩如下表所示。你可以用 NumPy 统计下这些人在语文、
英语、数学中的平均成绩、最小成绩、最大成绩、方差、标准差。然后把这些人的总成绩排
序,得出名次进行成绩输出。
在这里插入图片描述
答案如下:

# coding=utf-8

'''
使用结构化数组方式建立数据类型
插入数据
计算数据
'''

import numpy as np

dt = np.dtype({
    'names': ['name', 'chinese', 'math', 'english'],
    'formats': ['S32', 'f', 'f', 'f']})
# 张飞 66 65 30
# 关羽 95 85 98
# 赵云 93 92 96
# 黄忠 90 88 77
# 典韦 80 90 90

students = np.array([('ZhangFei', 66, 65, 30), ('GuanYu', 95, 85, 98),
                     ('ZhaoYun', 93, 92, 96), ('HuangZhong', 90, 88, 77),
                     ('DianWei', 80, 90, 90)], dtype=dt)
print(students)

print("============================")
# 平均成绩
chinese_avg = np.mean(students[:]['chinese'])
math_avg = np.mean(students[:]['math'])
english_avg = np.mean(students[:]['english'])
print("语文平均成绩:", chinese_avg)
print("数学平均成绩:", math_avg)
print("英语平均成绩:", english_avg)

print("============================")
# 最小成绩与最大成绩
chinese_min,chinese_max = np.min(students[:]['chinese']),np.max(students[:]['chinese'])
math_min,math_max = np.min(students[:]['math']),np.max(students[:]['math'])
english_min,english_max = np.min(students[:]['english']),np.max(students[:]['english'])
print("语文最低分:", chinese_min, "语文最高分:", chinese_max)
print("数学最低分:", math_min, "数学最高分:", math_max)
print("英语最低分:", english_min, "英语最高分:", english_max)

print("============================")
# 方差
chinese_var = np.var(students[:]['chinese'])
math_var = np.var(students[:]['math'])
english_var = np.var(students[:]['english'])
print("语文方差:", chinese_var)
print("数学方差:", math_var)
print("英语方差:", english_var)

print("============================")
# 标准差
chinese_std = np.std(students[:]['chinese'])
math_std = np.std(students[:]['math'])
english_std = np.std(students[:]['english'])
print("语文标准差:", chinese_std)
print("数学标准差:", math_std)
print("英语标准差:", english_std)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jesse_Kyrie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值