没想到吧?让数据处理速度高了2-6倍,我只写了3行Python代码

在 Python 中,我们可以找到原生的并行化运算指令。本文可以教你仅使用 3 行代码,大大加快数据预处理的速度。

傻了吧?数据处理速度高2-6倍,我只写了3行Python代码

在默认情况下,Python 程序是单个进程,使用单 CPU 核心执行。而大多数硬件都至少搭载了双核处理器。这意味着如果没有进行优化,在数据预处理的时候会出现「一核有难九核围观」的情况——超过 50% 的算力都会被浪费。

幸运的是,Python 库中内建了一些隐藏的特性,可以让我们充分利用所有 CPU 核心的能力。通过使用 Python 的 concurrent.futures 模块,我们只需要 3 行代码就可以让一个普通的程序转换成适用于多核处理器并行处理的程序。

标准方法

让我们举一个简单的例子,在单个文件夹中有一个图片数据集,其中有数万张图片。在这里,我们决定使用 1000 张。我们希望在所有图片被传递到深度神经网络之前将其调整为 600×600 像素分辨率的形式。以下是你经常会在 GitHub 上看到的标准 Python 代码:

import glob
import os
import cv2


### Loop through all jpg files in the current folder 
### Resize each one to size 600x600
for image_filename in glob.glob("*.jpg"):
 ### Read in the image data
 img = cv2.imread(image_filename)

 ### Resize the image
 img = cv2.resize(img, (600, 600)) 

上面的程序遵循你在处理数据脚本时经常看到的简单模式:

  • 1. 首先从需要处理内容的文件(或其他数据)列表开始。
  • 2. 使用 for 循环逐个处理每个数据,然后在每个循环迭代上运行预处理。

让我们在一个包含 1000 个 jpeg 文件的文件夹上测试这个程序,看看运行它需要多久:

time python standard_res_conversion.py

在我的酷睿 i7-8700k 6 核 CPU 上,运行时间为 7.9864 秒!在这样的高端 CPU 上,这种速度看起来是难以让人接受的,看看我们能做点什么。

更快的方法

为了便于理解并行化的提升,假设我们需要执行相同的任务,比如将 1000 个钉子钉入木头,假如钉入一个需要一秒,一个人就需要 1000 秒来完成任务。四个人组队就只需要 250 秒。

在我们这个包含 1000 个图像的例子中,可以让 Python 做类似的工作:

  • 将 jpeg 文件列表分成 4 个小组;
  • 运行 Python 解释器中的 4 个独立实例;
  • 让 Python 的每个实例处理 4 个数据小组中的一个;
  • 结合四个处理过程得到的结果得出最终结果列表。

这一方法的重点在于,Python 帮我们处理了所有棘手的工作。我们只需告诉它我们想要运行哪个函数,要用多少 Python 实例,剩下的就交给它了!只需改变三行代码。实例:

import glob
import os
import cv2
import concurrent.futures


def load_and_resize(image_filename):
 ### Read in the image data
 img = cv2.imread(image_filename)

 ### Resize the image
 img = cv2.resize(img, (600, 600)) 


### Create a pool of processes. By default, one is created for each CPU in your machine.
with concurrent.futures.ProcessPoolExecutor() as executor:
 ### Get a list of files to process
 image_files = glob.glob("*.jpg")

 ### Process the list of files, but split the work across the process pool to use all CPUs
 ### Loop through all jpg files in the current folder 
 ### Resize each one to size 600x600
 executor.map(load_and_resize, image_files)

从以上代码中摘出一行:

with concurrent.futures.ProcessPoolExecutor() as executor:

你的 CPU 核越多,启动的 Python 进程越多,我的 CPU 有 6 个核。实际处理代码如下:

executor.map(load_and_resize, image_files)

「executor.map()」将你想要运行的函数和列表作为输入,列表中的每个元素都是我们函数的单个输入。由于我们有 6 个核,我们将同时处理该列表中的 6 个项目!

如果再次用以下代码运行我们的程序:

time python fast_res_conversion.py

我们可以将运行时间降到 1.14265 秒,速度提升了近 6 倍!

注意:在生成更多 Python 进程及在它们之间整理数据时会有一些开销,所以速度提升并不总是这么明显。但是总的来说,速度提升还是非常可观的。

它总是那么快吗?

如果你有一个数据列表要处理,而且在每个数据点上执行相似的运算,那么使用 Python 并行池是一个很好的选择。但有时这不是最佳解决方案。并行池处理的数据不会在任何可预测的顺序中进行处理。如果你对处理后的结果有特殊顺序要求,那么这个方法可能不适合你。

