python数据分析-numpy

引言

当涉足数据分析世界,无论是初学者还是经验丰富的分析师,都会发现Python是一个强大而灵活的工具。而在Python的数据分析生态系统中,NumPy(Numerical Python)是一个不可或缺的库,它提供了广泛的数学和统计函数,以及多维数组操作的能力。

在本博客中,将探讨NumPy库的核心功能,从创建和操作多维数组,到使用广播机制进行数组计算,再到了解结构化数组和矩阵计算。NumPy不仅提供了强大的数学工具,还是数据分析、机器学习和科学计算的基础。

无论你是希望提高数据分析技能,还是需要深入了解NumPy的各种用途,这篇博客都将为你提供宝贵的知识。让我们一起开始探索NumPy,掌握这个强大的数据分析工具!

结构体系

基于 NumPy 的知识体系梳理:

一、NumPy 基础

  1. 数组创建与操作:ndarray对象、数组切片、数组形状修改、数组数据类型、数组转换与复制

  2. 数组索引与切片:一维、二维和多维数组的索引与切片操作。

  3. 数组运算与广播:NumPy 数组支持元素级别的运算,也可以使用数学函数和线性代数函数对数组进行操作。

  4. 数组统计与排序:计算数组的最大值、最小值、平均数、中位数、方差、标准差等统计量;以及对数组进行排序。

  5. 随机数生成:使用 NumPy 可以生成各种类型的随机数,例如服从正态分布、均匀分布等的随机数。

二、NumPy 进阶

  1. 数组高级操作:布尔索引、花式索引、where 函数、迭代器等。
  2. 数组合并和拆分:vstack、hstack、concatenate 等函数可以将多个数组合并成一个数组,split、hsplit 和 vsplit 函数则可以将一个数组拆分成多个部分。
  3. 广义表与轴:广义表是由嵌套列表或数组组成的数据结构,可以用来表示树状、分层结构的数据。轴是表示数组维度的对象,通过指定轴可以对数组进行各种操作。
  4. 数组的内存布局:了解 NumPy 数组内存布局对于数组的性能优化非常重要,包括数组的 C 风格和 Fortran 风格的存储方式,以及如何使用 strides 属性来自定义数组内存布局。
  5. 结构化数组:结构化数组可以看作是表格或数据库中的行,每个元素包含多个字段,可以使用字段名或下标访问。
  6. 矩阵计算:NumPy 提供了专门的矩阵类 matrix,以及针对矩阵的一些特定运算函数,例如矩阵乘法、求逆矩阵等。

1.数组创建与操作

1.1 ndarray对象

ndarray(N-dimensional array)是NumPy中的核心数据结构,用于表示多维数组。它提供了高效的数值计算和广泛的数学函数支持。

创建ndarray对象

在NumPy中,使用np.array()函数来创建ndarray对象。例如,创建一个简单的一维数组:

import numpy as np

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

#输出
[1 2 3 4 5]

数组的属性

ndarray对象有一些重要的属性:

  • 形状(shape):数组的维度和大小。
  • 数据类型(dtype):数组中元素的数据类型。
  • 维度(ndim):数组的维度数量。
  • 大小(size):数组中元素的总数。
# 数组的属性
print("形状:", arr.shape)
print("数据类型:", arr.dtype)
print("维度:", arr.ndim)
print("大小:", arr.size)

# 输出
形状: (5,)
数据类型: int32
维度: 1
大小: 5

多维数组

除了一维数组,NumPy还支持多维数组的创建。例如,创建一个二维数组:

# 创建二维数组
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix)

# 输出
[[1 2 3]
 [4 5 6]
 [7 8 9]]

数组索引与切片

你可以使用索引和切片来访问数组中的元素。例如,访问一维数组的第三个元素:

# 访问一维数组的元素
print(arr[2])  # 输出 3

或者访问二维数组的特定元素:

# 访问二维数组的元素
print(matrix[1, 2])  # 输出 6

1.2 数组切片

切片一维数组

在一维数组中,使用切片来获取数组的子集。例如,创建一个包含一些整数的一维数组:

import numpy as np

arr = np.array([10, 20, 30, 40, 50])

# 使用切片获取数组的子集
subset = arr[1:4]  # 从索引1到3(不包含4)
print(subset)

这将输出 [20 30 40],即从索引1到3的元素。

切片多维数组

