Как умножить элемент с плавающей точкой матрицы на целое число? - PullRequest
0 голосов
/ 23 апреля 2020

Я попробовал код ниже, чтобы умножить элемент с плавающей запятой матрицы a, который меньше, чем один на любое целое число, но с другой стороны он не работает, он работает правильно для матрицы, элемент которой не является с плавающей точкой, т.е. если вы определяете matix a = np.arange(9).reshape(3,3) тогда работает.

import numpy as np

a = np.linspace(0,1,9).reshape(3,3)

print(a)
print('new matrix')
for x in np.nditer(a, op_flags = ['readwrite']):
  if x in range(0,1):
    x[...] = 100*x
print(a)

Ответы [ 2 ]

1 голос
/ 23 апреля 2020
In [130]: a = np.linspace(0,1,9).reshape(3,3)                                                          
In [131]: a                                                                                            
Out[131]: 
array([[0.   , 0.125, 0.25 ],
       [0.375, 0.5  , 0.625],
       [0.75 , 0.875, 1.   ]])

Обычно я не рекомендую использовать nditer для перебора массива. Трудно правильно использовать, и редко, если вообще когда-либо, улучшает скорость. Я не уверен, кто или что побуждает людей использовать это. В его документах может использоваться более быстрый отказ от ответственности.

В любом случае, давайте рассмотрим, что происходит.

In [136]: for x in np.nditer(a, op_flags = ['readwrite']): 
     ...:   print(type(x), x, x.shape)   
     ...:   if x in range(0,1): 
     ...:     x[...] = 100*x 
     ...:     print('mul') 
     ...:                                                                                              
<class 'numpy.ndarray'> 0.0 ()
mul
<class 'numpy.ndarray'> 0.125 ()
<class 'numpy.ndarray'> 0.25 ()
<class 'numpy.ndarray'> 0.375 ()
<class 'numpy.ndarray'> 0.5 ()
<class 'numpy.ndarray'> 0.625 ()
<class 'numpy.ndarray'> 0.75 ()
<class 'numpy.ndarray'> 0.875 ()
<class 'numpy.ndarray'> 1.0 ()

nditer проходит через каждый элемент массива (не строки), создавая представление 0d каждый раз (форма ()). Только один из этих элементов равен 0, поэтому он умножается на 100. Ни один из остальных не находится в range(0,1) (только 0 in range(0,1), все остальное - False).

Таким образом, итерация работает, в хотя бы как закодировано, если не так, как вы намереваетесь.

a = np.arange(9).reshape(3,3) ничего не меняет. Только 0 - in range(0,1),

===

Изменить тест if:

In [146]: a = np.linspace(0,1,9).reshape(3,3)                                                          
In [147]: a                                                                                            
Out[147]: 
array([[0.   , 0.125, 0.25 ],
       [0.375, 0.5  , 0.625],
       [0.75 , 0.875, 1.   ]])
In [148]: for x in np.nditer(a, op_flags = ['readwrite']):  
     ...:   if x<1: 
     ...:     x[...] = 100*x 
     ...:     print('mul') 
     ...:                                                                                              
mul
...
mul
In [149]: a                                                                                            
Out[149]: 
array([[ 0. , 12.5, 25. ],
       [37.5, 50. , 62.5],
       [75. , 87.5,  1. ]])

Альтернативой nditer является flat итерация. В некоторых случаях это сложнее, поскольку для изменения исходных значений требуется enumerate:

In [150]: a = np.linspace(0,1,9).reshape(3,3)                                                          
In [151]: for i,v in enumerate(a.flat): 
     ...:     if v<1: 
     ...:         a.flat[i] *= 100 
     ...:                                                                                              
In [152]: a                                                                                            
Out[152]: 
array([[ 0. , 12.5, 25. ],
       [37.5, 50. , 62.5],
       [75. , 87.5,  1. ]])

Но, несмотря на некоторые утверждения в документах nditer, это не быстрее:

In [153]: %%timeit a=np.linspace(0,1,9).reshape(3,3) 
     ...: for i,v in enumerate(a.flat): 
     ...:     if v<1: 
     ...:         a.flat[i] *= 100 
5.4 µs ± 186 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [154]:                                                                                              
In [154]: %%timeit a=np.linspace(0,1,9).reshape(3,3) 
     ...: for x in np.nditer(a, op_flags = ['readwrite']):  
     ...:   if x<1: 
     ...:     x[...] = 100*x 
34.4 µs ± 108 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

===

Но обычно вы не должны выполнять итерации в массиве. Целый массив, векторизация , подход:

In [157]: mask = a<1                                                                                   
In [158]: mask                                                                                         
Out[158]: 
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True, False]])
In [159]: a[mask] *= 100                                                                               
In [160]: a                                                                                            
Out[160]: 
array([[ 0. , 12.5, 25. ],
       [37.5, 50. , 62.5],
       [75. , 87.5,  1. ]])
In [161]: %%timeit a=np.linspace(0,1,9).reshape(3,3) 
     ...: a[a<1] *= 100                                                                                               
12.5 µs ± 184 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Ой! это медленнее, чем перечисление плоских - для этого небольшого примера Для гораздо большего a это будет намного лучше.

0 голосов
/ 23 апреля 2020

Вы можете применить диапазон «вручную» в логическом фильтре, чтобы умножить только те элементы, на которые вы нацеливаетесь:

import numpy as np

a = np.linspace(0,1,9).reshape(3,3)

print(a)
print('new matrix')
a[(a>0) & (a<1)] *= 100
print(a)

[[0.    0.125 0.25 ]
 [0.375 0.5   0.625]
 [0.75  0.875 1.   ]]
new matrix
[[ 0.  12.5 25. ]
 [37.5 50.  62.5]
 [75.  87.5  1. ]]

обратите внимание, что ваше линейное пространство будет всегда генерировать только 1 значение, которое находится за пределами диапазона (последний), так что вы можете умножить все и переназначить последнее значение на 1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...