如何在Python中用k表示千并支持任意前缀符号格式化数字?

3 投票
1 回答
4737 浏览
提问于 2025-04-18 07:13

我想在给图表注释时格式化数字,让它们看起来更好,比如用“k”表示千,等等,并且要有精确的四舍五入,比如保留三位小数:

13.1    -> 13.1
13.1676 -> 13.2
1246    -> 1.25k
560254  -> 560k
6.234e7 -> 62.3M

我写了一个函数来实现这个功能,但感觉有点复杂:

import math


def num_fmt(num):
    i_offset = 15 # change this if you extend the symbols!!!
    prec = 3
    fmt = '.{p}g'.format(p=prec)
    symbols = ['Y', 'T', 'G', 'M', 'k', '', 'm', 'u', 'n']

    e = math.log10(abs(num))
    if e >= i_offset + 3:
        return '{:{fmt}}'.format(num, fmt=fmt)
    for i, sym in enumerate(symbols):
        e_thresh = i_offset - 3 * i
        if e >= e_thresh:
            return '{:{fmt}}{sym}'.format(num/10.**e_thresh, fmt=fmt, sym=sym)
    return '{:{fmt}}'.format(num, fmt=fmt)

1 个回答

1

像这样可能会有效:

from bisect import bisect

# A mapping of breakpoints for suffixes.
suffixes = {
    1e-9: 'n',
    1e-6: 'u',
    1e-3: 'm',
    1: '',
    1e3: 'k',
    1e6: 'M',
    1e9: 'G',
    1e12: 'T',
    1e15: 'Y',
}

# List of sorted breakpoints' values.
suffix_breakpoints = sorted(suffixes.iterkeys())

def format_with_suffix(num):
    num_format = '{:.2f}{}'
    if not num:
       return num_format.format(num, '')

    if num in suffixes:
       return num_format.format(1.0, suffixes[num])

    # Find the index of first breakpoint `x`, that's greater than `num`
    # using binary search.
    breakpoint_idx = bisect(suffix_breakpoints, num)

    # Get the breakpoint's value. If `num` is lower than the first breakpoint, use
    # that instead.
    breakpoint = suffix_breakpoints[breakpoint_idx - 1 if breakpoint_idx else 0]

    # Get the suffix.
    suffix = suffixes[breakpoint]
    return num_format.format(float(num) / breakpoint, suffix)

>>> for x in xrange(-10, 20):
>>>     print format_with_suffix(10.0 ** x), 10.0 ** x
0.10n 1e-10
1.00n 1e-09
10.00n 1e-08
100.00n 1e-07
1.00u 1e-06
10.00u 1e-05
100.00u 0.0001
1.00m 0.001
10.00m 0.01
100.00m 0.1
1.00 1.0
10.00 10.0
100.00 100.0
1.00k 1000.0
10.00k 10000.0
100.00k 100000.0
1.00M 1000000.0
10.00M 10000000.0
100.00M 100000000.0
1.00G 1000000000.0
10.00G 10000000000.0
100.00G 1e+11
1.00T 1e+12
10.00T 1e+13
100.00T 1e+14
1.00Y 1e+15
10.00Y 1e+16
100.00Y 1e+17
1000.00Y 1e+18
10000.00Y 1e+19

撰写回答