Python Pandas日期时间序列转换为自纪元以来的秒数

9

在遵循这个回答的精神下,我尝试将一个DataFrame列中的日期时间转换为自纪元以来的秒数列。

df['date'] = (df['date']+datetime.timedelta(hours=2)-datetime.datetime(1970,1,1))
df['date'].map(lambda td:td.total_seconds())

第二个命令导致以下错误,我不明白。这里有什么想法吗?我用 apply 替换了 map,但没有改善情况。
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-99-7123e823f995> in <module>()
----> 1 df['date'].map(lambda td:td.total_seconds())

/Users/cpd/.virtualenvs/py27-ipython+pandas/lib/python2.7/site-packages/pandas-0.12.0_937_gb55c790-py2.7-macosx-10.8-x86_64.egg/pandas/core/series.pyc in map(self, arg, na_action)
   1932             return self._constructor(new_values, index=self.index).__finalize__(self)
   1933         else:
-> 1934             mapped = map_f(values, arg)
   1935             return self._constructor(mapped, index=self.index).__finalize__(self)
   1936 

/Users/cpd/.virtualenvs/py27-ipython+pandas/lib/python2.7/site-packages/pandas-0.12.0_937_gb55c790-py2.7-macosx-10.8-x86_64.egg/pandas/lib.so in pandas.lib.map_infer (pandas/lib.c:43628)()

<ipython-input-99-7123e823f995> in <lambda>(td)
----> 1 df['date'].map(lambda td:td.total_seconds())

AttributeError: 'float' object has no attribute 'total_seconds'

似乎“日期”列一开始就不是datetime64类型? - Zeugma
1
该列是否包含任何缺失值?缺失值通常会导致pandas Series被转换为浮点数,在尝试将其解释为日期时间时会产生奇怪的结果。 - Abe
@Abe 确实你是对的。事实证明,一些记录中确实缺少数据。这不是我预期的... 唉。 - Chris
2个回答

15

更新:

在0.15.0版本中,Timedeltas成为了完整的数据类型。

因此,以下方法也变得可行。

In [45]: s = Series(pd.timedelta_range('1 day',freq='1S',periods=5))                         

In [46]: s.dt.components
Out[46]: 
   days  hours  minutes  seconds  milliseconds  microseconds  nanoseconds
0     1      0        0        0             0             0            0
1     1      0        0        1             0             0            0
2     1      0        0        2             0             0            0
3     1      0        0        3             0             0            0
4     1      0        0        4             0             0            0

In [47]: s.astype('timedelta64[s]')
Out[47]: 
0    86400
1    86401
2    86402
3    86403
4    86404
dtype: float64

我看到您正在使用主分支(0.13版本很快就要发布了),因此假设您的numpy版本大于等于1.7。请执行以下操作。有关文档,请参见此处(这是频率转换)。

In [5]: df = DataFrame(dict(date = date_range('20130101',periods=10)))

In [6]: df
Out[6]: 
                 date
0 2013-01-01 00:00:00
1 2013-01-02 00:00:00
2 2013-01-03 00:00:00
3 2013-01-04 00:00:00
4 2013-01-05 00:00:00
5 2013-01-06 00:00:00
6 2013-01-07 00:00:00
7 2013-01-08 00:00:00
8 2013-01-09 00:00:00
9 2013-01-10 00:00:00

In [7]: df['date']+timedelta(hours=2)-datetime.datetime(1970,1,1)
Out[7]: 
0   15706 days, 02:00:00
1   15707 days, 02:00:00
2   15708 days, 02:00:00
3   15709 days, 02:00:00
4   15710 days, 02:00:00
5   15711 days, 02:00:00
6   15712 days, 02:00:00
7   15713 days, 02:00:00
8   15714 days, 02:00:00
9   15715 days, 02:00:00
Name: date, dtype: timedelta64[ns]

In [9]: (df['date']+timedelta(hours=2)-datetime.datetime(1970,1,1)) / np.timedelta64(1,'s')
Out[9]: 
0    1357005600
1    1357092000
2    1357178400
3    1357264800
4    1357351200
5    1357437600
6    1357524000
7    1357610400
8    1357696800
9    1357783200
Name: date, dtype: float64

这些值包含在np.timedelta64[ns]对象中,它们不具有与timedelta对象相同的方法,因此没有total_seconds()方法。

In [10]: s = (df['date']+timedelta(hours=2)-datetime.datetime(1970,1,1))

In [11]: s[0]
Out[11]: numpy.timedelta64(1357005600000000000,'ns')

您可以将它们转换为整数,然后会得到一个 ns 单位。

In [12]: s[0].astype(int)
Out[12]: 1357005600000000000

你也可以这样做(但只能在单个元素上执行)。

In [18]: s[0].astype('timedelta64[s]')
Out[18]: numpy.timedelta64(1357005600,'s')

1
太好了Jeff,谢谢!一旦我清除了缺失数据的行,我就可以直接将这个应用到新问题上。;-) - Chris
不需要删除缺失值(NaT);它们将作为nan返回。 - Jeff
我现在没有时间编辑(和重新验证)答案,但实际上版本0.13现在允许将'astype'操作应用于整个Series。请参见http://pandas.pydata.org/pandas-docs/stable/timeseries.html#time-deltas-conversions,或http://pandas.pydata.org/pandas-docs/stable/whatsnew.html并在页面上查找“astype”。 - TimStaley
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - soupault
2
这个答案实际上已经过时了;Timedeltas在0.15.0中成为了完整的类型。我会添加另一种方法。 - Jeff

1

自从最近版本的 Pandas,您可以进行以下操作:

import pandas as pd

# create a dataframe from 2023-05-06 to 2023-06-04
df = pd.DataFrame({'date': pd.date_range('2023-05-26', periods=10, freq='D')})

df['timestamp'] = (df['date'].add(pd.DateOffset(hours=2))  # add hour offset
                             .sub(pd.Timestamp(0))  # subtract 1970-1-1
                             .dt.total_seconds()  # extract total of seconds
                             .astype(int))  # downcast float64 to int64

输出:

>>> df
        date   timestamp
0 2023-05-26  1685066400
1 2023-05-27  1685152800
2 2023-05-28  1685239200
3 2023-05-29  1685325600
4 2023-05-30  1685412000
5 2023-05-31  1685498400
6 2023-06-01  1685584800
7 2023-06-02  1685671200
8 2023-06-03  1685757600
9 2023-06-04  1685844000

关键是从每个日期(DatetimeIndex)中减去原点(pd.Timestamp(0)),然后使用dt访问器从结果(TimedeltaIndex)中提取秒数。您还可以将数字结果(float64)向下转换为int64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接