Tuesday, August 25, 2020

ufunc

 Ufunc


ufunc operates only on ndarrays. The purpose of ufunc is to vectorize loops. 


Let's say we want to add two ndarrays of the same dimensions. We can use python's built-in .zip() function and a for loop:


import numpy as np


# ndarrays must be the same size

no1 = [7 8 9 10 1 12 13 14]

no2 = [17 28 9 120 11 122 1300 314]

no3 = []


# i iterates over no1 and j iterates over no2

for i,j in zip(no1, no2)

    z.append(i+j)


print(no3)


# result is

[24, 36, 18, 130, 12, 134, 1313, 328]


Or we can use ndarrays and its .add() method.


import numpy as np


# ndarrays must be the same size

no1 = np.ndarray([7, 8, 9, 10, 1, 12, 13, 14])

no2 = np.ndarray([17, 28, 9, 120, 11, 122, 1300, 314])

no3 = np.add(no1, no2)

print(no3)


# result is same as before


[  24   36   18  130   12  134 1313  328]


What happens if the two arrays are not the same size:


import numpy as np


# ndarrays must be the same size

no1 = np.ndarray([7, 8, 9, 10, 1, 12, 13]) # 7 elements

no2 = np.ndarray([17, 28, 9, 120, 11, 122, 1300, 314]) # 8 elements

no3 = np.add(no1, no2)

print(no3)


ValueError: operands could not be broadcast together with shapes (8,) (7,) 


What happens if the two arrays are the same size, but with different dimensions:

import numpy as np


# ndarrays must be the same size

no1 = np.ndarray([7], [8], [9], [10], [1], [12], [13], [14]]) # 8  elements in one column

no2 = np.ndarray([17, 28, 9, 120, 11, 122, 1300, 314]) # 8 elements in one row

no3 = np.add(no1, no2)

print(no1)


# results in:


[[  24   35   16  127   18  129 1307  321]

 [  25   36   17  128   19  130 1308  322]

 [  26   37   18  129   20  131 1309  323]

 [  27   38   19  130   21  132 1310  324]

 [  18   29   10  121   12  123 1301  315]

 [  29   40   21  132   23  134 1312  326]

 [  30   41   22  133   24  135 1313  327]

 [  31   42   23  134   25  136 1314  328]]


Which is 8 by 8 square and all of the normally summed elements make a trace along the diagonal. The off-diagonal elements go something like this: take no2, transpose it into a column vector, then shift it from left to right, hold while the element of no1 is added to each of no2, then shift the original no2 again one column to the right, and repeat.


There is also a .multiply() method


import numpy as np


x = [1, 2, 3, 4]

y = [4, 5, 6, 7]

z = np.multiply(x,y)


print(z)


[ 4 10 18 28]


Finally, .zip() can produced some unusual results when used in non-standard ways


import numpy as np

x = [1, 2, 3, 4]

y = [4, 5, 6, 7]

z = []


for j in zip(y, x):

  z.append(j + j)

print(z)


[(4, 1, 4, 1), (5, 2, 5, 2), (6, 3, 6, 3), (7, 4, 7, 4)]


z = []


for i in zip(y, x):

  z.append(i + i)

print(z)


[(4, 1, 4, 1), (5, 2, 5, 2), (6, 3, 6, 3), (7, 4, 7, 4)]


z = []


for i in zip(y, x):

  z.append(i)

print(z)


[(4, 1), (5, 2), (6, 3), (7, 4)]


In these non-standard cases, there is no addition done by zip, but rather appending and repeating of elements.





No comments:

Post a Comment