介绍
我是一个程序员。从大学时代开始我就一直在进行编程,而我仍然对使用简单的Python代码所开辟的道路之多感到惊讶。
但是我并不总是那么高效。我相信这是大多数程序员(尤其是刚起步的程序员)共有的一个特征,编写代码的快感始终优先于效率和简洁性。虽然这在我们的大学期间有效,但在专业环境中,尤其是在数据科学项目中,情况却大相径庭。
作为数据科学家,编写优化的Python代码非常非常重要。杂乱,效率低下的代码即浪费你的时间甚至浪费你项目的钱。经验丰富的数据科学家和专业人员都知道,当我们与客户合作时,杂乱的代码是不可接受的。
因此,在本文中,我将借鉴我多年的编程经验来列出并展示四种可用于优化数据科学项目中Python代码的方法。
优化是什么?
首先定义什么是优化。我们将使用一个直观的示例进行此操作。
这是我们的问题:
假设给定一个数组,其中每个索引代表一个城市,该索引的值代表该城市与下一个城市之间的距离。假设我们有两个索引,我们需要计算这两个索引之间的总距离。简单来说,我们需要找到两个给定索引之间距离的总和。
首先想到的是,一个简单的FOR循环在这里可以很好地工作。但是,如果有100,000多个城市,而我们每秒接收50,000多个查询,该怎么办?你是否仍然认为FOR循环可以为我们的问题提供足够好的解决方案?
FOR循环并不能提供足够好的方案。这时候优化就派上用场了
简单地说,代码优化意味着在生成正确结果的同时减少执行任何任务的操作数。
让我们计算一下FOR循环执行此任务所需的操作数:
我们必须在上面的数组中找出索引1和索引3的城市之间的距离。
对于较小的数组大小,循环的性能良好
如果数组大小为100,000,查询数量为50,000,该怎么办?
这是一个很大的数字。如果数组的大小和查询数量进一步增加,我们的FOR循环将花费大量时间。你能想到一种优化的方法,使我们在使用较少数量的解决方案时可以产生正确的结果吗?
在这里,我将讨论一个更好的解决方案,通过使用前缀数组来计算距离来解决这个问题。让我们看看它是如何工作的:
你能理解吗?我们只需一次操作就可以得到相同的距离!关于此方法的最好之处在于,无论索引之间的差是1还是100,000,都只需执行一个操作即可计算任意两个索引之间的距离。
我创建了一个样本数据集,其数组大小为100,000和50,000个查询。你可以自己执行代码来比较两者所用的时间
注意:数据集总共有50,000个查询,你可以更改参数execute_queries以执行最多50,000个查询,并查看每种方法执行任务所花费的时间。
- import time
- from tqdm import tqdm
- data_file = open('sample-data.txt', 'r')
- distance_between_city = data_file.readline().split()
- queries = data_file.readlines()
- print('SIZE OF ARRAY = ', len(distance_between_city))
- print('TOTAL NUMBER OF QUERIES = ', len(queries))
- data_file.close()
- # 分配要执行的查询数
- execute_queries = 2000
- print('\n\nExecuting',execute_queries,'Queries')
- # FOR循环方法
- # 读取文件并存储距离和查询
- start_time_for_loop = time.time()
- data_file = open('sample-data.txt', 'r')
- distance_between_city = data_file.readline().split()
- queries = data_file.readlines()
- # 存储距离的列表
- distances_for_loop = []
- # 计算开始索引和结束索引之间的距离的函数
- def calculateDistance(startIndex, endIndex):
- distance = 0
- for number in range(startIndex, endIndex+1, 1):
- distance += int(distance_between_city[number])
- return distance
- for query in tqdm(queries[:execute_queries]):
- query = query.split()
- startIndex = int(query[0])
- endIndex = int(query[1])
- distances_for_loop.append(calculateDistance(startIndex,endIndex))
- data_file.close()
- # 获取结束时间
- end_time_for_loop = time.time()
- print('\n\nTime Taken to execute task by for loop :', (end_time_for_loop-start_time_for_loop),'seconds')
- # 前缀数组方法
- # 读取文件并存储距离和查询
- start_time_for_prefix = time.time()
- data_file = open('sample-data.txt', 'r')
- distance_between_city = data_file.readline().split()
- queries = data_file.readlines()
- # 存储距离列表
- distances_for_prefix_array = []
- # 创建前缀数组
- prefix_array = []
- prefix_array.append(int(distance_between_city[0]))
- for i in range(1, 100000, 1):
- prefix_array.append((int(distance_between_city[i]) + prefix_array[i-1]))
- for query in tqdm(queries[:execute_queries]):
- query = query.split()
- startIndex = int(query[0])
- endIndex = int(query[1])
- if startIndex == 0:
- distances_for_prefix_array.append(prefix_array[endIndex])
- else:
- distances_for_prefix_array.append((prefix_array[endIndex]-prefix_array[startIndex-1]))
- data_file.close()
- end_time_for_prefix = time.time()
- print('\n\nTime Taken by Prefix Array to execute task is : ', (end_time_for_prefix-start_time_for_prefix), 'seconds')
- # 检查结果
- correct = True
- for result in range(0,execute_queries):
- if distances_for_loop[result] != distances_for_prefix_array[result] :
- correct = False
- if correct:
- print('\n\nDistance calculated by both the methods matched.')
- else:
- print('\n\nResults did not matched!!')
结果极大的节省了时间,这就是优化Python代码的重要性。我们不仅节省时间,而且还可以节省很多计算资源!
你可能想知道这些如何应用于数据科学项目。你可能已经注意到,很多时候我们必须对大量数据点执行相同的查询。在数据预处理阶段尤其如此。
我们必须使用一些优化的技术而不是基本的编程来尽可能快速高效地完成工作。因此,这里我将分享一些我用来改进和优化Python代码的优秀技术
1. Pandas.apply() | 特征工程的钻石级函数
Pandas已经是一个高度优化的库,但是我们大多数人仍然没有充分利用它。现在你思考一下在数据科学中会使用它的常见地方。
我能想到的一项是特征工程,我们使用现有特征创建新特征。最有效的方法之一是使用Pandas.apply()。
在这里,我们可以传递用户定义的函数,并将其应用于Pandas序列化数据的每个数据点。它是Pandas库中很好的插件之一,因为此函数可以根据所需条件选择性隔离数据。所以,我们可以有效地将其用于数据处理任务。
(编辑:ASP站长网)
|