【问题标题】:Convert a column of datetimes to epoch in Python在 Python 中将一列日期时间转换为纪元
【发布时间】:2016-06-08 09:25:08
【问题描述】:

我目前遇到了 Python 问题。我有一个 Pandas DataFrame,其中一列是一个带日期的字符串。 格式为:

“%Y-%m-%d %H:%m:00.000”。例如:“2011-04-24 01:30:00.000”

我需要将整列转换为整数。我试图运行这段代码,但它非常慢,而且我有几百万行。

    for i in range(calls.shape[0]):
        calls['dateint'][i] = int(time.mktime(time.strptime(calls.DATE[i], "%Y-%m-%d %H:%M:00.000")))

你们知道如何将整列转换为纪元时间吗?

提前致谢!

【问题讨论】:

    标签: python datetime pandas epoch


    【解决方案1】:

    使用to_datetime 将字符串转换为datetime,然后减去日期时间1970-1-1 并调用dt.total_seconds()

    In [2]:
    import pandas as pd
    import datetime as dt
    df = pd.DataFrame({'date':['2011-04-24 01:30:00.000']})
    df
    
    Out[2]:
                          date
    0  2011-04-24 01:30:00.000
    
    In [3]:
    df['date'] = pd.to_datetime(df['date'])
    df
    
    Out[3]:
                     date
    0 2011-04-24 01:30:00
    
    In [6]:    
    (df['date'] - dt.datetime(1970,1,1)).dt.total_seconds()
    
    Out[6]:
    0    1303608600
    Name: date, dtype: float64
    

    您可以看到将这个值转换回产生相同的时间:

    In [8]:
    pd.to_datetime(1303608600, unit='s')
    
    Out[8]:
    Timestamp('2011-04-24 01:30:00')
    

    因此您可以添加新列或覆盖:

    In [9]:
    df['epoch'] = (df['date'] - dt.datetime(1970,1,1)).dt.total_seconds()
    df
    
    Out[9]:
                     date       epoch
    0 2011-04-24 01:30:00  1303608600
    

    编辑

    @Jeff 建议的更好方法:

    In [3]:
    df['date'].astype('int64')//1e9
    
    Out[3]:
    0    1303608600
    Name: date, dtype: float64
    
    In [4]:
    %timeit (df['date'] - dt.datetime(1970,1,1)).dt.total_seconds()
    %timeit df['date'].astype('int64')//1e9
    
    100 loops, best of 3: 1.72 ms per loop
    1000 loops, best of 3: 275 µs per loop
    

    您还可以看到它明显更快

    【讨论】:

    • 感谢您的回答!它工作得很好,而且比 for 循环快得多!
    • df.date.astype('int64')//1e9,虽然有点模糊
    • @GandalfSaxe 这是datetime 属性来访问类似日期时间的属性
    • @GandalfSaxe 啊,这是datetime 模块的别名:import datetime as dt 将更新以明确这一点
    • Ed:您可能已经注意到了,但是有一个 Meta 帖子要感谢您的 100K 评论:Congratulations to EdChum for 100,000 close reviews!。恭喜,谢谢!
    【解决方案2】:

    我知道这很旧,但我相信正确(也是最干净)的方法是下面的单行:

    calls['DATE'].apply(lambda x: x.timestamp())
    

    这假定calls['DATE']datetime64[ns] 类型。如果没有,请使用:

    pd.to_datetime(calls['DATE'], format="%Y-%m-%d %H:%m:00.000")
    

    说明

    要获取pd.Timestamp 的纪元值(以秒为单位),请使用:

    pd.Timestamp('20200101').timestamp()
    

    这应该给你1577836800.0。如果需要,您可以转换为 int。它是浮点数的原因是因为任何亚秒级时间都将在小数部分。

    为了完整起见,您还可以使用以下方法获取原始纪元值(以纳秒为单位):

    pd.Timestamp('20200101').value
    

    给出 1577836800000000000,这是上述日期的纪元。 .value 属性是自纪元以来的纳秒数,因此我们除以 1e6 得到毫秒。如果您希望以秒为单位的纪元作为第一次调用,请除以 1e9。

    【讨论】:

      【解决方案3】:

      来自Pandas documentation 处理时间序列数据:

      我们减去纪元(UTC 时间 1970 年 1 月 1 日午夜),然后除以“单位”(1 毫秒)。

      # generate some timestamps
      stamps = pd.date_range('2012-10-08 18:15:05', periods=4, freq='D')
      
      # convert it to milliseconds from epoch
      (stamps - pd.Timestamp("1970-01-01")) // pd.Timedelta('1ms')
      

      这将以毫秒为单位给出纪元时间。

      【讨论】:

        【解决方案4】:

        为了扩展 s5s 的答案,我认为代码可以进一步泛化以适应丢失的数据(例如,由 pd.NaT 表示)。在 Pandas 1.2.4 上测试,不适用于 Pandas

        calls['DATE'].apply(lambda x: x.timestamp() if not pd.isna(x) else pd.NA).astype('Int64')
        

        一些cmets:

        • pd.isna() 将捕获 pd.NaT

        • lambda 表达式将 pd.NaT 转换为 pd.NA,这将是缺失数据的新表示

        • 最后,lambda 表达式的输出将是整数和 pd.NA 的混合,因此我们需要像 Int64 这样的 Pandas ExtensionDtype 来处理它

        示例输出:

        0            <NA>
        1            <NA>
        2            <NA>
        3            <NA>
        4            <NA>
                  ...
        865    1619136000
        866    1619136000
                  ...
        Name: DATE, Length: 870, dtype: Int64
        

        【讨论】:

          猜你喜欢
          • 2018-04-24
          • 2011-12-06
          • 2017-02-28
          • 1970-01-01
          • 2012-09-06
          • 2012-11-08
          • 2019-01-15
          • 2012-07-29
          • 2018-05-16
          相关资源
          最近更新 更多