在多维数组中,你可以使用切片来获取行、列或子数组。例如,创建一个二维数组:

matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 使用切片获取行
row = matrix[1, :]  # 获取第二行
print(row)

这将输出 [4 5 6],表示我们获取了第二行的所有元素。

# 使用切片获取列
column = matrix[:, 2]  # 获取第三列
print(column)

这将输出 [3 6 9],表示我们获取了第三列的所有元素。

高级切片

NumPy允许使用更高级的切片操作,如跳跃切片、布尔值切片等,以满足更复杂的需求。例如,通过布尔值切片,可以根据某个条件选择数组中的元素。

# 布尔值切片示例
values = np.array([1, 2, 3, 4, 5])
condition = values > 2
result = values[condition]
print(result)

这将输出 [3 4 5],表示我们选择了大于2的元素。

继续我们的探讨,下一个要点是数组形状修改。在NumPy中,你可以轻松地改变数组的形状以满足你的需求。

1.3 数组形状修改

使用reshape()方法

reshape()方法允许改变数组的形状,而不改变其数据。例如,创建一个一维数组,然后将其形状改变为二维数组:

import numpy as np

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

# 使用reshape()方法改变数组形状
reshaped_arr = arr.reshape(2, 3)  # 将一维数组转换为二维数组
print(reshaped_arr)

这将输出一个二维数组:

[[1 2 3]
 [4 5 6]]

使用ravel()flatten()方法

需要将多维数组转换为一维数组,这时可以使用 ravel()flatten() 方法。

# 使用ravel()方法将多维数组转换为一维数组
raveled_arr = reshaped_arr.ravel()
print(raveled_arr)

# 使用flatten()方法同样将多维数组转换为一维数组
flattened_arr = reshaped_arr.flatten()
print(flattened_arr)

这两种方法都会将多维数组转换为一维数组,不过 ravel() 有时会返回视图(视图与原数组共享数据),而 flatten() 总是返回数组的副本(新数组)。

注意事项

在使用 reshape() 进行形状修改时,需要确保新形状兼容原数组的大小。否则,将会收到 ValueError 错误。例如,尝试将一个包含6个元素的一维数组改为3x3的形状将导致错误。

# 错误的形状修改示例
arr = np.array([1, 2, 3, 4, 5, 6])
reshaped_arr = arr.reshape(3, 3)  # 这将引发错误

1.4 数组数据类型

默认数据类型

当创建一个数组时,NumPy会根据输入的数据自动选择一个合适的数据类型。例如,创建一个包含整数的数组,NumPy通常会使用整数数据类型。

import numpy as np

arr = np.array([1, 2, 3, 4])
print("默认数据类型:", arr.dtype)

显示指定数据类型

需要显式指定数组的数据类型,以确保计算的精度或满足特定需求。可以使用dtype参数来指定数据类型:

# 显式指定数据类型
arr_float = np.array([1, 2, 3, 4], dtype=float)
print("指定数据类型为浮点数:", arr_float.dtype)

数据类型的影响

不同的数据类型会影响数组的内存占用和数值精度。例如,浮点数通常会占用更多内存,但具有更高的数值精度,而整数占用较少内存,但精度有限。

# 不同数据类型的影响
arr_int = np.array([1, 2, 3, 4], dtype=int)
arr_float = np.array([1, 2, 3, 4], dtype=float)

print("整数数组内存占用:", arr_int.itemsize)
print("浮点数数组内存占用:", arr_float.itemsize)

数据类型转换

使用astype()方法来将数组的数据类型转换为其他类型:

# 数据类型转换
arr_int = np.array([1, 2, 3, 4], dtype=int)
arr_float = arr_int.astype(float)
print("转换后的数据类型:", arr_float.dtype)

1.5 数组转换与复制

数组的数据类型转换

在前面的部分,已经讨论了如何使用 astype() 方法将数组的数据类型转换为其他类型。这对于将数组从一个数据类型转换为另一个数据类型非常有用。例如:

import numpy as np

arr_int = np.array([1, 2, 3, 4], dtype=int)
arr_float = arr_int.astype(float)  # 将整数数组转换为浮点数数组

复制和视图

当你对数组执行操作时,有时会创建原始数组的副本,有时会创建一个视图,它与原始数组共享数据。这可能会导致一些不同的行为。

  • 副本:如果你明确要创建一个新的独立副本,可以使用 copy() 方法。
