提升Python代码效率的技巧

作为一名程序员,自大学时代起就开始编程,至今仍对Python代码所能开启的无限可能感到惊奇。然而,并不是一开始就能写出高效的代码。这可能是大多数程序员的通病,尤其是新手。在大学时期,编写代码的乐趣总是优先于代码的效率和整洁性。但在专业环境中,尤其是在数据科学项目中,情况大不相同。

作为一名数据科学家,编写优化的Python代码至关重要。一个杂乱无章、效率低下的笔记本会浪费时间,也会给项目带来巨大的成本。正如经验丰富的数据科学家和专业人士所知,这是与客户合作时所不能接受的。

在本文中,将结合多年的编程经验,列出并展示四种优化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.apply() - 特征工程的利器

Pandas已经是一个高度优化的库,但大多数人仍然没有充分利用它。在数据科学项目中,经常使用它。能想到的一个函数是特征工程,使用现有特征创建新特征。使用Pandas.apply()是实现这一点最有效的方法之一。

import pandas as pd # 假设df是一个Pandas DataFrame,想要计算每条推文的字数 df['word_count'] = df['tweet'].apply(len)

apply()函数是Pandas库中最好的附加功能之一,因为它可以帮助根据所需的条件对数据进行分类。然后可以有效地将其用于数据操作任务。

Pandas.DataFrame.loc - Python数据操作的巧妙技巧

这是最喜欢的Pandas库技巧之一。认为这是处理数据操作任务的数据科学家必须知道的方法(所以几乎每个人都需要知道!)。大多数时候,只需要根据某些条件更新数据集中某个列的一些值。

# 假设想要将'City'变量中的前5个城市保留,其余的替换为'Others' top_cities = df['City'].value_counts().head(5).index df.loc[~df['City'].isin(top_cities), 'City'] = 'Others'

看到更新值有多容易了吗?这是解决这类数据操作任务的最优化方法。

在Python中向量化函数

另一种摆脱慢速循环的方法是通过向量化函数。这意味着新创建的函数将应用于一系列输入,并返回一个结果数组。

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))
  • Python数据科学免费课程
  • 使用Python的数据科学入门
  • 高级Python
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485