Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Solucionado (ver solução)

Duvidas sobre Numpy Array

Segui os passos do professor

np_array = np.arange(1000000)
py_list = list(range(1000000))
%time for _ in range (100): np_array *= 2
%time for _ in range (100): py_list = [x*2 for x in py_list]

Mas ao pedir para visualizar as duas variaveis ao fim das iterações obtive como resultado para o np_ array o seguinte valor: array([0, 0, 0, ..., 0, 0, 0])

Ou seja, parece que ele não executou o codigo, ja que deveria ser uma lista com [0, 2^100, 22^100, 32^100...]

Ja para o py_list eu obtenho os valores corretos

3 respostas

Acho que descobri o problema ao executar a seguinte linha de codigo

np_array = np.arange(100)
%time 
print(np_array[1])
for _ in range (100): 
  print(_, np_array[1])
  np_array *= 2

Obtive como resposta:

1
0 1
1 2
2 4
3 8
4 16
5 32
6 64
7 128
8 256
9 512
10 1024
11 2048
12 4096
13 8192
14 16384
15 32768
16 65536
17 131072
18 262144
19 524288
20 1048576
21 2097152
22 4194304
23 8388608
24 16777216
25 33554432
26 67108864
27 134217728
28 268435456
29 536870912
30 1073741824
31 2147483648
32 4294967296
33 8589934592
34 17179869184
35 34359738368
36 68719476736
37 137438953472
38 274877906944
39 549755813888
40 1099511627776
41 2199023255552
42 4398046511104
43 8796093022208
44 17592186044416
45 35184372088832
46 70368744177664
47 140737488355328
48 281474976710656
49 562949953421312
50 1125899906842624
51 2251799813685248
52 4503599627370496
53 9007199254740992
54 18014398509481984
55 36028797018963968
56 72057594037927936
57 144115188075855872
58 288230376151711744
59 576460752303423488
60 1152921504606846976
61 2305843009213693952
62 4611686018427387904
63 -9223372036854775808
64 0
65 0
66 0
67 0
68 0
69 0
70 0
71 0
72 0
73 0
74 0
75 0
76 0
77 0
78 0
79 0
80 0
81 0
82 0
83 0
84 0
85 0
86 0
87 0
88 0
89 0
90 0
91 0
92 0
93 0
94 0
95 0
96 0
97 0
98 0
99 0

Ou seja a partir de 2^62 a maionese desanda...

Logo, o comparativo que o professor faz entre o tempo de execução de array x lista fica comprometido...

solução

Oi Ricardo,

Bem observado, realmente existe um erro na execução do nosso código de aula, que não invalida o nosso exemplo, mas precisa ser considerado.

Isso aconteceu porque estamos inicialmente trabalhando com números inteiros e como estamos realizando multiplicações em cima de multiplicações, este números crescem e extrapolam o limite dos números inteiros (-2147483648 até 2147483647). A solução para este problema seria utilizarmos o tipo float da seguinte forma:

import numpy as np

np_array = np.arange(1000000)
py_list = list(range(1000000))
%time for _ in range(100): np_array = np_array * 2.0
%time for _ in range(100): py_list = [x * 2.0 for x in py_list]

Observe que no código acima estamos fazendo a multiplicação por 2.0 e não mais por 2. Isso converte automaticamente os valores de nossa lista e array NumPy para o formato float.

Obrigado pela ajuda!

Olá Ricardo.

Muito legal que você notou isso. Eu dei uma olhada e o array numpy guarda valores do tipo numpy_int64, que como pode ser visto na documentação, representa no máximo o numero 9223372036854775807, então quando o for chega 63 multiplicação ele supera esse numero e deixa o valor 0. O mesmo problema não acontece no py_list porque ele utiliza o tipo int do Python que não tem limite (o limite depende do sistema que ele está rodando)

Para resolver isso, quando estamos criando o np_array, coloquei o parâmetro dtype para forçar esse limite, utilizei o tipo np.float64 que tem tamanho suficiente para guardar nossos valores.

np_array = np.arange(1000000,dtype=np.float64)

Entretanto testei o tempo do código tendo o estouro do tipo e sem o estouro e ambos tem tempo muito semelhantes, então o conceito passado pelo professor, que o np_array é mais performático, ainda é verdade. Segue abaixo os testes que fiz: 1 - Sem estourar o máximo do tipo numpy_float64.

import numpy as np

np_array = np.arange(1000000,dtype=np.float64)
py_list = list(range(1000000))
%time for _ in range (100): np_array *= 2
%time for _ in range (100): py_list = [x*2 for x in py_list]
#verificando se as listas estão iguais apos a operação
print(np_array == py_list)
CPU times: user 39.6 ms, sys: 96 µs, total: 39.7 ms
Wall time: 40.8 ms
CPU times: user 7.25 s, sys: 211 ms, total: 7.46 s
Wall time: 7.54 s
[ True  True  True ...  True  True  True]

2 - Estourando o máximo do tipo numpy_int64.

import numpy as np

np_array = np.arange(1000000)
py_list = list(range(1000000))
%time for _ in range (100): np_array *= 2
%time for _ in range (100): py_list = [x*2 for x in py_list]
#verificando se as listas estão iguais apos a operação
print(np_array == py_list)
CPU times: user 48.5 ms, sys: 980 µs, total: 49.5 ms
Wall time: 50 ms
CPU times: user 7.2 s, sys: 266 ms, total: 7.47 s
Wall time: 7.53 s
[ True False False ... False False False]

Mas muito obrigado por nos avisar, vou verificar o que pode ser feito.

E qualquer duvida não hesite em perguntar. Bons estudos.