全文共3510字,预计学习时长7分钟
作为数据科学家,敲出最优的Python代码非常非常重要。别无他法,杂乱低效的代码笔记本会消耗你的时间,也会浪费大量项目资金。经验丰富的数据科学家和专业人士都很清楚,这样是没办法和客户合作的。
本文将列出4个可行的Python代码优化方法,以便大家日后应用到自己的数据科学项目中。
什么是最优化?
首先来看一个直观的例子,然后定义什么是最优化。
问题是这样的:
假设有一个数组,其中每个指数代表一个城市,指数的值代表该城市和下一个城市之间的距离。已知两个指数,求这两个指数间的距离。简单来讲,就是求任意两个指数间的总值。
指数
0
1
2
3
4
5
城市
A
B
C
D
E
F
距离
15(A-B)
20(B-C)
6(C-D)
10(D-E)
5(E-F)
-
大家肯定首先会想到这里可以用for循环。但是如果一共有十几万个城市,每秒会收到五万多个查询需求呢?这种情况下,for循环还是这个问题的最优解吗?
不是了吧。此时就该挥动优化代码的仙女棒了。
代码最优化,简单来讲,就是在保证结果正确的前提下尽可能减少执行任务的运算量。
来算算for循环完成任务所需的运算量吧:
首先计算出上面数组中指数1和3代表的城市间的距离。
指数1和3代表城市之间的距离=(0+20+6+10)=36=>3次算术运算。
如果数组大小为100000,需求数量为50000呢?
数组总大小为100000。
需求总数为50000。
假设两指数间的平均差异为1000。
完成该任务的算术运算总量近似值为50000*1000=50000000
这个数量非常庞大。如果数据和查询量不断增加,for循环将会花费更多的时间。如果想减少计算量,同时又想得到正确的结果,应该采取什么优化方法呢?
这里,使用前缀数组来计算距离是一种可能的优化方案。它是这样运算的:
大家能理解这里的做法吗?这样只需一次计算就得到了同样的城市距离!这一方法最棒的地方就是,不管指数间的差距是1还是100000,只需一次计算就能算出任意两个指数间的距离。是不是很神奇?
我们用10万的数组和5万查询量创建了一个样本数据集。在下面的在线编程窗口中比较两种方法所需的时间。
注意:数据集总查询量为5万,你可以改变execute_queries参数,执行不超过5万的任一查询数量,看看每种方法完成任务所花费的时间。
最优化不仅能节省时间,大大加快完成速度,还能节省计算能力!
这些要怎么应用于数据科学项目呢?大家可能已经注意到了,很多时候需要对大量数据点进行相同查询,尤其是数据预处理阶段。
所以,在编程中运用最优化方法,从而尽可能快速有效地完成任务至关重要。以下就来分享几个提升优化Python代码的方法。
1. Pandas.apply() – 特征工程瑰宝
Pandas 库已经非常优化了,但是大部分人都没有发挥它的最大作用。想想它一般会用于数据科学项目中的哪些地方。
一般首先能想到的就是特征工程,即用已有特征创造新特征。其中最高效的方法之一就是Pandas.apply(),即Pandas中的apply函数。
在Pandas.apply()中,可以传递用户定义功能并将其应用到Pandas Series的所有数据点中。这个函数是Pandas库最好的扩展功能之一,它能根据所需条件分隔数据。之后便能将其有效应用到数据处理任务中。
试着用推特的情感分析数据来计算每条推文的字数吧。可以使用dataframe iterrows函数、NumPy程序库和apply函数等方法,再在下面的在线编程窗口中进行比较。
数据集可在此处下载:https://datahack.analyticsvidhya.com/contest/practice-problem-twitter-sentiment-analysis/?utm_source=blog&utm_medium=4-methods-optimize-python-code-data-science
apply比iterrows函数快多了。它的性能和NumPy类似,但是却更加灵活。
阅读更多文档:https://datahack.analyticsvidhya.com/contest/practice-problem-twitter-sentiment-analysis/?utm_source=blog&utm_medium=4-methods-optimize-python-code-data-science
2. Pandas.DataFrame.loc – Python数据操作绝妙技巧
所有和数据处理打交道的数据科学家(差不多所有人了!)都应该学会这个方法。
很多时候,数据科学家需要根据一些条件更新数据集中某列的某些值。Pandas.DataFrame.loc就是此类问题最优的解决方法。
试试用它来解决下面这个问题吧。
数据集可在此处下载:https://drive.google.com/file/d/1VwXDA27zgx5jIq8C7NQW0A5rtE95e3XI/view?usp=sharing
# importing libraries
import pandas as pd
data = pd.read_csv('school.csv')
data.head()
检查“City”变量的值计算:
现在,假设只需要排名前五位的城市,其他城市替换为“Others”,试着做一下:
# save the top cities in a list
top_cities = ['Brooklyn','Bronx','Manhattan','Jamaica','Long Island City']
# use loc to update the target
data.loc[(data.City.isin(top_cities) == False),'City'] = 'Others'
# city value counts
data.City.value_counts()
看到更新这些值有多简单了吗?完成此类数据操作任务最好的方法就是它了。
3. Python函数向量化
另一种解决缓慢循环的方法就是将函数向量化。这意味着新建函数会应用于输入列表,并返回结果数组。在Python中使用向量化能至少迭代两次,从而加速计算。
事实上,这样不仅能加速代码运算,还能让代码更加简洁清晰。
4. Python多重处理
多重处理能使系统同时支持一个以上的处理器。
此处将数据处理分成多个任务,让它们各自独立运行。处理庞大的数据集时,即使是apply函数也显得有些迟缓。
所以,来看看Python中的多重处理库怎么大显神通吧。
先随机创建一百万个点,然后计算每个点的除数。比较apply函数和多重处理完成这一任务的性能:
# importing required libraries
import pandas as pd
import math
import multiprocessing as mp
from random import randint
# function to calculate the number of divisors
def countDivisors(n) :
count = 0
for i in range(1, (int)(math.sqrt(n)) + 1) :
if (n % i == 0) :
if (n / i == i) :
count = count + 1
else :
count = count + 2
return count
# create random data
random_data = [randint(10,1000) for i in range(1,1000001)]
data = pd.DataFrame({'Number' : random_data })
data.shape
%%time
data['Number_of_divisor'] = data.Number.apply(countDivisors)
%%time
pool = mp.Pool(processes = (mp.cpu_count() - 1))
answer = pool.map(countDivisors,random_data)
pool.close()
pool.join()
这个问题中,多重处理生成的输出比apply函数快了13倍。它的性能可能会随着硬件系统不同而有所变化,但是必定会提升性能。
留言 点赞 关注
我们一起分享AI学习与发展的干货
如需转载,请后台留言,遵守转载规范