将一列日期时间转换为 Python 中的纪元
Convert a column of datetimes to epoch in Python
我目前遇到 Python 的问题。我有一个 Pandas DataFrame,其中一列是带有日期的字符串。
格式为:
"%Y-%m-%d %H:%m:00.000". For example : "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")))
你们知道如何将整个列转换为纪元时间吗?
提前致谢!
使用 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
您还可以看到它明显更快
来自Pandas documentation关于处理时间序列数据的文章:
We subtract the epoch (midnight at January 1, 1970 UTC) and then floor divide by the “unit” (1 ms).
# 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')
这将给出以毫秒为单位的纪元时间。
我知道这是旧的,但我相信正确(和最干净)的方法是下面的一行:
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。
为了扩展 s5s 的答案,我认为代码可以进一步泛化以适应丢失的数据(例如,由 pd.NaT 表示)。在 Pandas 1.2.4 上测试,不适用于 Pandas < 1.0.
calls['DATE'].apply(lambda x: x.timestamp() if not pd.isna(x) else pd.NA).astype('Int64')
一些评论:
pd.isna() 会赶上 pd.NaT
lambda 表达式将 pd.NaT 转换为 pd.NA,这将是缺失数据的新表示形式
最后,lambda 表达式的输出将是整数和 pd.NA 的混合,因此我们需要 Pandas ExtensionDtype 例如 Int64 来处理
示例输出:
0 <NA>
1 <NA>
2 <NA>
3 <NA>
4 <NA>
...
865 1619136000
866 1619136000
...
Name: DATE, Length: 870, dtype: Int64
我目前遇到 Python 的问题。我有一个 Pandas DataFrame,其中一列是带有日期的字符串。 格式为:
"%Y-%m-%d %H:%m:00.000". For example : "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")))
你们知道如何将整个列转换为纪元时间吗?
提前致谢!
使用 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
您还可以看到它明显更快
来自Pandas documentation关于处理时间序列数据的文章:
We subtract the epoch (midnight at January 1, 1970 UTC) and then floor divide by the “unit” (1 ms).
# 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')
这将给出以毫秒为单位的纪元时间。
我知道这是旧的,但我相信正确(和最干净)的方法是下面的一行:
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。
为了扩展 s5s 的答案,我认为代码可以进一步泛化以适应丢失的数据(例如,由 pd.NaT 表示)。在 Pandas 1.2.4 上测试,不适用于 Pandas < 1.0.
calls['DATE'].apply(lambda x: x.timestamp() if not pd.isna(x) else pd.NA).astype('Int64')
一些评论:
pd.isna() 会赶上 pd.NaT
lambda 表达式将 pd.NaT 转换为 pd.NA,这将是缺失数据的新表示形式
最后,lambda 表达式的输出将是整数和 pd.NA 的混合,因此我们需要 Pandas ExtensionDtype 例如 Int64 来处理
示例输出:
0 <NA>
1 <NA>
2 <NA>
3 <NA>
4 <NA>
...
865 1619136000
866 1619136000
...
Name: DATE, Length: 870, dtype: Int64