pandas 半小时四舍五入
Round up half of the hour in pandas
round()
pandas 中的函数将时间 07:30 舍入到 07:00 但我想舍入超过 30 分钟(含)的任何时间。
例如
07:15 to 07:00
05:25 to 05:00
22:30 to 23:00
18:45 to 19:00
如何使用 pandas 为数据框的一列实现此目的?
时间戳
您需要使用 dt.round
。然而,这有点像 previous/next 小时行为取决于小时本身。你可以通过增加或减少少量时间(这里是 1ns)来强制它:
s = pd.to_datetime(pd.Series(['1/2/2021 3:45', '25/4/2021 12:30',
'25/4/2021 13:30', '12/4/2022 23:45']))
# xx:30 -> rounding depending on the hour parity (default)
s.dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00 <- -30min
2 2021-04-25 14:00:00 <- +30min
3 2022-12-05 00:00:00
dtype: datetime64[ns]
# 00:30 -> 00:00 (force down)
s.sub(pd.Timedelta('1ns')).dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00
2 2021-04-25 13:00:00
3 2022-12-05 00:00:00
dtype: datetime64[ns]
# 00:30 -> 01:00 (force up)
s.add(pd.Timedelta('1ns')).dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00
2 2021-04-25 13:00:00
3 2022-12-05 00:00:00
dtype: datetime64[ns]
浮动
IIUC,可以用divmod
(or numpy.modf
)得到整数和小数部分,然后进行简单的布尔运算:
s = pd.Series([7.15, 5.25, 22.30, 18.45])
s2, r = s.divmod(1) # or np.modf(s)
s2[r.ge(0.3)] += 1
s2 = s2.astype(int)
备选方案:使用 mod
和 boolean 到 int 等价:
s2 = s.astype(int)+s.mod(1).ge(0.3)
输出:
0 7
1 5
2 23
3 19
dtype: int64
注意精度。由于浮点运算,比较浮点数并不总是那么容易。例如,使用 gt
会在此处的 22.30 失败。为确保精度先舍入到2位。
s.mod(1).round(2).ge(0.3)
或使用整数:
s.mod(1).mul(100).astype(int).ge(30)
这里是一个使用时间戳的版本:
#dummy data:
df = pd.DataFrame({'time':pd.to_datetime([np.random.randint(0,10**8) for a in range(10)], unit='s')})
def custom_round(df, col, out):
if df[col].minute >= 30:
df[out] = df[col].ceil('H')
else:
df[out] = df[col].floor('H')
return df
df.apply(lambda x: custom_round(x, 'time', 'new_time'), axis=1)
#编辑:
使用 numpy:
def custom_round(df, col, out):
df[out] = np.where(
(
df['time'].dt.minute>=30),
df[col].dt.ceil('H'),
df[col].dt.floor('H')
)
return df
df = custom_round(df, 'time', 'new_time')
round()
pandas 中的函数将时间 07:30 舍入到 07:00 但我想舍入超过 30 分钟(含)的任何时间。
例如
07:15 to 07:00
05:25 to 05:00
22:30 to 23:00
18:45 to 19:00
如何使用 pandas 为数据框的一列实现此目的?
时间戳
您需要使用 dt.round
。然而,这有点像 previous/next 小时行为取决于小时本身。你可以通过增加或减少少量时间(这里是 1ns)来强制它:
s = pd.to_datetime(pd.Series(['1/2/2021 3:45', '25/4/2021 12:30',
'25/4/2021 13:30', '12/4/2022 23:45']))
# xx:30 -> rounding depending on the hour parity (default)
s.dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00 <- -30min
2 2021-04-25 14:00:00 <- +30min
3 2022-12-05 00:00:00
dtype: datetime64[ns]
# 00:30 -> 00:00 (force down)
s.sub(pd.Timedelta('1ns')).dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00
2 2021-04-25 13:00:00
3 2022-12-05 00:00:00
dtype: datetime64[ns]
# 00:30 -> 01:00 (force up)
s.add(pd.Timedelta('1ns')).dt.round(freq='1h')
0 2021-01-02 04:00:00
1 2021-04-25 12:00:00
2 2021-04-25 13:00:00
3 2022-12-05 00:00:00
dtype: datetime64[ns]
浮动
IIUC,可以用divmod
(or numpy.modf
)得到整数和小数部分,然后进行简单的布尔运算:
s = pd.Series([7.15, 5.25, 22.30, 18.45])
s2, r = s.divmod(1) # or np.modf(s)
s2[r.ge(0.3)] += 1
s2 = s2.astype(int)
备选方案:使用 mod
和 boolean 到 int 等价:
s2 = s.astype(int)+s.mod(1).ge(0.3)
输出:
0 7
1 5
2 23
3 19
dtype: int64
注意精度。由于浮点运算,比较浮点数并不总是那么容易。例如,使用 gt
会在此处的 22.30 失败。为确保精度先舍入到2位。
s.mod(1).round(2).ge(0.3)
或使用整数:
s.mod(1).mul(100).astype(int).ge(30)
这里是一个使用时间戳的版本:
#dummy data:
df = pd.DataFrame({'time':pd.to_datetime([np.random.randint(0,10**8) for a in range(10)], unit='s')})
def custom_round(df, col, out):
if df[col].minute >= 30:
df[out] = df[col].ceil('H')
else:
df[out] = df[col].floor('H')
return df
df.apply(lambda x: custom_round(x, 'time', 'new_time'), axis=1)
#编辑:
使用 numpy:
def custom_round(df, col, out):
df[out] = np.where(
(
df['time'].dt.minute>=30),
df[col].dt.ceil('H'),
df[col].dt.floor('H')
)
return df
df = custom_round(df, 'time', 'new_time')