Миграция python2 операций np.array смешанного типа в python3 - PullRequest
2 голосов
/ 10 февраля 2020

Я перехожу с python2 на python3 и сталкиваюсь с проблемой, которую я упростил до этого:

import numpy as np
a = np.array([1, 2, None])
(a > 0).nonzero()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: '>' not supported between instances of 'NoneType' and 'int' 

На самом деле я обрабатываю np-массивы с миллионами данные и правда нужно сохранить np-операцию для производительности. В python 2 это работало нормально и возвращает то, что я ожидаю, так как python2 не очень любит типы. Каков наилучший подход для переноса этого?

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Одним из способов достижения желаемого результата является использование лямбда-функции с np.vectorize:

>>> a = np.array([1, 2, None, 4, -1])
>>> f = np.vectorize(lambda t: t and t>0)
>>> np.where(f(a))
(array([0, 1, 3], dtype=int64),)

Конечно, если массив не содержит отрицательных целых чисел, вы можете просто использовать np.where(a) , поскольку и None, и 0 оцениваются как False:

>>> a = np.array([1, 2, None, 4, 0])
>>> np.where(a)
(array([0, 1, 3], dtype=int64),)

Еще один способ решить эту проблему - сначала преобразовать массив в тип float dtype, который имеет эффект преобразования None до np.nan. Тогда np.where(a>0) можно использовать как обычно.

>>> a = np.array([1, 2, None, 4, -1])
>>> np.where(a.astype(float) > 0)
(array([0, 1, 3], dtype=int64),)

Сравнение времени:

enter image description here

Так Подход Боба, хотя и не такой легкий для глаз, примерно в два раза быстрее, чем подход np.vectorise, и немного медленнее, чем подход с плавающим преобразованием.

Код для воспроизведения:

import perfplot
import numpy as np

f = np.vectorize(lambda t: t and t>0)

choices = list(range(-10,11)) + [None]

def cdjb(arr):
    return np.where(f(arr))

def cdjb2(arr):
    return np.where(arr.astype(float) > 0)

def Bob(arr):
    deep_copy = np.copy(arr)
    deep_copy[deep_copy == None] = 0
    return (deep_copy > 0).nonzero()[0]

perfplot.show(
    setup=lambda n: np.random.choice(choices, size=n),
    n_range=[2**k for k in range(25)],
    kernels=[
        cdjb, cdjb2, Bob
        ],
    xlabel='len(a)',
    )
1 голос
/ 10 февраля 2020

В заключение, с помощью @CDJB и @DeepSpace лучшее решение, которое я нашел, это заменить значения None значением, подходящим для указанной операции c. Также включена глубокая копия массива, чтобы не испортить исходные данные.

import numpy as np
a = np.array([1, None, 2, None])
deep_copy = np.copy(a)
deep_copy[deep_copy == None] = 0
result = (deep_copy > 0).nonzero()[0]
print(result)
[0 2]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...