<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Introduction to NumPy
Numpy is a library that provides multi-dimensional array objects. You can think of these somewhat like normal Python lists, except they have a number of qualities that make them better for numeric computations.
Let's try adding two lists together
Step1:  With Python lists the + operator appends them together. If we wanted to add these two lists elementwise we'd have to use a loop
Step2:  or a for comprehension
Step3:  With Numpy arrays this isn't the case
Step4:  The  + operator applied to Numpy arrays performs elementwise addition. -, * and / also apply elementwise. Using these operators makes it a lot easier to understand what's happening in the code. 
The other advantaged of Numpy arrays has to do with performance. Let's perform elementwise multiplication of the first 1 million numbers divided by 3 and the first 1 million numbers divided by 7, that is
Step5:  Both of the functions perform the same operation, one using a Python for loop and the other taking advantage of Numpy arrays.
<ASSISTANT_TASK:>
Python Code:
x = [1,2,3]
y = [4,5,6]
x + y
Explanation: Introduction to NumPy
Numpy is a library that provides multi-dimensional array objects. You can think of these somewhat like normal Python lists, except they have a number of qualities that make them better for numeric computations.
Let's try adding two lists together
End of explanation
z = [0]*len(x) # Generates a list of zeroes the same length as x.
for i in range(len(x)):
    z[i] = x[i] + y[i]
z
Explanation: With Python lists the + operator appends them together. If we wanted to add these two lists elementwise we'd have to use a loop
End of explanation
[i + j for (i, j) in zip(x, y)]
Explanation: or a for comprehension
End of explanation
xNumpy = np.array([1, 2, 3])
yNumpy = np.array([4, 5, 6])
xNumpy + yNumpy
Explanation: With Numpy arrays this isn't the case
End of explanation
def normal_multiply(x, y):
    return [i * j for i, j in zip(x, y)] 
        
def numpy_multiply(x, y):
    return x * y
x = [i/3. for i in range(1,1000001)]
y = [i/7. for i in range(1,1000001)]
xNumpy = np.array(x)
yNumpy = np.array(y)
Explanation: The  + operator applied to Numpy arrays performs elementwise addition. -, * and / also apply elementwise. Using these operators makes it a lot easier to understand what's happening in the code. 
The other advantaged of Numpy arrays has to do with performance. Let's perform elementwise multiplication of the first 1 million numbers divided by 3 and the first 1 million numbers divided by 7, that is:
[1/3, 2/3, ..., 999999/3, 1000000/3] *
[1/7, 2/7, ..., 999999/7, 1000000/7]
End of explanation
%timeit normal_multiply(x, y)
%timeit numpy_multiply(xNumpy, yNumpy)
Explanation: Both of the functions perform the same operation, one using a Python for loop and the other taking advantage of Numpy arrays.
End of explanation
<END_TASK>