original_arr = np.array([1, 2, 3])
copied_arr = original_arr.copy()  # 创建副本
  • 视图:在某些情况下,切片和形状修改操作会返回一个视图,而不是副本。这表示数据在原始数组和视图之间共享。
original_arr = np.array([1, 2, 3, 4, 5])
sliced_arr = original_arr[1:4]  # 创建一个切片(视图)

引用和复制的区别

理解视图和副本的区别非常重要。修改视图可能会影响原始数组,而修改副本则不会。例如:

original_arr = np.array([1, 2, 3, 4, 5])
sliced_arr = original_arr[1:4]  # 创建一个切片(视图)

sliced_arr[0] = 99  # 修改切片,会影响原始数组
print(original_arr)

在上面的例子中,原始数组中的值也被修改为 [1, 99, 3, 4, 5],因为切片是一个视图,与原始数组共享数据。

original_arr = np.array([1, 2, 3, 4, 5])
copied_arr = original_arr.copy()  # 创建副本

copied_arr[0] = 99  # 修改副本,不会影响原始数组
print(original_arr)

在这个例子中,原始数组保持不变,因为我们在副本上进行了修改

2. 数组索引与切片

2.1 一维数组的索引与切片

在NumPy中,一维数组的索引和切片操作非常类似于Python中的列表。示例:

import numpy as np

arr = np.array([10, 20, 30, 40, 50])

# 获取单个元素
element = arr[2]  # 获取索引为2的元素,值为30

# 使用切片获取子数组
subset = arr[1:4]  # 获取索引1到3的元素,子数组为 [20, 30, 40]

# 使用负数索引从尾部开始计数
tail_element = arr[-1]  # 获取最后一个元素,值为50

# 使用步长切片
every_other = arr[::2]  # 每隔一个元素,得到 [10, 30, 50]

# 修改元素的值
arr[3] = 42  # 将索引为3的元素修改为42

# 反转数组
reversed_arr = arr[::-1]  # 得到 [50, 42, 30, 20, 10]

这些是一维数组索引和切片的基本操作。通过索引获取单个元素,通过切片获取子数组,使用负数索引从尾部开始计数,以及使用步长切片来创建新的数组。

2.2 二维和多维数组的索引与切片

在二维和多维数组中,索引和切片操作稍微复杂一些,因为需要考虑多个维度。示例:

import numpy as np

matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 获取单个元素
element = matrix[1, 2]  # 获取第二行第三列的元素,值为6

# 使用切片获取行或列
row = matrix[0, :]  # 获取第一行,数组为 [1, 2, 3]
column = matrix[:, 1]  # 获取第二列,数组为 [2, 5, 8]

# 获取子矩阵
submatrix = matrix[0:2, 1:3]  # 获取第一行到第二行、第二列到第三列的子矩阵

在二维和多维数组中,使用逗号分隔的索引来访问不同维度的元素。还可以使用切片来获取行、列或子矩阵。

非常好,让我们继续探讨数组运算与广播,这是NumPy中非常重要的概念,允许你进行元素级别的运算以及应用数学函数和线性代数函数。

3. 数组运算与广播

3.1 元素级别的运算

NumPy数组支持元素级别的运算,可以对数组的每个元素进行操作,而不必编写循环。

import numpy as np

# 创建两个数组
arr1 = np.array([1, 2, 3, 4])
arr2 = np.array([5, 6, 7, 8])

# 加法
result_add = arr1 + arr2  # 对应元素相加

# 减法
result_subtract = arr1 - arr2  # 对应元素相减

# 乘法
result_multiply = arr1 * arr2  # 对应元素相乘

# 除法
result_divide = arr1 / arr2  # 对应元素相除

# 幂运算
result_power = arr1 ** 2  # 对每个元素进行平方运算

# 开方
result_sqrt = np.sqrt(arr1)  # 对每个元素进行平方根运算

这些是一些常见的元素级别运算示例,但NumPy支持更多运算,包括三角函数、指数函数等。

3.2 广播

广播是NumPy中强大的特性之一,它允许对不同形状的数组进行运算。当你对不同形状的数组进行运算时,NumPy会自动扩展较小的数组以匹配较大的数组,使它们具有相同的形状,然后执行运算

例如,将一个标量(如单个数字)与数组相乘:

import numpy as np

