Как сделать поэлементное округление массива NumPy до первой ненулевой цифры? - PullRequest
0 голосов
/ 24 октября 2019

Я бы хотел "округлить" (не точное математическое округление) элементы массива с нулями следующим образом:

С учетом двумерного массива NxN или NxM с цифрой от 0,00001 до 9.99999, например

 a=np.array([[1.232, 1.872,2.732,0.123],
             [0.0019, 0.025, 1.854, 0.00017],
             [1.457, 0.0021, 2.34 , 9.99],
             [1.527, 3.3, 0.012 , 0.005]]
    )

Я хотел бы в основном "округлить" этот массив с нулевыми значениями, выбрав первую ненулевую цифру (независимо от цифры, которая следует за первой ненулевой цифрой) каждого элемента, дающего вывод:

output =np.array([[1.0, 1.0, 2.0, 0.1],
                 [0.001, 0.02, 1.0, 0.0001],
                 [1.0, 0.002, 2 , 9.0],
                 [1, 3, 0.01 , 0.005]]
        )

спасибо за любую помощь!

Ответы [ 3 ]

1 голос
/ 24 октября 2019

Что вы хотели бы сделать, это сохранить фиксированное количество значащих цифр .

Эта функция не интегрирована в NumPy.

Чтобы получить только 1Вы можете посмотреть ответы @ PaulPanzer или @ darcamo (при условии, что у вас есть только положительные значения).

Если вы хотите что-то, что работает по заданномучисло значащих цифр, вы можете использовать что-то вроде:

def significant_figures(arr, num=1):
    # : compute the order of magnitude
    order = np.zeros_like(arr)  
    mask = arr != 0
    order[mask] = np.floor(np.log10(np.abs(arr[mask])))
    del mask  # free unused memory
    # : compute the corresponding precision
    prec = num - order - 1
    return np.round(arr * 10.0 ** prec) / 10.0 ** prec


print(significant_figures(a, 1))
# [[1.e+00 2.e+00 3.e+00 1.e-01]
#  [2.e-03 2.e-02 2.e+00 2.e-04]
#  [1.e+00 2.e-03 2.e+00 1.e+01]
#  [2.e+00 3.e+00 1.e-02 5.e-03]]

print(significant_figures(a, 2))
# [[1.2e+00 1.9e+00 2.7e+00 1.2e-01]
#  [1.9e-03 2.5e-02 1.9e+00 1.7e-04]
#  [1.5e+00 2.1e-03 2.3e+00 1.0e+01]
#  [1.5e+00 3.3e+00 1.2e-02 5.0e-03]]

EDIT

Для усеченного вывода используйте np.floor() вместо np.round() непосредственно перед return.

1 голос
/ 24 октября 2019

Вы можете использовать np.logspace и np.seachsorted, чтобы определить порядок величины каждого элемента, а затем разделить и умножить на пол обратно

po10 = np.logspace(-10,10,21)
oom = po10[po10.searchsorted(a)-1]
a//oom*oom
# array([[1.e+00, 1.e+00, 2.e+00, 1.e-01],
#        [1.e-03, 2.e-02, 1.e+00, 1.e-04],
#        [1.e+00, 2.e-03, 2.e+00, 9.e+00],
#        [1.e+00, 3.e+00, 1.e-02, 5.e-03]])
0 голосов
/ 24 октября 2019

Сначала получите степени 10 для каждого числа в массиве с

powers = np.floor(np.log10(a))

В вашем примере это дает нам

array([[ 0.,  0.,  0., -1.],
       [-3., -2.,  0., -4.],
       [ 0., -3.,  0.,  0.],
       [ 0.,  0., -2., -3.]])

Теперь, если мы разделим i -ый элемент в массиве с помощью 10**power_i мы по существу перемещаем каждый ненулевой элемент в массиве на первую позицию. Теперь мы можем просто взять слово, чтобы удалить другие ненулевые цифры, а затем умножить результат на 10**power_i, чтобы вернуться к исходной шкале.

Полное решение - это только код ниже

powers = np.floor(np.log10(a))
10**powers * np.floor(a/10**powers)

А как насчет чисел, больших или равных 10?

Для этого вы можете просто взять np.floor исходного значения в массиве. Мы можем сделать это легко с помощью маски. Вы можете изменить ответ, как показано ниже

powers = np.floor(np.log10(a))
result = 10**powers * np.floor(a/10**powers)

mask = a >= 10
result[mask] = np.floor(a[mask])

Вы также можете использовать маску, чтобы избежать вычисления степеней и логарифма для чисел, которые будут заменены позже.

...