将未知整数舍入到最高的 base10 值 Python

Round unknown whole number to highest base10 value Python

值将作为来自 pandas 数据框的 max() 给出。对于每个项目,我想获得一个四舍五入的最大值,以便为刻度数 = 10 的 matplot 图创建 y 刻度。

我使用的数据框是官方的 John Hopkins Covid Data。前面的代码 return 是按国家或州、每日总数或累计、病例或死亡分类的数据框。

我在 for 循环中编写了代码,该代码将转换最大值(可能超过 2000 万或低至 6)以获取前导数字并加 1,然后在需要时连接额外的零。如果下一个数字很小,我宁愿将值向下舍入,因为此代码会在某些图表的顶部产生小间隙。

我写的代码是在str和int之间来回转换的pythonic吗? 有没有一种简单的方法可以向该代码添加一个 round 方法? 要么 是否有更好、更有效的方法来完成我想做的事情?

# Per Capita ## (identical version for daily totals on dfs1)
cumulative2 = dfs2.T[default[ind]]
daily_cases2 = cumulative2.diff()
d_max2 = daily_cases2.max().max()
c_max2 = cumulative2.max().max()

...

plot1 = daily_cases1.plot(kind='area', stacked=False, ax=ax1, lw=2, ylim=(0, d_max1))
plot2 = daily_cases2.plot(kind='area', stacked=False, ax=ax2, lw=2, ylim=(0, d_max2))
plot3 = cumulative1.plot(kind='area', stacked=False, ax=ax3, lw=2, ylim=(0, c_max1))
plot4 = cumulative2.plot(kind='area', stacked=False, ax=ax4, lw=2, ylim=(0, c_max2))

plots = [plot1, plot2, plot3, plot4]
maxes = [d_max1, d_max2, c_max1, c_max2]
for i, plot in enumerate(plots):
    rnd_max = int(f'{str(int(str(int(maxes[i]))[0]) + 1) + "0" * (len(str(int(maxes[i]))) - 1)}')
    yticks = np.arange(0, rnd_max, 1 if rnd_max < 10 else rnd_max // 10)
    ytick_labels = pd.Series(yticks).apply(lambda value: f"{int(value):,}")
    plot.set_yticks(yticks)
    plot.set_yticklabels(ytick_labels)

编辑:如果值为 2,750,00,我希望主值是 3;如果值为 41,我希望是 4。所以不是真正的基数 10 return。但以 10 为基数,前导数字。

累计:

State    California  Arizona  Florida  New York    Texas  Illinois
11/4/20      950920   250633   821123    519890  1003342    443803
3/14/20         372       12       76       557       60        64
5/22/20       90281    15624    49451    360818    53817    105444

每日:

State    California  Arizona  Florida  New York    Texas  Illinois
4/3/20       1226.0    173.0   1260.0   10675.0    771.0    1209.0
6/25/20      5088.0   3091.0   5004.0     814.0   5787.0     894.0
11/3/20      4990.0   1679.0   4637.0    2069.0   9721.0    6516.0

c_max 和 d_ max 只是 floats/ints 的列表(等于正在绘制的 pd 系列的最大值) 63817.0

2675262

这是一系列绘图的输出。您可以看到第一个图表的刻度比第一个图表的实际最大值高得多(忽略目前最适合的绘图位置)。这是将低数舍入为高数的结果,我想减轻这一点。但我的目标是尽可能给出最干净的刻度值,同时保持图表美观紧凑

如果您真的只想要 10 个步骤的一位有效数字,您可以复制您的(不,我会说不是真正的 Pythonic)字符串转换表达式,使用以 10 为底的对数,例如

def round10(n):
  return 10**math.ceil(math.log10(n))

但是正如您自己注意到的那样,这并没有真正产生有用的结果,例如,如果最大值为 1001,则 y 刻度将从 0 变为 10000,这意味着基本上所有内容都会被压缩到最近的刻度.内置的自动缩放功能更加复杂,可以最大化可用区域。

from math import floor, log
def round_first(x):
    p = 10**floor(log(x,10))
    return (round(x/p)*p)
>>> round_first(5123)
5000
>>> round_first(5987)
6000
>>>

编辑: 如果您关心 performance ,那么将所有数据作为 numpy 数组放入并执行矢量化方法。下面的代码是矢量化的,也不会阻塞零数或负数。

import numpy as np
>>> def round_first(x):                                 
...     xa = np.abs(x)                                  
...     xs = np.sign(x)                                 
...     nonzero = x!=0                                  
...     p=10**np.floor(np.log10(xa[nonzero]))           
...     out=np.zeros(x.shape)
...     out[nonzero] = np.round(xa[nonzero]/p)*p*xs[nonzero]
...     return out                                      
...
>>> x = np.arange(-1000,2001,67)                        
>>> x
array([-1000,  -933,  -866,  -799,  -732,  -665,  -598,  -531,  -464,
        -397,  -330,  -263,  -196,  -129,   -62,     5,    72,   139,
         206,   273,   340,   407,   474,   541,   608,   675,   742,
         809,   876,   943,  1010,  1077,  1144,  1211,  1278,  1345,
        1412,  1479,  1546,  1613,  1680,  1747,  1814,  1881,  1948])
>>> round_first(x)
array([-1000.,  -900.,  -900.,  -800.,  -700.,  -700.,  -600.,  -500.,
        -500.,  -400.,  -300.,  -300.,  -200.,  -100.,   -60.,     5.,
          70.,   100.,   200.,   300.,   300.,   400.,   500.,   500.,
         600.,   700.,   700.,   800.,   900.,   900.,  1000.,  1000.,
        1000.,  1000.,  1000.,  1000.,  1000.,  1000.,  2000.,  2000.,
        2000.,  2000.,  2000.,  2000.,  2000.])

你的问题也说最近的圆(你说 41 变成 40 而不是 50),但是你自己的答案使用 ceil(),这会使 41 变成 50。

def round10_first(x):
    from math import floor, ceil, log
    p = 10 ** floor(log(x, 10))
    return ceil(x / p) * p

谢谢大家的帮助。我实际上结合了你的答案来解决我的问题 我 运行 对它们进行了计时,它们的速度相同,但我会使用由您构建的那个更像 pythonic

%timeit -n 10000000 function1
%timeit -n 10000000 function2

16.7 ns ± 0.108 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
16.8 ns ± 0.13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)