arr = np.array([1, 2, 3, 4])
result = arr * 2  # 数组中的每个元素都乘以2

在这个示例中,标量2被广播到数组arr的每个元素上,以执行元素级别的乘法运算。

广播也适用于不同形状的数组,只要它们在某些维度上具有相同的大小。例如,将一个一维数组与一个二维数组相加:

import numpy as np

arr1 = np.array([1, 2, 3])
arr2 = np.array([[10, 20, 30], [40, 50, 60]])

result = arr1 + arr2

在这个示例中,一维数组arr1被广播到与二维数组arr2相同的形状,以执行元素级别的加法运算。

广播是NumPy中强大的功能,能够执行各种不同形状的数组之间的运算,而无需显式编写循环。

这是数组运算与广播的基础知识,NumPy提供了丰富的数学函数和线性代数函数,可以应用于数组,以进行更复杂的数学和统计分析。

继续我们的学习,下一个要点是数组统计与排序,在NumPy中,你可以轻松地执行各种统计操作和数组排序。

4. 数组统计与排序

4.1 数组的统计操作

NumPy提供了一系列用于计算数组统计量的函数,如最大值、最小值、平均数、中位数、方差、标准差等。

下面是一些常见的统计函数示例:

import numpy as np

arr = np.array([12, 45, 7, 23, 56, 19, 5])

# 计算数组的最大值
max_value = np.max(arr)  # 输出 56

# 计算数组的最小值
min_value = np.min(arr)  # 输出 5

# 计算数组的平均值
mean_value = np.mean(arr)  # 输出 23.285714285714285

# 计算数组的中位数
median_value = np.median(arr)  # 输出 19.0

# 计算数组的方差
variance = np.var(arr)  # 输出 301.38775510204084

# 计算数组的标准差
std_deviation = np.std(arr)  # 输出 17.387426361556492

这些函数可用于一维数组,也可以用于多维数组,并通过指定axis参数来沿指定轴进行计算。

首先,创建一个二维数组,以进行示例:

import numpy as np

matrix = np.array([[12, 45, 7, 23],
                  [56, 19, 5, 8],
                  [33, 22, 11, 43]])

沿行进行统计

沿行计算统计量,例如每行的平均值,可以使用axis参数指定轴0(行轴):

# 计算每行的平均值
row_means = np.mean(matrix, axis=0)

这将计算每一列的平均值,结果为 [33.66666667 28.66666667 7.66666667 24.66666667]

沿列进行统计

沿列计算统计量,例如每列的最大值,可以使用axis参数指定轴1(列轴):

# 计算每列的最大值
column_max = np.max(matrix, axis=1)

这将计算每一行的最大值,结果为 [45 56 43]

这是一个简单的案例,说明如何使用axis参数来沿指定轴执行统计操作。可以使用相同的方法来计算其他统计量,如最小值、中位数、方差等。

4.2 数组的排序

NumPy还提供了用于数组排序的函数,按升序或降序对数组进行排序。下面是一些示例:

import numpy as np

arr = np.array([12, 45, 7, 23, 56, 19, 5])

# 对数组升序排序 sort默认为升序
sorted_arr_ascending = np.sort(arr)  # 输出 [ 5  7 12 19 23 45 56]

# 对数组降序排序
sorted_arr_descending = np.sort(arr)[::-1]  # 输出 [56 45 23 19 12  7  5]

使用argsort()函数来获取排序后的索引,以便对其他数组进行相同的排序操作。

# 获取排序后的索引
sorted_indices = np.argsort(arr)

继续我们的学习,下一个要点是随机数生成,在NumPy中,你可以使用随机数生成函数生成各种类型的随机数,包括服从正态分布、均匀分布等的随机数。

5. 随机数生成

5.1 生成均匀分布的随机数

使用np.random.rand()函数生成服从均匀分布的随机数。这将生成在0到1之间均匀分布的随机数。以下是一些示例:

import numpy as np

# 生成一个均匀分布的随机数
uniform_random = np.random.rand()  # 生成一个[0, 1)范围内的随机数

# 生成一个一维数组,包含多个均匀分布的随机数
uniform_array = np.random.rand(5)  # 生成包含5个随机数的一维数组

# 生成一个二维数组,包含多个均匀分布的随机数
uniform_matrix = np.random.rand(3, 2)  # 生成3x2的二维数组,包含均匀分布的随机数

5.2 生成正态分布的随机数

