【问题标题】:Pandas convert datetime with a separate time zone columnPandas 使用单独的时区列转换日期时间
【发布时间】:2017-01-31 11:53:08
【问题描述】:

我有一个数据框,其中有一列用于时区,一列用于日期时间。我想先将这些转换为 UTC 以加入其他数据,然后我将进行一些计算以最终从 UTC 转换为查看者本地时区。

datetime              time_zone
2016-09-19 01:29:13   America/Bogota 
2016-09-19 02:16:04   America/New_York
2016-09-19 01:57:54   Africa/Cairo

def create_utc(df, column, time_format='%Y-%m-%d %H:%M:%S'):
    timezone = df['TZ']
    df[column + '_utc'] = df[column].dt.tz_localize(timezone).dt.tz_convert('UTC').dt.strftime(time_format)
    df[column + '_utc'].replace('NaT', np.nan, inplace=True)
    df[column + '_utc'] = pd.to_datetime(df[column + '_utc'])
    return df

那是我有缺陷的尝试。错误在于事实是模棱两可的,这是有道理的,因为“时区”变量指的是一列。如何引用同一行中的值?

编辑:以下是一天数据(394,000 行和 22 个唯一时区)的以下答案的一些结果。 Edit2:我添加了一个 groupby 示例,以防有人想查看结果。这是迄今为止最快的。

%%timeit

for tz in df['TZ'].unique():
    df.ix[df['TZ'] == tz, 'datetime_utc2'] = df.ix[df['TZ'] == tz, 'datetime'].dt.tz_localize(tz).dt.tz_convert('UTC')
df['datetime_utc2'] = df['datetime_utc2'].dt.tz_localize(None)

1 loops, best of 3: 1.27 s per loop

%%timeit

df['datetime_utc'] = [d['datetime'].tz_localize(d['TZ']).tz_convert('UTC') for i, d in df.iterrows()]
df['datetime_utc'] = df['datetime_utc'].dt.tz_localize(None)

1 loops, best of 3: 50.3 s per loop

df['datetime_utc'] = pd.concat([d['datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') for tz, d in df.groupby('TZ')])



**1 loops, best of 3: 249 ms per loop**

【问题讨论】:

    标签: python pandas pytz


    【解决方案1】:

    这是一种矢量化方法(它将循环df.time_zone.nunique() 次):

    In [2]: t
    Out[2]:
                 datetime         time_zone
    0 2016-09-19 01:29:13    America/Bogota
    1 2016-09-19 02:16:04  America/New_York
    2 2016-09-19 01:57:54      Africa/Cairo
    3 2016-09-19 11:00:00    America/Bogota
    4 2016-09-19 12:00:00  America/New_York
    5 2016-09-19 13:00:00      Africa/Cairo
    
    In [3]: for tz in t.time_zone.unique():
       ...:         mask = (t.time_zone == tz)
       ...:         t.loc[mask, 'datetime'] = \
       ...:             t.loc[mask, 'datetime'].dt.tz_localize(tz).dt.tz_convert('UTC')
       ...:
    
    In [4]: t
    Out[4]:
                 datetime         time_zone
    0 2016-09-19 06:29:13    America/Bogota
    1 2016-09-19 06:16:04  America/New_York
    2 2016-09-18 23:57:54      Africa/Cairo
    3 2016-09-19 16:00:00    America/Bogota
    4 2016-09-19 16:00:00  America/New_York
    5 2016-09-19 11:00:00      Africa/Cairo
    

    更新:

    In [12]: df['new'] = df.groupby('time_zone')['datetime'] \
                           .transform(lambda x: x.dt.tz_localize(x.name))
    
    In [13]: df
    Out[13]:
                 datetime         time_zone                 new
    0 2016-09-19 01:29:13    America/Bogota 2016-09-19 06:29:13
    1 2016-09-19 02:16:04  America/New_York 2016-09-19 06:16:04
    2 2016-09-19 01:57:54      Africa/Cairo 2016-09-18 23:57:54
    3 2016-09-19 11:00:00    America/Bogota 2016-09-19 16:00:00
    4 2016-09-19 12:00:00  America/New_York 2016-09-19 16:00:00
    5 2016-09-19 13:00:00      Africa/Cairo 2016-09-19 11:00:00
    

    【讨论】:

    • 我将投票作为答案。对于超过 320k 行,我的速度低于 1 秒,而其他答案的速度则接近 1 分钟。我只是希望有人也分享一个 groupby sn-p 我也可以测试。
    • 您好,我不知道“名称”列的来源?在 tz_localize(x.name) 谢谢
    • 另外我没有得到和你一样的格式。我得到了 UTC 信息:2020-07-20 20:30:00-07:00
    • 这段代码似乎对我有用,但我也对“x.name”部分感到困惑。 .name 在做什么? (我的猜测是它调用了 groupby 名称字符串,但我不确定,因为我没有找到文档,也不知道如何测试这种情况)。谢谢!
    • @amquack,试试这个:df.groupby('time_zone')['datetime'].apply(lambda x: print(x.name)) ;)
    【解决方案2】:

    您的问题是 tz_localize() 只能采用标量值,因此我们必须遍历 DataFrame:

    df['datetime_utc'] = [d['datetime'].tz_localize(d['time_zone']).tz_convert('UTC') for i,d in df.iterrows()]
    

    结果是:

                datetime         time_zone              datetime_utc
    0 2016-09-19 01:29:13    America/Bogota 2016-09-19 06:29:13+00:00
    1 2016-09-19 02:16:04  America/New_York 2016-09-19 06:16:04+00:00
    2 2016-09-19 01:57:54      Africa/Cairo 2016-09-18 23:57:54+00:00
    

    另一种方法是按时区分组并一次转换所有匹配的行:

    df['datetime_utc'] = pd.concat([d['datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') for tz, d in df.groupby('time_zone')])
    

    【讨论】:

    • 让我试试这个。我只是没有时间枚举或迭代。我只是不知道什么时候使用这些命令
    • 这样做的方法是在 time_zone 上进行转换并转换所有该区域 - iirc 我在一个 SO 问题中解决了这个问题一次
    • 我试图查看您的回答历史记录,但没有看到。上面的方法似乎有效,但如果你找到了 groupby 示例,那会很酷。我每月要对大约 200 万行执行此操作,因此最好测试每种方法的速度
    • @trench,你的 200 万有多少个独特的时区。行 DF? print(df.time_zone.nunique()) - 应该给你一个号码...
    • 我查了前几天的一些数据,有32个。
    猜你喜欢
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 2016-10-05
    • 2021-11-15
    • 2021-05-30
    相关资源
    最近更新 更多