[英]Speed up datetime conversion to mixed time zones - Python pandas
注意:这是这个问题的后续。
问题摘要:我有一个带有 UNIX 时间戳的 Pandas 数据框,没有任何时间信息。 我需要将这些转换为特定的时区(然后使它们成为时区幼稚对象)。 问题是将这种转换作为对每一行的迭代进行非常密集,目前约占我处理时间的 60%(在这个简化的示例中甚至更多)。 我相信这可以通过使用额外的 Pandas 日期时间功能来减少,但我很难弄清楚如何做到这一点。 为了扩大规模,我需要在数千个文件上运行代码,每个文件都有几个/几百万个观察值。
例子:
import pandas as pd
import time
#creating data:
n_obs=750000 # need to be a multiple of 15
l1=[1546555701, 1546378818, 1546574677, 1546399159, 1546572278]
l2=['America/Detroit','America/Chicago','America/Los_Angeles']
c1=l1*(int(n_obs/5))
c2=l2*(int(n_obs/3))
df=pd.DataFrame(list(zip(c1,c2)),columns=['timestamp','tz'])
print(df)
# operations:
sort_dict={}
tz_list=df['tz'].unique()
for x in tz_list:
df_temp=df[df['tz']==x]
sort_dict[x]=df_temp
def setTZ(row,x):
return row['date_time'].tz_convert(x).replace(tzinfo=None)
for x in [tz_list[0]]: # I just time the first iteration of the loop for simplicity
tic = time.perf_counter()
sort_dict[x]['date_time']=pd.to_datetime(df['timestamp'],unit='s',utc=True)
toc = time.perf_counter()
print(f'to_datetime() completed in {toc-tic:0.4f} seconds')
# the above works quite quickly, but the problem is in the following lines:
tic = time.perf_counter()
sort_dict[x]['date_time']=sort_dict[x].apply(lambda row: setTZ(row,x), axis=1)
toc = time.perf_counter()
print(f'setTZ() completed in {toc-tic:0.4f} seconds')
tic = time.perf_counter()
sort_dict[x]['date']=sort_dict[x].apply(lambda row: row['date_time'].date(),axis=1)
toc = time.perf_counter()
print(f'create date column with .date() completed in {toc-tic:0.4f} seconds')
tic = time.perf_counter()
sort_dict[x]['time']=sort_dict[x].apply(lambda row: row['date_time'].time(),axis=1)
toc = time.perf_counter()
print(f'create time column with .time() completed in {toc-tic:0.4f} seconds')
输出:
to_datetime() completed in 0.0311 seconds
setTZ() completed in 26.3287 seconds
create date column with .date() completed in 3.2471 seconds
create time column with .time() completed in 3.2625 seconds
# I also have a SettingWithCopyWarning error from my code, which I think comes from how I'm overwriting the dictionaries
要点: setTZ() 函数非常慢。 我认为这是因为我正在逐行迭代代码以进行此转换。 to_datetime() 非常快。 如果有一种方法可以合并时区并失去时间感知(因为我将跨时区同时比较观察结果),那将是理想的。 与 to_datetime() 函数相比,创建日期和时间列较慢,但相对于 setTZ() 函数而言较快。 优化这些会很好。
可能的解决方案:我猜我可以利用一些熊猫的日期时间函数,例如 tz_localize() 和 tz_convert(),但我需要能够将我的熊猫数据帧的列转换为日期时间数组。 我不清楚我该怎么做。 我相信其他解决方案也存在。
给定一个如上所述的数据框并扩展到中等的 50k 行
from datetime import datetime
from backports.zoneinfo import ZoneInfo # backports not needed with Python 3.9
import pandas as pd
c1 = [1546555701, 1546378818, 1546574677, 1546399159, 1546572278]*10000
c2 = ['America/Detroit','America/Chicago','America/Los_Angeles','America/Los_Angeles','America/Detroit']*10000
df3 = pd.DataFrame({'utc': c1, 'tz': c2})
df3['datetime'] = pd.to_datetime(df3['utc'], unit='s', utc=True)
除了迭代使用tz_convert
内置tz_convert
,您还可以使用Pandas 的 itertuples + Python 的datetime和zoneinfo的列表理解:
def toLocalTime_pd(row): # as given
return row['datetime'].tz_convert(row['tz']).replace(tzinfo=None)
def localTime_dt(df):
return [datetime.fromtimestamp(row.utc, tz=ZoneInfo(row.tz)).replace(tzinfo=None) for row in df.itertuples()]
在直接比较中,对于合成示例 df,列表 comp 的性能提高了 ~x8 :
%timeit df3.apply(lambda r: toLocalTime_pd(r), axis=1)
1.85 s ± 17.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit localTime_dt(df3)
217 ms ± 7.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.