Создать диапазон десятичного числа с помощью numpy не работает - PullRequest
0 голосов
/ 24 марта 2020

Я хочу создать диапазон значений от 521 до 522 с шагом 0.1. Это мой код:

ICD9CD1 = np.arange(521, 522, 0.1)

Результат:

array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9])

, но когда я хочу преобразовать его в список, это результат:

np.arange(521, 522, 0.1).tolist()

[521.0,
 521.1,
 521.2,
 521.3000000000001,
 521.4000000000001,
 521.5000000000001,
 521.6000000000001,
 521.7000000000002,
 521.8000000000002,
 521.9000000000002]

Какая часть моего кода неверна? Я хочу этот список в качестве своего вывода: [521. , 521,1, 521,2, 521,3, 521,4, 521,5, 521,6, 521,7, 521,8, 521,9]

Ответы [ 3 ]

3 голосов
/ 24 марта 2020

Вы должны либо использовать np.arange(5210, 5220) / 10 или np.linspace(521, 522, 10, endpoint=False), но прочитать весь ответ.


Часть вашего кода является неправильной, но не так, как вы мышление.

Операции с плавающей точкой имеют ошибку округления. Это является фундаментальным для чисел с плавающей запятой и фундаментальным ограничением попыток выполнять вычисления с действительными числами на компьютерах с ограниченными ресурсами. Даже символьные c вычисления не исправят ситуацию - когда выражение невозможно символически упростить, вы в конечном итоге просто строите гигантские деревья выражений вместо того, чтобы фактически что-либо вычислять.

Простое присутствие ошибки округления в вашем вывод не означает, что вы сделали что-то не так. Кроме того, ошибка округления уже присутствовала в выводе arange, просто скрыта настройками печати по умолчанию NumPy - она ​​не была введена в вызове tolist. При любом даже немного нетривиальном вычислении с плавающей точкой вы никогда не устраните все ошибки округления.

Даже результат, который выглядит как [521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9], на самом деле будет иметь ошибку округления, потому что действительное число 521.1 на самом деле не представляется в двоичном виде плавающая запятая. Большинство чисел, которые выглядят так, как будто они в этом списке, не могут быть представлены в двоичной форме с плавающей точкой. (64-разрядный) float 521.1 на самом деле 521.1000000000000227373675443232059478759765625, но большинство языков программирования не отображают точное значение по умолчанию.


Часть вашего кода, которая действительно неверна, использование arange с входами с плавающей запятой. arange не согласуется с входными данными с плавающей запятой, поскольку в зависимости от ошибки округления он может содержать больше или меньше элементов, чем ожидалось. Например,

np.arange(1, 1.3, 0.1)

возвращает

array([1. , 1.1, 1.2, 1.3])

вместо

array([1. , 1.1, 1.2])

из-за ошибки округления с плавающей точкой при вычислении длины результата.

Кроме того, из-за некоторых странных решений о реализации, arange с входными данными с плавающей запятой имеет гораздо большую ошибку округления, чем должна, даже когда он получает правильный выходной размер.

np.linspace разработан, чтобы избежать проблем с arange. Он принимает выходной размер в качестве аргумента напрямую, вместо того, чтобы вычислять его из шага, и имеет явный параметр для включения или выключения правильной конечной точки. Это позволяет избежать ошибки округления при вычислении выходного размера, если вы сами не представите его, вычислив выходной размер с плавающей запятой. np.linspace также имеет меньшую погрешность округления, чем arange при вычислении выходных элементов. Не гарантируется минимальная ошибка округления - например, np.linspace(0, 3, 148)[::49].tolist() показывает избыточную ошибку округления - но это намного лучше, чем с плавающей точкой arange.

np.arange(5210, 5220) / 10 использует arange с целочисленными аргументами и делит потом. Эта опция имеет только один источник ошибки округления, деление на 10. Это деление гарантировано IEEE 754 spe c, чтобы быть правильно округленным , в результате чего результаты будут округлены до плавающей запятой значения, наиболее близкие к идеальным действительным числам деления. Эта опция гарантирует наименьшую ошибку округления, в некоторых случаях превышая linspace. Например, np.arange(148) / 49 бьет np.linspace(0, 3, 148) в ошибке округления.

2 голосов
/ 24 марта 2020

arange docs выдает предупреждение:

При использовании нецелого шага, такого как 0,1, результаты часто не будут согласованными. Для этих случаев лучше использовать numpy.linspace.

То, что вы видите, - это сочетание неточности с плавающей запятой и arange способа генерации последовательных значений. Значения с плавающей точкой никогда не бывают точными.

arange рекомендует использовать linspace с дробными шагами. Только будьте осторожны, чтобы выбрать правильное число:

In [301]: np.linspace(521,522,11)                                                                                    
Out[301]: 
array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9, 522. ])
In [302]: np.linspace(521,522,11).tolist()                                                                           
Out[302]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9, 522.0]

Генерация целочисленных значений и их масштабирование также работает:

In [303]: (np.arange(5210,5220)/10)                                                                                  
Out[303]: 
array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9])
In [304]: (np.arange(5210,5220)/10).tolist()                                                                         
Out[304]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9]

это также можно сделать с помощью python 's range:

In [305]: [i/10 for i in range(5210,5220)]                                                                           
Out[305]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9]
0 голосов
/ 24 марта 2020

Попробуйте это:

import numpy as np
list(np.around(np.arange(521, 522, 0.1),2))
...