[英]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.