使用np.random.randn()函数生成服从标准正态分布(均值为0,标准差为1)的随机数。以下是一些示例:

import numpy as np

# 生成一个标准正态分布的随机数
normal_random = np.random.randn()  # 生成一个标准正态分布的随机数

# 生成一个一维数组,包含多个标准正态分布的随机数
normal_array = np.random.randn(5)  # 生成包含5个标准正态分布的随机数的一维数组

# 生成一个二维数组,包含多个标准正态分布的随机数
normal_matrix = np.random.randn(3, 2)  # 生成3x2的二维数组,包含标准正态分布的随机数

5.3 生成指定分布的随机数

NumPy还提供了其他随机数生成函数,可以生成不同分布的随机数,如二项分布、泊松分布等。使用np.random模块来探索这些函数。

# 生成二项分布的随机数
binomial_random = np.random.binomial(10, 0.5, 5)  # 生成5个符合二项分布的随机数

# 生成泊松分布的随机数
poisson_random = np.random.poisson(3, 5)  # 生成5个符合泊松分布的随机数

这些函数非常有用,可以生成符合不同分布的随机数,以用于模拟、实验或统计分析。

非常好,我们将继续学习数组高级操作,包括布尔索引、花式索引、where函数、迭代器等。

6. 数组高级操作

6.1 布尔索引

布尔索引是一种强大的工具,用于根据某些条件从数组中选择元素。创建一个布尔数组,其中每个元素表示与条件相对应的真值,然后使用该布尔数组来选择满足条件的元素。以下是一个示例:

import numpy as np

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

# 创建一个布尔数组,满足条件的元素为True
condition = arr > 3

# 使用布尔索引选择满足条件的元素
selected = arr[condition]  # 选择大于3的元素

print(selected)  # 输出 [4 5 6]

6.2 花式索引

花式索引是一种通过指定索引数组来获取数组元素的方式。使用整数数组来选择元素,从而创建一个新的数组。以下是一个示例:

import numpy as np

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

# 创建一个索引数组,用于选择元素
indices = np.array([1, 3, 5])

# 使用花式索引选择元素
selected = arr[indices]

print(selected)  # 输出 [2 4 6]

6.3 where函数

np.where()函数是一个强大的工具,用于根据条件从数组中选择元素。它可以返回满足条件的元素的索引或实际的元素值。以下是一些示例:

import numpy as np

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

# 使用np.where()选择满足条件的元素的索引
indices = np.where(arr > 3)

# 使用np.where()选择满足条件的元素的值 np.where(condition, x, y)
values = np.where(arr > 3, arr, 0)

print(indices)  # 输出 (array([3, 4, 5]),)
print(values)   # 输出 [0 0 0 4 5 6]

np.where()函数是一个非常灵活的工具,它可以在不同的条件下返回不同的结果。

6.4 迭代器

NumPy数组可以使用Python标准的for循环进行迭代,但更常见的做法是使用NumPy提供的迭代器。以下是一个示例:

import numpy as np

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

# 使用NumPy迭代器遍历数组
for element in np.nditer(arr):
    print(element)

继续我们的学习,下一个要点是数组合并和拆分,在NumPy中,你可以使用各种函数来将多个数组合并成一个数组,或将一个数组拆分成多个部分。

7. 数组合并和拆分

7.1 数组合并

在NumPy中,可以用不同的函数来合并多个数组,如 vstackhstackconcatenate 等。以下是一些示例:

  • vstack 函数用于垂直堆叠(按行堆叠)多个数组:
    import numpy as np

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

    # 使用vstack垂直堆叠数组
    result = np.vstack((arr1, arr2))

    print(result)

    #输出
    [[1 2 3]
      [4 5 6]]

结果是一个新的数组,其中包含两个输入数组按行堆叠在一起。

  • hstack 函数用于水平堆叠(按列堆叠)多个数组:
import numpy as np

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

# 使用hstack水平堆叠数组
result = np.hstack((arr1, arr2))

print(result) #输出[1 2 3 4 5 6]

结果是一个新的数组,其中包含两个输入数组按列堆叠在一起。

  • concatenate 函数允许你指定要沿着哪个轴合并数组:
import numpy as np

# 定义两个一维数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

# 使用 concatenate 函数按行合并数组
result_row = np.concatenate((arr1, arr2), axis=0)

