1. 前言
有经验的开发者都知道,整型计算、比较是计算机软件高级编程语言、数据库里较快的,对于Python及Pandas也不例外。
问题过程是这样的,按年月筛选数据集范围,更加较好的满足算法时序需求和计算效率。因此,在网络故障停止计算的紧张的空隙时间,及时优化代码。在优化代码过程中,为了减少代码修改,快速实现,直接使用原有数据字段没有进行类型强制转换,而是动态求值转换为字符串直接比较,结果,欲速则不达,计算效率大幅下降(少量数据调试代码,凭直觉看不出来)。
Python作为一门动态语言,其变量的类型可以自由变化。这个特性提高了代码的开发效率,却也增加了阅读代码和维护代码的难度。
2. 实验分析三种筛选数据集效率
为了准确定位计算效率问题,提高未来数据处理能力,筹备如下小实验,为优化代码提供参考依据。实验比较方法为:在pandas dataframe中,使用年月数据筛选数据集,比较方法如下:
- 整型数据比较筛选数据
- 整型数据字符串类型比较筛选数据
- 动态转换为整型字符串类型比较筛选数据。
其中,数据源为随机产生10000个“年月”(实际场景数据量是千万以上级别),进行10000次筛选,比较计算用时。
实验代码如下:
import pandas as pd
import datetime
import numpy as np
import random
from scipy import stats
x =[random.randint(2015,2030)*100+ random.randint(1,12) for j in range(10000)]
data = pd.DataFrame({'x':x})
data['sx'] = data['x'].astype(str)
print('整型数字比较')
now_time = datetime.datetime.now()
time_str = datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S.%f')
print(time_str)
for i in range(10000):
tmp = data.loc[data['x']>202001]
print('整型数字字符串比较')
now_time = datetime.datetime.now()
time_str = datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S.%f')
print(time_str)
for i in range(10000):
tmp = data.loc[data['sx']>'202001']
print('转换整型数字字符串比较')
now_time = datetime.datetime.now()
time_str = datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S.%f')
print(time_str)
for i in range(10000):
tmp = data.loc[data['sx']>((data['sx']+'01').astype('datetime64') + datetime.timedelta(days=-3*366)).dt.strftime('%Y%m').max()]
now_time = datetime.datetime.now()
time_str = datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S.%f')
print(time_str)
运行结果如下:
整型数字比较
2022-05-09 09:32:01.370711
整型数字字符串比较
2022-05-09 09:32:06.368290
转换整型数字字符串比较
2022-05-09 09:32:15.074743
2022-05-09 09:41:45.381319
3. 结论
3.1. 实验结果分析
对实验结果进行统计分析,在1万级别的数据量情况下,以整型数据比较筛选数据集用时为基准,数字字符串比较筛选数据集用时增加到172%,动态转换整型数字字符串比较筛选数据集用时增加到11408%。
3.2. 优化措施
- 数据输入、输出强制类型检查,转换为理想数据类型;
- 数据计算、比较尽量使用整型数据类型;
- 杜绝使用动态类型转换,提前对数据进行类型强制转换、计算处理。
例如增加变量定义和处理:
self.threeyearsbefore = datetime.datetime.strptime(self.end,'%Y-%m-%d %H:%M:%S') + datetime.timedelta(days=-3*366)
self.yearmonthbefore = int(self.threeyearsbefore.strftime('%Y%m'))
在程序体相应的使用点,修改相应引用。
3.3. 实验应用效果
计算效率有所提升。
|