[英]numpy Array Error: Summing elements gives wrong output
如果我對0
和1
的數組求和,我會通過 numpy 數組得到不同的結果。 為什么會發生這種情況,解決方案是什么? 代碼如下:
vl_2=vl_1=0
string_1="00001000100111000010001001100001000100110000100010011000010001011100001"
sb=string_1
table = bytearray.maketrans(b'01', b'\x00\x01')
X = bytearray(sb, "ascii").translate(table)
Y=2.**(np.nonzero(X)[0]+1)#X=np.nonzero(sb)[0]
for i in range(len(sb)):
vl_1 = vl_1+X[i]*2**(i+1)
for y in np.nditer(Y) :
vl_2=vl_2+y
請注意,我正在做相同的數學運算,我都循環,所以vl_2==vl_1
應該是True
,但我得到False
。
編輯:
np.nditer(Y)
上的循環使用科學記數法,這會稍微影響計算。 我稍微改變了循環
vl_2_2 = 0
for y in np.nditer(Y):
vl_2 = vl_2 + y
vl_2_2 = vl_2_2 + int(y.item())
print(f'{vl_2} {int(vl_2)} {vl_2_2}')
vl_2
是原始的
vl_2_2
在將y
轉換為int
后進行計算
在打印輸出中,我還在計算后將vl_2
打印為int
。
在轉換為科學計數法之前,兩個循環的結果都是相同的
第一個循環(沒有重復):
32
544
4640
12832
29216
553504
8942112
76050976
210268704
4505236000
73224712736
622980526624
1722492154400
36906864243232
599856817664544
5103456445035040
14110655699776032
302341031851487776
4914027050278875680
23360771123988427296
60254259271407530528
134041235566245736992
2495224477001068343840
第二個循環(查看原始數字的第一個數字)
32.0 32 32
544.0 544 544
4640.0 4640 4640
12832.0 12832 12832
29216.0 29216 29216
553504.0 553504 553504
8942112.0 8942112 8942112
76050976.0 76050976 76050976
210268704.0 210268704 210268704
4505236000.0 4505236000 4505236000
73224712736.0 73224712736 73224712736
622980526624.0 622980526624 622980526624
1722492154400.0 1722492154400 1722492154400
36906864243232.0 36906864243232 36906864243232
599856817664544.0 599856817664544 599856817664544
5103456445035040.0 5103456445035040 5103456445035040
1.4110655699776032e+16 14110655699776032 14110655699776032
3.0234103185148774e+17 302341031851487744 302341031851487776
4.914027050278875e+18 4914027050278875136 4914027050278875680
2.3360771123988427e+19 23360771123988426752 23360771123988427296
6.025425927140753e+19 60254259271407534080 60254259271407530528
1.3404123556624574e+20 134041235566245740544 134041235566245736992
2.4952244770010683e+21 2495224477001068314624 2495224477001068343840
通過您的設置 - 我喜歡看到一些價值觀,而不僅僅是一個模糊的“不一樣”的主張。
In [70]: Y
Out[70]:
array([3.20000000e+01, 5.12000000e+02, 4.09600000e+03, 8.19200000e+03,
1.63840000e+04, 5.24288000e+05, 8.38860800e+06, 6.71088640e+07,
1.34217728e+08, 4.29496730e+09, 6.87194767e+10, 5.49755814e+11,
1.09951163e+12, 3.51843721e+13, 5.62949953e+14, 4.50359963e+15,
9.00719925e+15, 2.88230376e+17, 4.61168602e+18, 1.84467441e+19,
3.68934881e+19, 7.37869763e+19, 2.36118324e+21])
In [72]: X
Out[72]: bytearray(b'\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x01\x01\x01\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x01\x01\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x01\x01\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x01\x01\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x01\x01\x01\x00\x00\x00\x00\x01')
In [73]: for i in range(len(sb)):
...: vl_1 = vl_1+X[i]*2**(i+1)
...:
In [74]: vl_1
Out[74]: 2495224477001068343840
In [76]: for y in np.nditer(Y) :
...: vl_2=vl_2+y
...:
In [77]: vl_2
Out[77]: 2.4952244770010683e+21
一個是浮點數(畢竟Y
是浮點數),否則值相同(在浮點精度內)
In [78]: vl_1-vl_2
Out[78]: 0.0
nditer
對您沒有任何幫助:
In [79]: vl_2=0
...: for y in Y : vl_2=vl_2+y
In [80]: vl_2
Out[80]: 2.4952244770010683e+21
但是在數組上迭代比較慢。 你不需要它
In [81]: np.sum(Y)
Out[81]: 2.4952244770010683e+21
如果在構造Y
時將2.
替換為2
:
In [95]: 2.**(np.nonzero(X)[0]+1)
Out[95]:
array([3.20000000e+01, 5.12000000e+02, 4.09600000e+03, 8.19200000e+03,
1.63840000e+04, 5.24288000e+05, 8.38860800e+06, 6.71088640e+07,
1.34217728e+08, 4.29496730e+09, 6.87194767e+10, 5.49755814e+11,
1.09951163e+12, 3.51843721e+13, 5.62949953e+14, 4.50359963e+15,
9.00719925e+15, 2.88230376e+17, 4.61168602e+18, 1.84467441e+19,
3.68934881e+19, 7.37869763e+19, 2.36118324e+21])
In [96]: 2**(np.nonzero(X)[0]+1)
Out[96]:
array([ 32, 512, 4096,
8192, 16384, 524288,
8388608, 67108864, 134217728,
4294967296, 68719476736, 549755813888,
1099511627776, 35184372088832, 562949953421312,
4503599627370496, 9007199254740992, 288230376151711744,
4611686018427387904, 0, 0,
0, 0], dtype=int64)
第二個是整數值,但最后 4 個對於int64
來說太大了。
跳過X
的最后一部分,我得到相同的整數結果:
In [100]: sum(2**(np.nonzero(X[:-8])[0]+1))
Out[100]: 4914027050278875680
In [101]: sum([x*2**(i+1) for i,x in enumerate(X[:-8])])
Out[101]: 4914027050278875680
另一個答案建議使用object
dtype。 雖然它可能有效,但它失去了使用數字 dtype 數組的大部分速度優勢。
正如另一個答案中所建議的,將nonzero
結果轉換為object
會產生足夠大的 Python 整數:
In [166]: 2**(np.nonzero(X)[0]+1).astype(object)
Out[166]:
array([32, 512, 4096, 8192, 16384, 524288, 8388608, 67108864, 134217728,
4294967296, 68719476736, 549755813888, 1099511627776,
35184372088832, 562949953421312, 4503599627370496,
9007199254740992, 288230376151711744, 4611686018427387904,
18446744073709551616, 36893488147419103232, 73786976294838206464,
2361183241434822606848], dtype=object)
一些比較時間
In [167]: timeit np.sum(2**(np.nonzero(X)[0]+1).astype(object))
46.5 µs ± 1.64 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
近似的浮動方法:
In [168]: timeit np.sum(2.**(np.nonzero(X)[0]+1))
32.3 µs ± 1.12 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
枚舉列表:
In [169]: timeit sum([x*2**(i+1) for i,x in enumerate(X)])
43.1 µs ± 1.14 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
快速使用對象 dtype 數組並沒有幫助。
nonzero_bits 的列表版本更快
In [173]: %%timeit
...: nonzero_bits = [i for i, x in enumerate(X) if x != 0]
...: vl = sum(2 ** (i + 1) for i in nonzero_bits)
18.9 µs ± 221 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
首先,使用 numpy 仍然使用 for 循環不是矢量化,不會提高性能(會更糟,因為 numpy 數組實例化開銷)。
其次,您正在處理非常大的數字,高於 numpy 的本機 ctypes 容量,但本機 python int
可以處理它們,因此您需要為 numpy 指定dtype=object
不強制轉換類型(請參閱https://stackoverflow.com/a/ 37272717/13636407 )。
即使在那里,因為使用dtype=object
,numpy 不能矢量化,所以使用 numpy 沒有性能改進,正如@hpaulj 所注意到的(參見下面的性能測試)。
import numpy as np
def using_list(s):
X = to_bytearray(s)
nonzero_bits = [i for i, x in enumerate(X) if x != 0]
return sum(2 ** (i + 1) for i in nonzero_bits)
def using_numpy(s):
# because large numbers, need to convert to dtype=object
# see https://stackoverflow.com/a/37272717/13636407
X = to_bytearray(s)
nonzero_bits = np.nonzero(X)[0].astype(object)
return np.sum(2 ** (nonzero_bits + 1))
table = bytearray.maketrans(b"01", b"\x00\x01")
def to_bytearray(s):
return bytearray(s, "ascii").translate(table)
平等檢查:
s = "00001000100111000010001001100001000100110000100010011000010001011100001"
vl_list = using_list(s)
vl_numpy = using_numpy(s)
assert vl_list == vl_numpy
性能測試:
>>> %timeit using_list(s)
... %timeit using_numpy(s)
... print()
... %timeit using_list(s * 10)
... %timeit using_numpy(s * 10)
... print()
... %timeit using_list(s * 100)
... %timeit using_numpy(s * 100)
10.1 µs ± 81 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
18.1 µs ± 146 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
128 µs ± 700 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
104 µs ± 605 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
9.88 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.77 ms ± 108 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.