根据下限/上限条件,将 pandas 列值四舍五入或截断为小数点后 2 位

Jak*_*her 3 python truncate rounding floor pandas

我有一个数据帧,需要根据以下逻辑将其专门转换为两位小数分辨率

  • if x (以超过两位小数的值表示) > math.floor(x) + 0.5

    • ...然后将该值四舍五入到小数点后两位。
  • if x(以两位以上小数位的值表示)< math.ceil(x) - 0.5

    • ...然后将该值截断为两位小数。

我遇到的主要问题是实际上看到这些新舍入/截断的值替换了数据框中的原始值。

示例数据框:

import math
import pandas as pd  

test_df = pd.DataFrame({'weights': ['25.2524%', '25.7578%', '35.5012%', '13.5000%', 
    "50.8782%", "10.2830%", "5.5050%", "30.5555%", "20.7550%"]})

# .. which creates:

   | weights |
|0 | 25.2524%|
|1 | 25.7578%|
|2 | 35.5012%|
|3 | 13.5000%|
|4 | 50.8782%|
|5 | 10.2830%|
|6 |  5.5050%|
|7 | 30.5555%|
|8 | 20.7550%|
Run Code Online (Sandbox Code Playgroud)

定义截断函数,以及配置小数分辨率的函数:

def truncate_decimals(target_allocation, two_decimal_places) -> float:
    decimal_exponent = 10.0 ** two_decimal_places
    return math.trunc(decimal_exponent * target_allocation) / decimal_exponent

def decimals(df):
    df["weights"] = df["weights"].str.rstrip("%").astype("float")
    decimal_precision = 2
    for x in df["weights"]:
        if x > math.floor(x) + 0.5:
            x = round(x, decimal_precision)
            print("This value is being rounded", x)
            df.loc[(df.weights == x), ('weights')] = x
        elif x < math.ceil(x) - 0.5:
            y = truncate_decimals(x, decimal_precision)
            print("This value is being truncated", y)
            df.loc[(df.weights == x), ('weights')] = y
        else:
            pass
            print("This value does not meet one of the above conditions", round(x, decimal_precision))

    return df


decimals(test_df)
Run Code Online (Sandbox Code Playgroud)

预期输出:

This value is being truncated 25.25
This value is being rounded 25.76
This value is being rounded 35.5
This value does not meet one of the above conditions 13.5
This value is being rounded 50.88
This value is being truncated 10.28
This value is being rounded 5.5
This value is being rounded 30.56
This value is being rounded 20.75

   | weights|
|0 | 25.25  |
|1 | 25.76  |
|2 | 35.5   |
|3 | 13.5   |
|4 | 50.88  |
|5 | 10.28  |
|6 |  5.5   |
|7 | 30.56  |
|8 | 20.75  |
Run Code Online (Sandbox Code Playgroud)

电流输出:

The current value is being truncated 25.25

   | weights |
|0 | 25.2524%|
|1 | 25.7578%|
|2 | 35.5012%|
|3 | 13.5000%|
|4 | 50.8782%|
|5 | 10.2830%|
|6 |  5.5050%|
|7 | 30.5555%|
|8 | 20.7550%|
Run Code Online (Sandbox Code Playgroud)

smc*_*mci 6

pandas.round()函数已经在一行中完成了所有这些工作不要重新发明轮子。

>>> tdf['weights'].round(2)

0    25.25
1    25.76
2    35.50
3    13.50
4    50.88
5    10.28
6     5.50
7    30.56
8    20.76
Run Code Online (Sandbox Code Playgroud)
  • 如果您想消除例如“13.50”中的尾随“0”,这只是字符串格式,请参阅.format()

您甚至不需要使用modf获取浮点数的小数部分和整数部分的函数。

  • (它在 和 中都有numpy.modfmath.modf使用 numpy 版本,因为它是矢量化的,因此您可以在整个系列中调用它一次,并且不会执行大量单独的、缓慢的 C 调用,例如math.modfmath.ceilmath.floor

例如,如果您想获得一系列(浮点,整数)部分的元组:

import numpy as np
pd.Series(zip(*np.modf(tdf['weights'])))

0    (0.2524000000000015, 25.0)
1    (0.7577999999999996, 25.0)
2    (0.5011999999999972, 35.0)
3                   (0.5, 13.0)
4    (0.8781999999999996, 50.0)
5    (0.2829999999999995, 10.0)
6     (0.5049999999999999, 5.0)
7    (0.5554999999999986, 30.0)
8     (0.754999999999999, 20.0)
Run Code Online (Sandbox Code Playgroud)

注意:首先必须将百分比字符串转换为浮点数:

tdf["weights"] = tdf["weights"].str.rstrip("%").astype("float")
Run Code Online (Sandbox Code Playgroud)