pandas 将一个数列四舍五入到N位有效数字

332nm8kg  于 2023-03-16  发布在  其他
关注(0)|答案(3)|浏览(192)

我有一个浮点数的 Dataframe ,我需要创建一个函数,该函数将接受一列,并将所有值舍入到N个有效数字
因此,该列可能类似于:

123.949
23.87 
1.9865
0.0129500

如果我想四舍五入到3位有效数字,我会将列和3传递给函数,以获得

124.0
23.9
1.99
0.013

我怎样才能高效地完成这一工作而不遍历整个列呢?
我有一个公式可以计算一个数字的有效数字

round(x, N-int(floor(log10(abs(x))))

但它不适用于系列或 Dataframe

2admgd59

2admgd591#

您可以使用,pandas.Series.apply,它在轴(列或行)上实现函数元素方式:

df.col.apply(lambda x: round(x, N - int(floor(log10(abs(x))))))

注意,这里不能使用pandas.DataFrame.apply,因为round函数应该是元素级的,而不是整个轴上的。
不同之处在于,您的函数输入是float,而不是得到array
另一个选项是applymap,它在整个pandas.DataFrame上实现一个函数元素级。

df.applymap(lambda x: round(x, N - int(floor(log10(abs(x))))))
clj7thdc

clj7thdc2#

这是在dataframe中的序列上应用自定义函数的另一个例子。然而,当最后一位数字是5时,内置的round()似乎会向下舍入小数部分,所以在您的示例中,您实际上会得到0.0129而不是0.013。我试图纠正这个问题。还添加了将有效数字的数量设置为参数以获得您想要应用的舍入器的功能。

import pandas as pd
from math import floor, log10

df = pd.DataFrame({'floats':[123.949, 23.87, 1.9865, 0.0129500]})

def smarter_round(sig):
    def rounder(x):
        offset = sig - floor(log10(abs(x)))
        initial_result = round(x, offset)
        if str(initial_result)[-1] == '5' and initial_result == x:
            return round(x, offset - 2)
        else:
            return round(x, offset - 1)
    return rounder

print(df['floats'].apply(smarter_round(3)))

Out:
    0    124.000
    1     23.900
    2      1.990
    3      0.013
    Name: floats, dtype: float64
ogq8wdun

ogq8wdun3#

对于大型 Dataframe ,.apply可能会很慢,我见过的最好的解决方案来自Scott Gigante,它直接为numpy解决了同样的问题。
下面是他的答案的一个稍微修改的版本,只是添加了一些Pandas Package 。解决方案是快速和健壮的。

from typing import Union
import pandas as pd
import numpy as np

def significant_digits(df: Union[pd.DataFrame, pd.Series], 
                       significance: int, 
                       inplace: bool = False
                       ) -> Union[pd.DataFrame, pd.Series, None]:
    
    # Create a positive data vector with a place holder for NaN / inf data
    data = df.values
    data_positive = np.where(np.isfinite(data) & (data != 0),
                             np.abs(data),
                             10**(significance-1))

    # Align data by magnitude, round, and scale back to original
    magnitude = 10 ** (significance - 1 - np.floor(np.log10(data_positive)))
    data_rounded = np.round(data * magnitude) / magnitude

    # Place back into Series or DataFrame
    if inplace:
        df.loc[:] = data_rounded
    else:
        if isinstance(df, pd.DataFrame):
            return pd.DataFrame(data=data_rounded,
                                index=df.index,
                                columns=df.columns)
        else:
            return pd.Series(data=data_rounded, index=df.index)

相关问题