我有一个经常变化的熊猫数据帧,看起来像这样:
date name time timezone
0 2016-08-01 aaa 0900 Asia/Tokyo
1 2016-08-04 bbb 1200 Europe/Berlin
2 2016-08-05 ccc 1400 Europe/London
日期、时间和时区是指通常针对海外地点的交货日期,名称是客户公司的名称。
计划是获取此数据并创建一个datetime_local
列,其中包含数据帧timezone
列中显示的时区。然后,我想添加一个包含该日期和时间的列datetime_london
,但以伦敦的时间和日期表示。
我已经完成了大部分工作,但是当打电话给tz_localize
时,我最终得到了一个ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()
,这对我来说表明我没有正确处理时区的列。
关于如何进行的任何建议?
mydf = pd.DataFrame(data={'date':['2016-08-01','2016-08-04','2016-08-05'],
'time':['0900','1200','1400'],
'timezone':['Asia/Tokyo','Europe/Berlin','Europe/London'],
'name':['aaa','bbb','ccc']}
)
print(mydf)
mydf["datetime"] = mydf["date"].map(str) + " " + mydf["time"]
mydf.datetime = pd.to_datetime(mydf.datetime)
mydf.index = mydf.datetime
print(mydf)
mydf["datetime_local"] = mydf.datetime
mydf.datetime_local.tz_localize(mydf.timezone)
虽然前面的答案非常有效,但当面对处理大数据的问题时,应用方法有点低效(对于 10^6 个数量级的行)。逐行处理应用方法需要我 10-15 分钟来处理该规模。如果时区列的唯一值比率非常小,则与数据帧中的行数相比,此代码的效率要高得多:
for tz in df['timezone'].unique(): #iterates over each unique value of timezone in the dataframe
mask = df['timezone'] == tz #selects all rows with current unique tz value
df.loc[mask,'datetime_local'] = pd.DatetimeIndex(df.loc[mask, 'datetime']).tz_localize('UTC').tz_convert(tz)
最后一行代码将datetime
列转换为 DatetimeIndex
,这使得它datetime
UTC 和 tz-naive
(如果还没有)。因此,tz_localize('UTC')
是必需的,因为tz_convert
不适用于tz-naive
日期时间。
我知道这是一个古老的问题,但我真的需要一个更快的解决方案,我认为我的答案可能会帮助那些追随我的人。
import pandas as pd
def convert_to_local_time(row):
return pd.to_datetime(row.datetime).tz_localize(row.timezone)
def convert_to_london_time(row):
return pd.to_datetime(row.datetime_local).tz_convert('Europe/London')
mydf = pd.DataFrame(data={'date':['2016-08-01','2016-08-04','2016-08-05'],
'time':['0900','1200','1400'],
'timezone':['Asia/Tokyo','Europe/Berlin','Europe/ London'],
'name':['aaa','bbb','ccc']}
)
print(mydf)
输出:
date name time timezone
0 2016-08-01 aaa 0900 Asia/Tokyo
1 2016-08-04 bbb 1200 Europe/Berlin
2 2016-08-05 ccc 1400 Europe/London
添加datetime_local
列
mydf["datetime"] = mydf["date"].map(str) + " " + mydf["time"]
mydf['datetime_local'] = mydf.apply(convert_to_local_time, axis=1)
print(mydf)
输出:
date name time timezone datetime
0 2016-08-01 aaa 0900 Asia/Tokyo 2016-08-01 0900
1 2016-08-04 bbb 1200 Europe/Berlin 2016-08-04 1200
2 2016-08-05 ccc 1400 Europe/London 2016-08-05 1400
datetime_local
0 2016-08-01 09:00:00+09:00
1 2016-08-04 12:00:00+02:00
2 2016-08-05 14:00:00+01:00
添加datetime_london
列
mydf['datetime_london'] = mydf.apply(convert_to_london_time, axis=1)
print('After adding datetime_london:')
print(mydf)
输出:
date name time timezone datetime
0 2016-08-01 aaa 0900 Asia/Tokyo 2016-08-01 0900
1 2016-08-04 bbb 1200 Europe/Berlin 2016-08-04 1200
2 2016-08-05 ccc 1400 Europe/London 2016-08-05 1400
datetime_local datetime_london
0 2016-08-01 09:00:00+09:00 2016-08-01 01:00:00+01:00
1 2016-08-04 12:00:00+02:00 2016-08-04 11:00:00+01:00
2 2016-08-05 14:00:00+01:00 2016-08-05 14:00:00+01:00
试试这个:
In [12]: mydf.apply(lambda x: x.datetime_local.tz_localize(x.timezone), axis=1)
Out[12]:
datetime
2016-08-01 09:00:00 2016-08-01 09:00:00+09:00
2016-08-04 12:00:00 2016-08-04 12:00:00+02:00
2016-08-05 14:00:00 2016-08-05 14:00:00+01:00
dtype: object