你处理的数据也必须是 Python 可以「炮制」的类型。所幸这些指定类别都很常见。以下来自 Python 官方文件:

  • None, True, 及 False
  • 整数、浮点数、复数
  • 字符串、字节、字节数组
  • 只包含可挑选对象的元组、列表、集合和字典
  • 在模块顶层定义的函数(使用 def ,而不是 lambda )
  • 在模块顶层定义的内置函数
  • 在模块顶层定义的类
  • 这种类的实例,其 __dict__ 或调用__getstate__() 的结果是可选择的(参见「Pickling Class Instances」一节)。
  • 有需要的小伙伴,点赞加收藏,关注我之后添加小助理vx:bjmsb0606006 即可获取免费下载方式

<think>好的,我现在需要帮助用户解决将Python列表转换为34列的数组,并提取特定三组数据的问题。首先,我要理清楚用户的具体需求。 用户提供的序列是a = [6,2,5,0,1,3,4,7,8,9,10,11]。转换成34列的数组,应该怎么做呢?首先想到的是使用NumPy库的reshape方法。但用户提到是Python初学者,可能对NumPy不熟悉,所以可能需要用基本的列表操作来实现。 不过,可能用户还是更倾向于用NumPy,因为reshape更方便。所以先假设使用NumPy。接下来,数组的结构需要确认。34列的话,元素是按填充还是按列填充?默认情况下,NumPy的reshape是按优先(C风格),也就是按顺序填充每一。所以原列表中的元素会按顺序分配到各个。例如,第一6,2,5,0,第二是1,3,4,7,第三是8,9,10,11。那数组应该是这样的结构: [ [6, 2, 5, 0], [1, 3, 4, 7], [8, 9, 10, 11] ] 接下来要提取的三组数据分别是: 第一组:[[6,2],[1,3]]。这里看起来像是第一的前两个元素和第二的前两个元素组成的子数组。但原数组第一前两个是6,2,第二前两个是1,3,所以这两个子数组组合成一个二维数组。所以索引可能是array[0, 0:2]和array[1, 0:2],然后组合起来。 第二组:[8,9,10,11],这应该是第三的全部元素,即array[2, :]。 第三组:[[4,7],[10,11]]。这里可能需要第二的第三、第四个元素(索引23)是4和7,第三的第三、第四个元素是10和11?或者可能是第二的最后两个元素和第三的最后两个。原数组的第二是1,3,4,7,所以索引23是4和7。第三的最后两个是10和11。所以需要array[1, 2:4]和array[2, 2:4],然后组合成二维数组。 现在,如何用Python实现呢? 首先,导入numpy,将a转换为数组,reshape成34列。然后,分别提取这三个部分。 对于第一组:取第一前两个和第二前两个,组成[[6,2], [1,3]]。在数组中的索引是arr[0, 0:2]和arr[1, 0:2]。但是如何将这两个一维数组组合成二维?可能需要将它们放在一个列表中,如 [arr[0, 0:2], arr[1, 0:2]]。此时,每个切片是一个一维数组,组合后变成二维。 第二组直接是arr[2, :],即第三所有元素。 第三组是取第二的第三到第四个元素(索引23)和第三的第三到第四个元素。即arr[1, 2:4]和arr[2, 2:4]。同样,组合成一个列表。 那这样代码应该是这样的: import numpy as np a = [6,2,5,0,1,3,4,7,8,9,10,11] arr = np.array(a).reshape(3,4) group1 = [arr[0, :2].tolist(), arr[1, :2].tolist()] group2 = arr[2, :].tolist() group3 = [arr[1, 2:4].tolist(), arr[2, 2:4].tolist()] print("第一组数据:", group1) print("第二组数据:", group2) print("第三组数据:", group3) 但用户是否希望得到numpy数组还是列表?可能用户需要的是列表形式,因为给出的示例中有列表结构。所以转换成列表形式用.tolist()方法。 但需要注意的是,当使用arr[0, :2]时,得到的是一个一维数组,例如array([6,2]),转换为列表就是[6,2]。所以group1的结构是[[6,2], [1,3]],符合要求。 同样,group3的结构是[[4,7], [10,11]],因为arr[1, 2:4]是array([4,7]),arr[2, 2:4]是array([10,11]),转换后就是对应的列表。 对于第二组,arr[2, :]是array([8,9,10,11]),转换成列表即为[8,9,10,11]。 那这样应该就能得到正确的结果了。接下来检查是否有错误。 原数组的reshape是否正确?是的,34列,12个元素正好填充。 索引是否正确: 第一是索引0,前两个元素是0到2(不包括2),即0和1索引,对应62。 第二索引1,前两个是0到2,即1的0和1,对应1和3?不,原数组第二reshape后的元素应该是1,3,4,7。因为原列表a中的元素在reshape时是按顺序排列的。原列表a的索引0到11: reshape后的数组: row 0: a[0], a[1], a[2], a[3] → 6,2,5,0?但是用户给出的数组在问题描述中是否可能不是这样? 等等,这里可能出问题。用户给出的原序列是[6,2,5,0,1,3,4,7,8,9,10,11]。当reshape成34列时,默认是按填充,即第一是前四个元素,第二接下来四个,第三最后四个。因此,数组应该是: row 0: 6, 2, 5, 0 → indices 0,1,2,3 row 1:1,3,4,7 → indices 4,5,6,7(原列表中的第四个元素是索引4,即1,索引5是3,索引6是4,索引7是7) row 2:8,9,10,11 → indices8,9,10,11,对应原列表中的8,9,10,11. 但原列表中的索引4是1,索引5是3,索引6是4,索引7是7。所以第二的元素是1,3,4,7。那用户提到的三组数据中的第二组是[8,9,10,11],也就是第三,没问题。 现在,第一组数据是[[6,2],[1,3]]。这里,6,2是第一的前两个元素,而1,3是第二的前两个元素吗?因为第二的第一个元素是1,第二个是3,对吗? 是的,所以arr[0, :2]是[6,2],arr[1, :2]是[1,3]。所以group1的结构正确。 第三组数据是[[4,7],[10,11]]。第二的第三和第四个元素是4和7,对应的索引是23,即arr[1, 2:4]。第三的第三和第四元素是10和11,即索引23,arr[2, 2:4]是[10,11]。所以组合起来正确。 所以代码是正确的。 但需要提醒用户安装numpy吗?可能用户是初学者,所以需要在代码前提示安装。或者,如果不想用numpy,可以用列表推导式手动reshape。 不过用户的问题可能希望使用numpy,因为手动处理比较麻烦。但作为回答,可能需要给出两种方法? 但用户明确提到用Python,并且可能希望用numpy来处理数组操作。所以应该用numpy的解决方案,并给出详细步骤。 总结步骤: 1. 将列表转换为NumPy数组,并reshape成34列。 2. 提取各组的索引位置: - 第一组:第一前两个元素和第二前两个元素。 - 第二组:第三所有元素。 - 第三组:第二的后两个元素和第三的后两个元素。 3. 将这些部分组合成所需的列表结构。 最后,确保输出符合要求。代码测试后应该输出正确的结果。 可能用户的问题中的第三组数据是[[4,7],[10,11]],而原数组中第二的后两个元素是4和7,第三的后两个是10和11,所以正确。 所以最终的代码应该是正确的,并附上解释,帮助用户理解每个步骤。</think>我们将按照以下步骤解决问题: ### 步骤 1:转换数组 ```python import numpy as np a = [6,2,5,0,1,3,4,7,8,9,10,11] arr = np.array(a).reshape(3, 4) ``` 得到 3 4 列的数组: $$ \begin{bmatrix} 6 & 2 & 5 & 0 \\ 1 & 3 & 4 & 7 \\ 8 & 9 & 10 & 11 \\ \end{bmatrix} $$ --- ### 步骤 2:提取第一组数据 [[6,2], [1,3]] ```python group1 = [ arr[0, :2].tolist(), # 第一前两个元素 [6,2] arr[1, :2].tolist() # 第二前两个元素 [1,3] ] ``` --- ### 步骤 3:提取第二组数据 [8,9,10,11] ```python group2 = arr[2, :].tolist() # 第三全部元素 ``` --- ### 步骤 4:提取第三组数据 [[4,7], [10,11]] ```python group3 = [ arr[1, 2:4].tolist(), # 第二最后两个元素 [4,7] arr[2, 2:4].tolist() # 第三最后两个元素 [10,11] ] ``` --- ### 最终代码 ```python import numpy as np a = [6,2,5,0,1,3,4,7,8,9,10,11] arr = np.array(a).reshape(3, 4) group1 = [arr[0, :2].tolist(), arr[1, :2].tolist()] group2 = arr[2, :].tolist() group3 = [arr[1, 2:4].tolist(), arr[2, 2:4].tolist()] print("第一组:", group1) # 输出 [[6,2], [1,3]] print("第二组:", group2) # 输出 [8,9,10,11] print("第三组:", group3) # 输出 [[4,7], [10,11]] ``` --- ### 输出结果验证 1. **第一组**:提取数组中第 0 和第 1 的前两个元素 2. **第二组**:直接获取第 2 所有元素 3. **第三组**:提取第 1 和第 2 的最后两个元素 运代码即可得到正确结果 ✅
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值