pandas 中的半小时四舍五入

发布于 01-20 22:30 字数 202 浏览 2 评论 0 原文

pandas 中的 round() 函数将时间 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 对数据框的列实现此目的?

round() function in pandas rounds down the time 07:30 to 07:00 But I want to round up any time which passes the 30 minutes (inclusive).

Eg.

07:15 to 07:00
05:25 to 05:00
22:30 to 23:00
18:45 to 19:00

How to achieve this for a column of a dataframe using pandas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡淡離愁欲言轉身 2025-01-27 22:30:28

时间戳

您需要使用 dt.round< /代码>。然而,这有点像前一小时/下一小时的行为取决于该小时本身。您可以通过添加或减去少量时间(此处为 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 (或 "="">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)

替代方案:使用 "=""> numpy.modf) 获取整数和小数部分,然后执行简单的布尔算术: pydata.org/docs/reference/api/pandas.Series.mod.html" rel="nofollow noreferrer">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)

timestamps

You need to use dt.round. This is however a bit as the previous/next hour behavior depends on the hour itself. You can force it by adding or subtracting a small amount of time (here 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]

floats

IIUC, you can use divmod (or numpy.modf) to get the integer and decimal part, then perform simple boolean arithmetic:

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)

Alternative: using mod and boolean to int equivalence:

s2 = s.astype(int)+s.mod(1).ge(0.3)

output:

0     7
1     5
2    23
3    19
dtype: int64

Note on precision. It is not always easy to compare floats due to floating point arithmetics. For instance using gt would fail on the 22.30 here. To ensure precision round to 2 digits first.

s.mod(1).round(2).ge(0.3)

or use integers:

s.mod(1).mul(100).astype(int).ge(30)
拥有 2025-01-27 22:30:28

这里是与时间戳合作的版本:

#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)

#edit:

使用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')

Here a version that works with timestamps:

#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)

#edit:

using 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')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文