如何在海量数据帧上提高lambda函数的性能

2024-06-25 23:37:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个超过数亿行的df

     latitude                    longitude                   time                    VAL     
0   -39.20000076293945312500    140.80000305175781250000    1972-01-19 13:00:00     1.20000004768371582031  
1   -39.20000076293945312500    140.80000305175781250000    1972-01-20 13:00:00     0.89999997615814208984 
2   -39.20000076293945312500    140.80000305175781250000    1972-01-21 13:00:00     1.50000000000000000000 
3   -39.20000076293945312500    140.80000305175781250000    1972-01-22 13:00:00     1.60000002384185791016 
4   -39.20000076293945312500    140.80000305175781250000    1972-01-23 13:00:00     1.20000004768371582031
... ...

它包含一个time列,其类型为UTC中的datetime64。下面的代码将创建一个新列isInDST,以指示time是否处于本地时区的夏令时

df['isInDST'] = pd.DatetimeIndex(df['time']).tz_localize('UTC').tz_convert('Australia/Victoria').map(lambda x : x.dst().total_seconds()!=0)

处理15223160行大约需要400秒

是否有更好的方法以更好的性能实现这一点?{}是更好的方法吗


Tags: 方法代码类型dftimevaltzpd
1条回答
网友
1楼 · 发布于 2024-06-25 23:37:09

所有结果都是在1M数据点上计算的

Cython+np.vectorize

比原始代码快7.2倍

%%cython
from cpython.datetime cimport datetime
cpdef bint c_is_in_dst(datetime dt):
    return dt.dst().total_seconds() != 0 

%%timeit
df['isInDST'] = np.vectorize(c_is_in_dst)(df['time'].dt.tz_localize('UTC').dt.tz_convert('Australia/Victoria').dt.to_pydatetime())

1.08 s±10.2 ms/圈/圈

np.vectorize

比原始代码快6.5倍

def is_in_dst(dt):
    return dt.dst().total_seconds() != 0 

%%timeit
df['isInDST'] = np.vectorize(is_in_dst)(df['time'].dt.tz_localize('UTC').dt.tz_convert('Australia/Victoria').dt.to_pydatetime())

1.2 s±29.3 ms/圈/圈

基于documentationThe implementation is essentially a for loop),我期望结果与列表理解的结果相同,但始终比列表理解好一点

列表理解

比原始代码快5.9倍

%%timeit
df['isInDST'] = [x.dst().total_seconds()!=0 for x in pd.DatetimeIndex(df['time']).tz_localize('UTC').tz_convert('Australia/Victoria')]

1.33 s±48.4 ms/回路

这个结果表明pandasmap/apply非常慢,它增加了额外的开销,只需使用python for循环就可以消除这些开销

原始方法(map在DatetimeIndex上)

%%timeit
df['isInDST'] = pd.DatetimeIndex(df['time']).tz_localize('UTC').tz_convert('Australia/Victoria').map(lambda x : x.dst().total_seconds()!=0)

7.82 s±84.3 ms/回路

在1M行虚拟数据上进行测试

N = 1_000_000
df = pd.DataFrame({"time": [datetime.datetime.now().replace(hour=random.randint(0,23),minute=random.randint(0,59)) for _ in range(N)]})

另外,在100K和10M行上运行代码-结果与行数成线性关系

相关问题 更多 >