He hecho esta pregunta antes y me han votado en contra. De todos modos, a juzgar por el hecho de que nadie vuelve a ver una pregunta con triple voto negativo, la vuelvo a publicar para dejar en claro que estoy interesado en la respuesta real (si la hay).

Planteamiento del problema:

Estoy en una situación en la que necesito la característica de precisión arbitraria de los enteros de Python puros. En algún momento de mi código, tengo una matriz numpy con boolean. Algo como:

arr

array ([Verdadero, Falso, Falso, Falso, Verdadero, Verdadero, Verdadero, Falso, Verdadero, Verdadero, Falso, Falso, Verdadero, Verdadero, Verdadero, Falso, Verdadero, Falso, Falso, Verdadero, Falso, Verdadero, Verdadero, Verdadero , Verdadero, Verdadero, Falso, Verdadero, Falso, Verdadero, Verdadero, Falso, Verdadero, Verdadero, Falso, Verdadero, Falso, Falso, Verdadero, Falso, Verdadero, Verdadero, Falso, Verdadero, Falso, Verdadero, Verdadero, Falso, Verdadero , Verdadero, Verdadero, Falso, Falso, Falso, Verdadero, Falso, Falso, Verdadero, Verdadero, Verdadero, Verdadero, Falso, Verdadero, Falso])

Que lo convierto a numpy.int64 usando arr.astype(int) para hacerlo aritmético.

Pero usé este código para convertirlo en un número entero que se desbordó (y produjo números negativos que no quiero).

El código está usando esta función (que es Python puro y no tendrá ningún problema de desbordamiento de enteros por sí solo):

def bool2int(x):
    y = 0
    for i,j in enumerate(x):
        y += j<<i
    return y

Si ejecuto el código directamente en np.array (convertido a int o no, no importa):

bool2int(arr)

-2393826705255337647

bool2int(h.astype(int))

-2393826705255337647

¿Necesitaré un número entero positivo? Entonces, usé una lista de comprensión:

bool2int([int(x) for x in arr])

16052917368454213969

Obviamente, el número representado por arr excede la capacidad de los enteros de precisión fija (es decir, 2 63 -1) para poder usar ti directamente.

¿Hay alguna otra forma directa de lograr más allá de la comprensión de la lista?

Editar:

Para la teoría del desbordamiento de enteros en Python, demandé esta fuente.

2
Eypros 16 oct. 2018 a las 17:06

2 respuestas

La mejor respuesta

El uso de astype(int) parece funcionar bien; el siguiente código:

import numpy as np

test = np.array([True, False, False, False, True, True, True, False, True, True, False, False, True, True, True, False, True, False, False, True, False, True, True, True, True, True, False, True, False, True, True, False, True, True, False, True, False, False, True, False, True, True, False, True, False, True, True, False, True, True, True, False, False, False, True, False, False, True, True, True, True, False, True, False])
test_int = test.astype(int)

print(test_int)
print(test_int.sum())

Devuelve:

[1 0 0 0 1 1 1 0 1 1 0 0 1 1 1 0 1 0 0 1 0 1 1 1 1 1 0 1 0 1 1 0
1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 0 1 1 1 1 0 1 0]

37

La excepción de desbordamiento que está obteniendo parece poco probable aquí, por lo que volvería a investigar eso porque tal vez tuvo un error en otro lugar.

Editar

Si desea obtener un tipo de Python en lugar de un objeto numpy, simplemente haga:

test.astype(int).tolist()
2
Isma 16 oct. 2018 a las 14:31

Una forma de obtener elementos nativos de tipo Python es .tolist(). Tenga en cuenta que podemos hacer esto directamente en la matriz booleana. Su código funciona bien con bools nativos de Python.

>>> x = np.random.randint(0, 2, (100,)).astype(bool)
>>> x
array([ True,  True, False,  True, False,  True, False, False,  True,
       False, False,  True,  True, False, False, False,  True, False,
       False,  True, False,  True, False, False,  True,  True,  True,
        True,  True,  True,  True, False, False, False, False, False,
        True,  True,  True,  True, False, False,  True, False, False,
       False, False,  True, False,  True,  True, False, False,  True,
       False,  True,  True,  True, False,  True,  True,  True, False,
        True,  True,  True,  True, False,  True,  True,  True, False,
        True, False,  True, False,  True, False,  True,  True,  True,
       False, False,  True,  True,  True,  True,  True, False, False,
        True, False, False, False,  True,  True,  True, False, False,  True], dtype=bool)
>>> bool2int(x)
-4925102932063228254
>>> bool2int(x.tolist())
774014555155191751582008547627L

Como beneficio adicional, en realidad es más rápido.

>>> timeit(lambda:bool2int(x), number=1000)
0.24346303939819336
>>> timeit(lambda:bool2int(x.tolist()), number=1000)
0.010725975036621094
2
Paul Panzer 16 oct. 2018 a las 14:27