# 将一维数组转换为二维数组
arr1_2d = arr1.reshape(1, -1)
arr2_2d = arr2.reshape(1, -1)

# 使用 concatenate 函数按列合并二维数组
result_column = np.concatenate((arr1_2d, arr2_2d), axis=1)

print(result_row)     # 输出 [1 2 3 4 5 6]
print(result_column)  # 输出 [[1 4]
                      #      [2 5]
                      #      [3 6]]

7.2 数组拆分

NumPy也提供了函数来拆分数组,如 splithsplitvsplit。以下是一些示例:

  • split 函数可以将数组沿指定轴拆分成多个部分:
np.split(arr, indices_or_sections, axis=0)
import numpy as np

# 定义一个一维数组
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

# 将数组分割成两个等份
result1 = np.split(arr, 2)
print(result1)  # 输出 [array([1, 2, 3, 4, 5]), array([6, 7, 8, 9, 10])]

# 在索引 3 和 7 处进行分割
result2 = np.split(arr, [3, 7])
print(result2)  # 输出 [array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9, 10])]

# 沿着列方向分割二维数组
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
result3 = np.split(arr_2d, 3, axis=1)
print(result3)  # 输出 [array([[1], [4], [7]]), array([[2], [5], [8]]), array([[3], [6], [9]])]

结果是一个包含拆分后的数组部分的列表。

  • hsplit 函数用于水平拆分数组,vsplit 用于垂直拆分数组:
import numpy as np

matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 使用hsplit函数水平拆分数组
hsplit_parts = np.hsplit(matrix, 3)

# 使用vsplit函数垂直拆分数组
vsplit_parts = np.vsplit(matrix, 3)

print(hsplit_parts)
print(vsplit_parts)

# 输出
[array([[1],
       [4],
       [7]]), array([[2],
       [5],
       [8]]), array([[3],
       [6],
       [9]])]
[array([[1, 2, 3]]), array([[4, 5, 6]]), array([[7, 8, 9]])]

这些函数允许你按照指定轴将数组拆分为多个部分。

8. 广义表与轴

8.1 广义表

广义表是一种由嵌套列表或多维数组组成的数据结构,它可以表示树状、分层结构的数据。在NumPy中,多维数组通常被视为广义表,其中每个维度对应于数据的一个层次结构。

例如,考虑一个包含学生成绩的二维数组,其中第一个维度表示不同的课程,第二个维度表示不同的学生。这可以被视为广义表,其中每个课程有一组学生成绩。以下是一个示例:

import numpy as np

# 创建包含学生成绩的二维数组
grades = np.array([[85, 92, 78],
                  [90, 88, 80],
                  [79, 85, 88]])

# grades 是一个广义表,其中每行表示一个课程的成绩

8.2 轴

在NumPy中,轴是表示数组的维度的对象。对于二维数组,通常有两个轴:0轴表示行,1轴表示列。对于三维数组,会有三个轴,以此类推。

轴在NumPy中非常重要,因为它们允许你在多维数组中执行各种操作。例如,可以使用轴来计算每一行或每一列的总和、平均值等。

以下是一些示例:

import numpy as np

matrix = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

# 计算每一行的总和(沿0轴)
row_sum = np.sum(matrix, axis=0)

# 计算每一列的总和(沿1轴)
column_sum = np.sum(matrix, axis=1)

print(row_sum)  # 输出 [12 15 18]
print(column_sum)  # 输出 [ 6 15 24]

理解NumPy数组的内存布局对于数组的性能优化至关重要。NumPy支持两种主要的内存布局方式:C风格和Fortran风格,并提供strides属性来自定义数组的内存布局。让我们详细了解这些概念。

9. 数组的内存布局

9.1 C风格内存布局

C风格内存布局是NumPy中的默认方式,它与大多数编程语言的内存布局一致,数据以行为主存储。在C风格内存布局中,数组的元素在内存中是按行存储的,即相邻元素在相邻内存位置中。

下面是一个示例:

import numpy as np

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

print(arr.flags['C_CONTIGUOUS'])  # 输出 True,表示C风格内存布局

9.2 Fortran风格内存布局

Fortran风格内存布局与C风格相反,它以列为主存储数据。在Fortran风格内存布局中,数组的元素在内存中是按列存储的,即相邻元素在相邻内存位置中。

下面是一个示例:

import numpy as np

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

