仅使用现有日期列中的小时数来对新pandas列进行矢量化计算

时间:2018-01-22 15:32:42

标签: python pandas datetime dataframe

我有什么:

  • 包含日期
  • 的列的pandas数据框
  • Python 3.6

我想要的是什么:

  • 计算新列,其中每行的新值仅取决于同一行的现有列中日期的一部分(例如,仅取决于日期的小时的操作)
  • 以有效的方式(思考,矢量化)这样做,而不是逐行计算。

示例数据框(小数据帧便于打印,但我也有一个实际的用例,我可以分享更大的数据框,但可以用来计时不同的解决方案):

import numpy as np
import pandas as pd
from datetime import datetime
from datetime import timedelta

df = pd.DataFrame({'Date': np.arange(datetime(2000,1,1), 
                                     datetime(2000,1,2), 
                                     timedelta(hours=3)).astype(datetime)})
print(df)

给出了:

                 Date
0 2000-01-01 00:00:00
1 2000-01-01 03:00:00
2 2000-01-01 06:00:00
3 2000-01-01 09:00:00
4 2000-01-01 12:00:00
5 2000-01-01 15:00:00
6 2000-01-01 18:00:00
7 2000-01-01 21:00:00

现有解决方案(太慢)

df['SinHour'] = df.apply(
    lambda row: np.sin((row.Date.hour + float(row.Date.minute) / 60.0) * np.pi / 12.0), 
    axis=1)
print(df)

给出了:

                 Date       SinHour
0 2000-01-01 00:00:00  0.000000e+00
1 2000-01-01 03:00:00  7.071068e-01
2 2000-01-01 06:00:00  1.000000e+00
3 2000-01-01 09:00:00  7.071068e-01
4 2000-01-01 12:00:00  1.224647e-16
5 2000-01-01 15:00:00 -7.071068e-01
6 2000-01-01 18:00:00 -1.000000e+00
7 2000-01-01 21:00:00 -7.071068e-01

我说这个解决方案太慢了,因为它逐行计算列中的每个值。当然,如果这真的是唯一的可能性,我将不得不满足于此。然而,在功能更简单的情况下,我通过使用矢量化numpy函数获得了巨大的加速,我希望在这里也可以采用某种方式。

所需解决方案的方向(不起作用):

我希望能够做到这样的事情:

df = df.assign(
    SinHour=lambda data: np.sin((data.Date.hour + float(data.Date.minute) / 60.0)
    * np.pi / 12.0))

这是我希望进入的方向,因为它不再是逐行apply。但是,它显然不起作用,因为它无法在"矢量化"中立即访问整个Date列的hourminute属性。方式。

1 个答案:

答案 0 :(得分:1)

你真的很接近,只需要.dt来处理datetime s Series和投标astype

df = df.assign(SinHour=np.sin((df.Date.dt.hour + 
                              (df.Date.dt.minute).astype(float) / 60.0) * np.pi / 12.0)
               )
print(df)
                 Date       SinHour
0 2000-01-01 00:00:00  0.000000e+00
1 2000-01-01 03:00:00  7.071068e-01
2 2000-01-01 06:00:00  1.000000e+00
3 2000-01-01 09:00:00  7.071068e-01
4 2000-01-01 12:00:00  1.224647e-16
5 2000-01-01 15:00:00 -7.071068e-01
6 2000-01-01 18:00:00 -1.000000e+00
7 2000-01-01 21:00:00 -7.071068e-01