作为一名程序员,自大学时代起就开始编程,至今仍对Python代码所能开启的无限可能感到惊奇。然而,并不是一开始就能写出高效的代码。这可能是大多数程序员的通病,尤其是新手。在大学时期,编写代码的乐趣总是优先于代码的效率和整洁性。但在专业环境中,尤其是在数据科学项目中,情况大不相同。
作为一名数据科学家,编写优化的Python代码至关重要。一个杂乱无章、效率低下的笔记本会浪费时间,也会给项目带来巨大的成本。正如经验丰富的数据科学家和专业人士所知,这是与客户合作时所不能接受的。
在本文中,将结合多年的编程经验,列出并展示四种优化Python代码的方法,以帮助数据科学项目。如果是Python(和数据科学)的新手,建议阅读以下资源:
首先,来定义什么是优化。将通过一个直观的例子来解释这一点。假设有一个数组,每个索引代表一个城市,该索引的值代表该城市与下一个城市之间的距离。假设需要计算两个索引之间的总距离。简单来说,需要找到任何两个给定索引之间的总和。
第一个想到的方法可能是使用FOR循环。但如果有100,000+个城市,每秒接收50,000+个查询,还会认为FOR循环能给一个足够好的解决方案吗?实际上并不会。这就是优化代码的神奇之处。
代码优化,简单来说,就是减少执行任何任务所需的操作数量,同时产生正确的结果。让计算一下FOR循环执行这项任务需要多少操作。
这里,将讨论一个可能更好的解决方案,即使用前缀数组来计算距离。让看看它是如何工作的:
# 假设distances是一个包含城市间距离的数组
prefix_sum = [0] # 初始化前缀和数组
for i in range(1, len(distances)):
prefix_sum.append(prefix_sum[i-1] + distances[i])
# 计算索引1和3之间的距离
distance = prefix_sum[3] - prefix_sum[1] + distances[1]
只用了一个操作就得到了相同的距离!这种方法最棒的地方在于,无论索引之间的差异是1还是100,000,它都只需要一个操作来计算任何两个索引之间的距离。这不是很神奇吗?
Pandas已经是一个高度优化的库,但大多数人仍然没有充分利用它。在数据科学项目中,经常使用它。能想到的一个函数是特征工程,使用现有特征创建新特征。使用Pandas.apply()是实现这一点最有效的方法之一。
import pandas as pd
# 假设df是一个Pandas DataFrame,想要计算每条推文的字数
df['word_count'] = df['tweet'].apply(len)
apply()函数是Pandas库中最好的附加功能之一,因为它可以帮助根据所需的条件对数据进行分类。然后可以有效地将其用于数据操作任务。
这是最喜欢的Pandas库技巧之一。认为这是处理数据操作任务的数据科学家必须知道的方法(所以几乎每个人都需要知道!)。大多数时候,只需要根据某些条件更新数据集中某个列的一些值。
# 假设想要将'City'变量中的前5个城市保留,其余的替换为'Others'
top_cities = df['City'].value_counts().head(5).index
df.loc[~df['City'].isin(top_cities), 'City'] = 'Others'
看到更新值有多容易了吗?这是解决这类数据操作任务的最优化方法。
另一种摆脱慢速循环的方法是通过向量化函数。这意味着新创建的函数将应用于一系列输入,并返回一个结果数组。
import numpy as np
# 定义一个向量化的函数来计算字数
def count_words(text):
return len(text)
# 使用NumPy的vectorize功能
vectorized_count = np.vectorize(count_words)
counts = vectorized_count(df['tweet'])
令人难以置信,对吧?在上面的例子中,向量化比循环快了80倍!这不仅有助于加快代码速度,还使代码更加清晰。
多进程是系统同时支持多个处理器的能力。在这里,将进程分解为多个任务,所有任务都独立运行。即使在使用大型数据集时,apply()函数看起来也很慢。
from multiprocessing import Pool
# 定义一个函数来计算除数的数量
def count_divisors(n):
return sum(1 for i in range(1, int(n**0.5) + 1) if n % i == 0)
# 创建一个进程池并映射函数
with Pool() as pool:
results = pool.map(count_divisors, random.sample(range(1, 1000000), 1000000))