print(arr.flags['F_CONTIGUOUS'])  # 输出 False,表示不是Fortran风格内存布局

9.3 自定义数组内存布局

NumPy还允许自定义数组的内存布局,通过使用strides属性。strides是一个元组,指定了在每个维度上跨越数组元素所需的字节数。可以使用strides属性来创建一个不连续的数组,以满足特定的需求。

下面是一个示例,创建一个具有自定义内存布局的数组:

import numpy as np

# 创建一个自定义内存布局的数组
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]], dtype=np.int32)

# 设置自定义strides,使数组在每行之间有空隙
arr.strides = (24, 4)  # 每行跨越24字节,每个元素之间跨越4字节

print(arr)

通过自定义strides属性,可以创建特定内存布局的数组,以满足性能和数据处理需求。

10结构化数据

结构化数组是NumPy中的一个重要概念,它允许创建类似表格或数据库中的数据结构,每个元素都包含多个字段,可以使用字段名或下标来访问和操作数据。结构化数组通常用于处理异构数据,例如,每个元素包含不同类型的数据,如字符串、整数、浮点数等。

以下是如何创建和使用结构化数组的基本示例:

import numpy as np

# 创建一个结构化数组,定义字段名和数据类型
data_type = [('name', 'U10'), ('age', int), ('weight', float)]

# 创建一个空的结构化数组
people = np.array([], dtype=data_type)

# 添加数据到结构化数组
person1 = ('Alice', 25, 55.5)
person2 = ('Bob', 30, 68.2)
person3 = ('Charlie', 22, 61.8)

people = np.append(people, np.array([person1, person2, person3], dtype=data_type))

# 访问结构化数组中的数据
print(people['name'])    # 输出 ['Alice' 'Bob' 'Charlie']
print(people['age'])     # 输出 [25 30 22]
print(people['weight'])  # 输出 [55.5 68.2 61.8]

在这个示例中,我们首先定义了结构化数组的数据类型,其中包含三个字段:’name’(字符串类型,最大长度为10),’age’(整数类型),’weight’(浮点数类型)。然后,我们创建了一个空的结构化数组,并向其中添加数据,最后通过字段名访问数组中的数据。

11矩阵计算

NumPy提供了专门的矩阵类matrix,以及针对矩阵的一些特定运算函数,使矩阵计算更方便。虽然NumPy中的多维数组(ndarray)可以执行矩阵计算,但matrix类提供了更直观的语法和一些额外的矩阵运算功能。

以下是一些关于矩阵计算的基本示例:

import numpy as np

# 创建矩阵
matrix1 = np.matrix([[1, 2], [3, 4]])
matrix2 = np.matrix([[5, 6], [7, 8]])

# 矩阵乘法
result = matrix1 * matrix2

print(result)

# 求逆矩阵
inverse_matrix = matrix1.I

print(inverse_matrix)

# 矩阵转置
transpose_matrix = matrix1.T

print(transpose_matrix)

# 输出
[[19 22]
 [43 50]]
[[-2.   1. ]
 [ 1.5 -0.5]]
[[1 3]
 [2 4]]

在上述示例中,首先创建了两个矩阵matrix1matrix2,然后进行了矩阵乘法、求逆矩阵和矩阵转置的操作。matrix类提供了更直观的运算符重载,使矩阵计算更容易理解。

虽然matrix类在某些情况下很有用,但在实际应用中,NumPy多维数组(ndarray)仍然是更通用和灵活的数据结构,因为它们支持更多的数学和科学计算操作,并且在生态系统中更为广泛使用。

参考

numpy官网:https://numpy.org/doc/stable/index.html


   转载规则


《python数据分析-numpy》 Bevis23 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
python数据分析-pandas python数据分析-pandas
引言数据分析是当今世界中日益重要的技能之一。随着大量数据的产生和积累,数据分析能力已成为了解、预测和解决各种问题的关键工具。无论你是一名数据分析师,一名学生,还是一个对数据分析感兴趣的人,了解如何使用Python和Pandas进行数据分析都
2023-10-13
下一篇 
python生成器与yield python生成器与yield
引言在Python编程世界中,有一种神奇的机制,它能够以惊人的效率管理数据流,同时又占用极少的内存空间。这个机制就是生成器,而它的魔力关键字是”yield”。生成器和yield在处理大型数据集或无限序列时,可以成为性能的保障,同时让代码变得
2023-10-13
  目录
切换