[英]Round unknown whole number to highest base10 value Python
值将作为来自 pandas 数据帧的 max() 给出。 对于每个项目,我想获得一个四舍五入的最大值来为 matplot plot 创建 y 刻度,刻度数 = 10。
我使用的数据框是官方的 John Hopkins Covid Data。 前面的代码返回按国家或州、每日总数或累计、病例或死亡分类的数据框。
我在 for 循环中编写了代码,该代码将转换最大值(可能超过 2000 万或低至 6)以获取前导数字并加 1,然后在需要时连接额外的零。 如果下一个数字很小,我宁愿将值向下舍入,因为此代码会在某些图表的顶部产生小间隙。
我写的代码是在str和int pythonic之间来回转换的吗? 有没有一种简单的方法可以向该代码添加一个圆形方法? 或者是否有更好、更有效的方法来做我想做的事情?
# 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 为底的回报。 但以 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 只是浮点数/整数列表(等于正在绘制的 pd 系列的最大值)63817.0
2675262
这是一系列情节的output。 您可以看到第一个图表的刻度 go 远高于第一个图表的实际最大值(忽略 plot 的位置,它现在是最合适的)。 这是我想减轻的将低数字四舍五入的结果。 但我们的目标是提供最干净的刻度值,同时保持情节的美观和紧凑
如果你真的只想要你的 10 步的一个有效数字,你可以用使用以 10 为底的对数的东西来复制你的(不,不是真正的 Pythonic)字符串转换表达式,例如
def round10(n):
return 10**math.ceil(math.log10(n))
但是正如您自己注意到的那样,这并不会真正产生有用的结果,例如,如果最大值为 1001,则 y 刻度将 go 从 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
>>>
编辑:如果您关心性能,则将所有数据作为 numpy arrays 并执行矢量化方法。 下面的代码是矢量化的,也不会因零或负数而窒息。
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 go 变为 50。
def round10_first(x):
from math import floor, ceil, log
p = 10 ** floor(log(x, 10))
return ceil(x / p) * p
谢谢你们的帮助。 实际上,我将您的答案结合起来作为我的解决方案我在它们上运行了一个 timeit,它们的速度相同,但我将使用您构建的那个更 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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.