Constant dripping wears away a stone

**NumPy**(Numerical Python) is a Python library used for working with arrays. Arrays are widely used in numerical analyses. As we have already
discussed in a previous chapter, Python lists are also used to serve the purpose of arrays. However, the array object in NumPy (ndarray)
works up to 50 times faster than the Python lists, because unlike lists, NumPy arrays are stored in one continuous memory space. To use NumPy functions,
import the NumPy library first by using*import numpy.* In the following, we assume that npArray is a NumPy array.

**NumPy Basics:****Install NumPy:**To install NumPy on a PC, you can run the pip command*pip install numpy*in terminal. For other installation methods and installations on other platforms, please go tohttps://numpy.org/install/ for a complete guidance.**Check NumPy Version:**To check the NumPy version installed in your computer, use*numpy.__version__***Create Arrays:**Use numpy.array(arr[, ndmin, dtype]) to create an array.*arr:*A list, tuple or any array-like object to be converted into an ndarray.*ndmin:*A number representing the dimensions of the array.*dtype:*A string or a data type keyword representing the data type of the array.

**Dimensions of Arrays:****0-D Arrays:**An array that is a scalar.**1-D Arrays:**An array that has 0-D arrays as its elements.**2-D Arrays:**An array that has 1-D arrays as its elements. It is often used to represent a matrix with a certain number of rows and a certain number of columns.**3-D Arrays:**An array that has 2-D arrays (matrices) as its elements.**Higher Dimensional Arrays:**When creating an array, the dimensions of the array can be specified using the optional*ndmin*argument.**Check the Dimensions of an Array:***npArray.ndim:*Returns an integer representing the dimensions of the array*npArray.*

**Check the Shape of an Array:***npArray.shape:*Returns a tuple such that each element of the tuple is the length of each dimension of the ndarray*npArray.*

**Array Indexing:**The indexes of NumPy arrays start with 0. An array element can be accessed by referring to its index number. A non-negative index number counts from the beginning to the end starting from 0. The indexes can also be negative numbers. A negative index number counts from the end to the beginning starting from -1. In the following examples, we use npArray as a NumPy array.**Negative Indexing:**Negative indexing is used to access an array from the end. Use npArray[-i] (i>=1) to get the ith element from the end where i is between 1 and npArray.shape[0].**Access 1-D Arrays:**Use npArray[i] to get the element in the array.- if i is in [0, npArray.shape[0] - 1], get the (i+1)th element from the beginning of the array.
- if i is in [-npArray.shape[0], -1], get the (-i)th element from the end of the array.

**Access 2-D Arrays:**Use npArray[i, j] to get the element in the array.- if i is in [0, npArray.shape[0] - 1], get the (i+1)th element (row) from the beginning of the array.
- if i is in [-npArray.shape[0], -1], get the (-i)th element (row) from the end of the array.
- if j is in [0, npArray.shape[1] - 1], get the (j+1)th element from the beginning of the row specified by i.
- if j is in [-npArray.shape[1], -1], get the (-j)th element from the end of the row specified by i.

**Access 3-D Arrays:**Use npArray[i, j, k] to get the element at the (j+1)th row and the (k+1) column from the (i+1)th item in the array. if i is in [0, npArray.shape[0] - 1], j is in [0, npArray.shape[1] - 1], and k is in [0, npArray.shape[2] - 1]. If i, j or k is negative, access the element from the end in that dimension accordingly.

**Array Slicing:**Slicing is to take elements from one given index (a starting index, inclusive) to another given index (an ending index, exclusive).**[start:end]:**Slice elements from the start index*start*to the end index*end.*Return the elements from the start index to the end index minus 1.**[start:end:step]:**Slice elements from the start index*start*to the end index*end*with the increment*step.*if*start*is not given, use 0 for it; if*end*is not given, use the length of the array in that dimension; if*step*is not given, use 1 for it. Return the elements at the start index and at every step positions till the end index minus 1.**Negative Slicing:**[-start:-end] is to slice from the index*start*from the end of the array in that dimension to the index*end*from the end of the array in that dimension.**Slicing 2-D Arrays:**[start1:end1, start2:end2] is to slice from from the index*start1*to the index*end1*of the array in the first dimension (rows) and slice from from the index*start2*to the index*end2*of the array in the second dimension (columns).

**Data Types:**NumPy has some extra data types besides Python data types. A NumPy array has an attribute called*dtype*that tells the data type of the array. Below is a list of NumPy data types represented with one-character strings.**Data Types:****'i':**integer**'b':**boolean**'u':**unsigned integer**'f':**float**'c':**complex float**'m':**timedelta**'M':**datetime**'O':**object**'S':**string**'U':**unicode string**'V':**fixed chunk of memory for one type (void)

**Check the Data Type of an Array: npArray.dtype**Return the data type of the array.**Create an Array with a Specified Data Type:**Pass a data type to the optional parameter*dtype*to define the expected data type of the elements of the array using*numpy.array(arr, dtype=__).***Convert the Data Type on an Existing Array:***npArray.astype(datatype)*creates a new array from the array*npArray*such that the data type of the new array's elements is*datatype.*When some elements of the array cannot be converted to the specified data type*datatype,*a ValueError will be raised.

**Copy vs View:**A copy of an array is a new array that is stored in a different memory space from the original array. Any changes made to the copy will not affect the original array, and any changes made to the original array will not affect the copy. A view of an array is just a view of the array. It does not own the data. Changes made to the view will actually change the original array, and any changes made to the original array will affect the view.**Check if an Array Owns its Data:**NumPy arrays have an attribute*base*that tells whether a NumPy array owns the data.*npArray.base:*Returns None if npArray owns the data; otherwise, returns the original array object.

**Make a Copy:**Use npArray.copy() to make a copy of the array npArray.**Make a View:**Use npArray.view() to make a view of the array npArray.

**Reshape an Array:**NumPy arrays can be reshaped. An array reshaping is to add or remove dimensions of the array or change the number of elements in each dimension. Array reshaping does not create a new array. Instead, it reshapes the original array and returns a view of the array. An array can be reshaped into any shape as long as the number of elements required for reshaping are equal in both shapes. If the number of elements required for reshaping is not equal to the number of elements in the original shape, a ValueError will be raised.**From 1-D to 2-D:**Assume npArray is a 1-D array, npArray.reshape(x, y) reshapes the array into a 2-D array with x rows and y columns.**From 1-D to 3-D:**Assume npArray is a 1-D array, npArray.reshape(x, y, z) reshapes the array into a 3-D array with x as the number of elements in the outermost dimension. Each such element is a 2-D array with y rows and z columns.**Unknow Dimension:**The reshape() method can have one "unknown" dimension meaning that you don't have to specify the exact number for one of the dimensions in the method. Use -1 as the number for the unknown dimension and the reshape() method will calculate the number for that dimension.**Flatten Arrays:**A multidimensional array can be converted into a 1-D array using its*reshape(-1)*method.

**Iterate an Array:****Using for Loops:**For an 1-D array, one for loop will go through each element of the array one by one. For a 2-D array, two nested for loops are needed to go through each scalar of the array. For a n-D array, n nested for loops are needed.**Using numpy.nditer(op[, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', op_axes=None, itershape=None, buffersize=0]):**For n-dimensional arrays (n>3), it can be very difficult to go through the scalars using n for loops. This function can be easily used to go through each scalar of an array.**Iterate on Each Scalar Element:**numpy.nditer(op) is to iterate through the array*op.*and return a numpy.nditer instance that contains the scalars of the array*op.***Change the Datatype of the Elements while Iterating:**Use the parameter*op_dtypes*and pass it the expected datatype to change the datatype of elements while iterating. NumPy does not change the data type of the elements of an array in place, so an extra space is needed. In nditer(), we can use flags=['buffered'] to pass the extra space information to the parameter*flags*to enable the extra space called buffer.**Iterate with Different Step Sizes:**Different dimensions of an array can be iterated using different step sizes.

**Using**The numpy.ndenumerate(arr) method returns a numpy.ndenumerate instance that contains the tuples for the scalars of the array__ndenumerate():__*arr.*Every tuple consists of two elements with the second element as a scalar of the array and the first element as a tuple representing the index of the scalar.

**Join Arrays:****concatenate(arr1, arr2[,...,arrn, axis=0])**Concatenate two or more arrays along with the axis. The default value of axis is 0.**stack(arr1, arr2[,...,arrn, axis=0])**Stacking is the similar to concatenation. The only difference is that stacking is done along a new axis.**Stack along a New Axis:**__numpy.stack((arr1, arr2[,...,arrn])[, axis=0])__**Stack along Rows:**__numpy.hstack((arr1, arr2[,...,arrn]))__**Stack along Columns:**__numpy.vstack((arr1, arr2[,...,arrn]))__**Stack along Depth:**__numpy.dstack((arr1, arr2[,...,arrn]))__

**Split Arrays:**Splitting arrays is reverse operation of joining arrays. Splitting an array is to split the array into multiple arrays.**numpy.array_split(arr, split_num[, axis=0]):**Split the array*arr*into*split_num*arrays and return a list of the resulted arrays. If the array*arr*cannot be evenly splitted with the number, the function will adjust from the end accordingly.**Split 1-D Arrays:****Split 2-D Arrays:**

**hsplit(arr, split_num):**Split one array into multiple arrays along rows.**vsplit(arr, split_num):**Split one array into multiple arrays along columns.**dsplit(arr, split_num):**Split one array into multiple arrays along depth. It requires that the array has 3 or more dimensions.

**Search Arrays:**Search an array for a certain value or multiple values from left or right.**where(conditions):**Search the array to find the indexes of the elements that satisfy the conditions, and return a tuple that contains an array of the indexes and the data type.**searchsorted(arr, a_single_value[, side='left']):**Performs a binary search in the array*arr,*and return the first index where the specified value*a_single_value*would be inserted to maintain the order of the array. If*side='right',*search from the right to the left. Otherwise, search from left to right.**searchsorted(arr, a_list_of_values[, side='left']):**Performs a binary search in the array*arr,*and return a list of indexes such that each index is the first index where the corresponding value in*a_list_of_values*would be inserted to maintain the order of the array. If*side='right',*search from the right to the left. Otherwise, search from left to right.

**Sort Arrays**Sort the array__sort(arr[, axis=1, order, kind]):__*arr*such that its elements are in an ordered sequence, and return a sorted copy of the array.*arr:*Array to be sorted.*axis:*Axis along which the array is to be sorted.*order:*Which field to compare first. It is for arrays that have fields.*kind:*Sorting Algorithm ('quicksort'(default), 'mergesort', 'heapsort').

**Filter Arrays:**Filter an array to remove some elements and return a new array that contains the remaining elements.**Filter with a Boolean List:**Return a new array that contains the elements that are True in the corresponding boolean list.**Create the Filter List:**Instead of being given, the filter list can be created based on some conditions.**By going through the elements of the array:**Check the conditions while going through the elements. For each element, if the condition is satisfied, append True to the filter list; otherwise, append False.**Directly from the given array:**The filter list can be directly created from the given array arr. For example, if you want to remove all elements that are less than or equal to 4, the filter list can be assigned as*arr > 4.*

**NumPy Random and Data Distributions:**NumPy offers the*random*module to work with random numbers. The module needs to be imported first before using its functions.**Generate Random Numbers:****randint(range):**Generate and return an integer number. For*range,*if it is*an integer:*If it is just a single integer, it must be a positive integer. The random number generated is an integer number in [0, range]. both 0 and end point are inclusive.*start, end:*If it consists of two integers*start*and*end,*they must satisfy*end > start,*The random number generated is in [start, end]. Both start point and end point are inclusive.

**rand():**Generate and return a float number in [0, 1].**Generate Random Arrays:****randint(num1,[num2,] size):**Generate and return an integer array of size*size.*The parameters num1 and num2 are for the range of the generated integers. If only num1 is provided, it must be a positive integer and the generated integers are between 0 and num1. If both num1 and num2 are provided, they must be integers and satisfy*num2 > num1*and the integer number generated are between num1 and num2.*size:*A positive integer or a tuple of multiple positive integers representing the shape of the generated array.

**rand(size):**Generate and return a float array of size*size.**size*is a positive integer or multiple positive integers representing the shape of the generated array.

**Data Distribution:**Data distribution is a set of values and the probability each value occurs. To use the functions, import the*random*module from numpy first or use numpy.random. in front of the functions.**Visualize Distributions with Seaborn:**Seaborn is a module that uses Matplotlib to plot graphs to visualize distributions.**Install Seaborn:**To install Seaborn, use*pip install seaborn*in terminal, or use*!pip install seaborn*in jupyter notebook.**Import Seaborn:**To import Seaborn, use the statement*import seaborn.***Import the pyplot Object of the Matplotlib:**To import the pyplot object of the matplotlib, use this statement:*import matplotlib.pyplot*or*import matplotlib.pyplot as plt*for a more convenient use.**Plot a Distplot:**To plot a distplot using Seaborn.*displot(arr, kde=False, stat="count", linewidth=0):*Plot for the array*arr*with histograms. If*kde*is not given or set to False, the plot does not have a line. When*kde*is set to True, plot the distribution with a line of width*linewidth.**arr:*Required. An array returned from a distribution.*kde:*Optional. A boolean data type. Its default value is False. If False, the plot conains the line; otherwise, the plot does not contain the line.*stat:*Optional. A string representing the statistics to use for the numbers in the array.*linewidth:*Optional. A number for the line width.

**Random Distribution:**Random distribution is a set of random numbers that follow a certain probability density function (a function that describes a continuous probability).**choice(arr, probabs, size)**Return a new array containing numbers randomly picked from the array*arr*based on the probabilities*probabs.**arr:*Required. A 1-D array containg the numbers from which numbers are to be generated.*probabs:*Optional. A 1-D array that has the same size as the array*arr.*Each value in*probabs*is the probability that the corresponding number in the array*arr*at the same index occurs in the generated sequence. The sum of the probabilities in this array needs to equal to 1.0.*size:*Optional. A single number or a tuple of multiple numbers which represents the shape of the generated array.

**Random Permutation:**Randomly permutate the elements in an array. A permutation of an array is an new arrangement of the elements in the array.**shuffle(arr)**Randomly shuffle the elements in the array*arr*in place.**permutation(arr)**Randomly permutate the elements in the array*arr*and returns a new array with the new arrangement of the elements. The original array is unchanged.

**Normal Distribution:**It is also called Gauss distribution.**normal([loc, scale, size]):**Generate a random array of size*size*that follows a normal distribution with*loc*as the mean and*scale*as the standard deviation.**loc:**Optional. A number representing the mean of the number sequence.**scale:**Optional. A number representing the standard deviation of the number sequence.**size:**Optional. A number or a tuple representing the shape of the returned array.

**Binomial Distribution:**It is a discrete distribution for binary scenarios such as coin tossing.**binomial(n, p[, size]):**Generate a binomial array of size*size*that follows a binomial distribution.**n:**Required. A number representing the number of trials.**p:**Required. A number representing the probability of the occurrence of each trial.**size:**Optional. A number or a tuple representing the shape of the returned array.

**Poisson Distribution:**It is a discrete distribution for estimating the number of times an event can happen at a specific time given a known rate.**poisson([lam, size]):**Generate a random array of size*size*that follows a Poisson distribution.**lam:**Optional. A number representing the rate or the known number of occurrences for the problem.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Uniform Distribution:****uniform([lower, upper, size]):**Generate a random array of size*size*that follows a uniform distribution with*lower*as the lower bound and*upper*as the upper bound.**lower:**Optional. Not a keyword argument. A number representing the lower bound of the number sequence. Its default value is 0.**upper:**Optional. Not a keyword argument. A number representing the upper bound of the number sequence. Its default value is 1.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Logistic Distribution:**It is used to describe growth.**logistic([loc, scale, size]):**Generate a random array of size*size*that follows a logistic distribution with*loc*as the mean and*scale*as the standard deviation.**loc:**Optional. A number representing the mean of the number sequence.**scale:**Optional. A number representing the standard deviation of the number sequence.**size:**Optional. A tuple representing the shape of the generated array.

**Multinomial Distribution:**It is a generalization of binomial distribution describing the outcomes of multi-nomial scanarios such as blood types of a population, dice rolling, etc.**multinomial(n, pvals[, size]):**Generate a random array of size*size*that follows a multinomial distribution with*n*as the number of possible outcomes,*pval*as the list of probabilities of possible outcomes.**n:**Required. A number representing the number of possible outcomes.**pvals:**Required. A list of numbers representing the probabilities of possible outcomes.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Exponential Distribution:**It is used to describe time till next event.**exponential([scale, size]):**Generate a random array of size*size*that follows an exponential distribution with*scale*as the inverse of the rate of occurrences for the problem.**scale:**Optional. A number representing the inverse of the rate of occurrences for the problem.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Chi Square Distribution:**It is used as a basis to verify the hypothesis.**chisquare(df[, size]):**Generate a random array of size*size*that follows a Chi Square distribution with*df*as the degree of freedom.**df:**Required. A number representing the degree of freedom.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Rayleigh Distribution:**It is used for signal processing.**rayleigh([scale, size]):**Generate a random array of size*size*that follows a Rayleigh distribution with*scale*as the standard deviation.**scale:**Optional. A number representing the standard deviation of the number sequence. Its default is 1.0.**size:**Optional. A number or a tuple representing the shape of the generated array.

**Pareto Distribution:**It is a distribution that follows Pareto's law.**pareto(shape[, size]):**Generate a random array of size*size*that follows a Pareto distribution with number*a*shape.**a:**Required. A number representing the shape.**size:**Optional. A number tuple representing the shape of the generated array.

**Zipf Distribution:**It is a distribution that follows Zipf's law.**zipf(a[, size]):**Generate a random array of size*size*that follows a Zipf distribution with number*a*shape.**a:**Required. A number representing the mean of the number sequence; needs to be greater than 1.**size:**Optional. A number or a tuple representing the shape of the generated array.

**NumPy Universal Functions (ufuncs):**ufuncs are functions that are used to implement vectorization in NumPy.**Vectorization:**Vectorization is to convert iterative statements into vector based operations.**Create Your Own ufunc using frompyfunc(my_func, num_inputs, num_outputs):**Create and return a NumPy ufunc function.*my_func:*The name of your normal function.*num_inputs:*The number of inputs your function takes.*num_outputs:*The number of outputs the function produces.

**Check if a Function is a ufunc type(ufunc_name):**Check the type of the function*ufunc_name*to see whether it is a ufunc or not. If it is a ufunc, the returned result for*ufunc_name*will be; otherwise, it will be or raise an error. **Simple Arithmetic for Arrays:****add(arr1, arr2):**Add the values of two arrays, and return a new array containing the results.**subtract(arr1, arr2):**Subtract the values in arr2 from the values in arr1, and return a new array containing the results.**multiply(arr1, arr2):**Multiply the values in one array with the values in the other array, and return a new array containing the results.**divide(arr1, arr2):**Divide the values in arr1 by the values in arr2, and return a new array containing the results.**power(arr1, arr2):**Raise the values in arr1 to the power of values in arr2, and return a new array containing the results.**remainder(arr1, arr2)/mod(arr1, arr2):**Divide the values in arr1 by the values in arr2, and return a new array containing the remainders.**divmod(arr1, arr2):**Divide the values in arr1 by the values in arr2, and return a tuple of two new arrays with the first array containing the quotients and the second array containing the remainders.**absolute(arr):**Return a new array containing the absolute values of the values in arr.

**Rounding Decimals:****trunc(p)/fix(p):**The parameter*p*could be a single float number or a collection of float numbers in a list or a tuple, etc. If p is a collection of float numbers, remove the decimals from each float number in p and return an array of the float numbers closest to zero. if p is a single float number, remove the decimals from the float number and return the float number closest to zero.**around(p, int_number):**The parameter*p*is the same as the above in the trunc() method.*int_number*specifies the number of decimal points to be round off to. Round the number(s) specified by*p*to a float number or an array of float numbers with*int_number*decimal points.**floor(p):**The parameter*p*is the same as the above in the trunc() method. If p is a collection of float numbers, round off the decimals from each float number in p and return an array of the nearest lower integers of the float numbers. if p is a single float number, remove the decimals from the float number and return its nearest lower integer.**ceil(p):**Same as floor(p), except instead of rounding to the nearest lower integer, it rounds off decimals to nearest upper integers.

**Logs:**Perform the logarithm of a single value (or all values in an array) and return its logarithm value (or a new array containing the logarithm values).**log2(arr)/log2(num):**Perform logarithm at base 2 of all values in*arr*and return a new array containg the logarithm values.**log10(arr)/log10(num):**Perform logarithm at base 10 of all values in*arr*and return a new array containg the logarithm values.**log(arr)/log(num):**Perform logarithm at base e of all values in*arr*and return a new array containg the logarithm values.**frompyfunc(log, 2, 1):**NumPy does not provide a function that takes logarithm at any base, so we can create a ufunc with the frompyfunc() function along with built-in function math.log() with two as the number of input parameters and one as the number of output parameters, and returns a new ufunc, i.e, ufuncLog. ufuncLog(arr, num) will perform logarithm at base*num*of all values in*arr*and return a new array containg the logarithm values.

**Summations:**Sum the values in one or more arrays and return the result(s).**add(x, y):**Both parameters are required.- Both x and y are single values: add the two values and return the result.
- One of them is a single value and the other one is an array: add each value in the array with the single value and return a new array containing the results.
- Both of them are arrays: they must have the same shapes. For each value in x, add it to the corresponding value in y, and return a new array containing the results.

**sum(x1[, x2, ..., xn]):**x1 is required. Other parameters are optional. If there are more than one argument, enclose them in parentheses or square brackets.- Only a single array (or a collection of single values): sum all values in the array and return the result.
- The arguments are a mix of single values and arrays: the arrays must have the same shape. Do vector based summations of the arrays and add all single values to the resulted vector, and return a new array containing the results.
- All arguments are arrays: sum up all the values in the arrays and return the result.

**sum(x1[, x2, ..., xn], axis):**Same as the above except that the summations are done along the specified axis.**cumsum(arr1[, arr2, ..., arrn]):**Perform a cummulative summation on the arrays and return an array containing the results.

**Products:**Compute the product of the elements in one or more arrays and return the result(s).**prod(x1[, x2, ..., xn]):**x1 is required. Other parameters are optional. If there are more than one argument, enclose them in parentheses or square brackets.- Only a single array (or a collection of single values): Compute the product of all values in the array and return the result.
- The arguments are a mix of single values and arrays: the arrays must have the same shape. Do vector based products of the arrays and multiply all single values to the resulted vector, and return a new array containing the results.
- All arguments are arrays: multiply all the values in the arrays and return the result.

**prod(x1[, x2, ..., xn], axis):**Same as the above except that the products are done along the specified axis.**cumprod(arr1[, arr2, ..., arrn]):**Perform a cummulative product of the arrays and return an array containing the results.

**Differences:**Find the discrete differences and return a new array containing the results. A discrete difference is the difference of two consecutive element which is obtained by subtracting the (i)th element from the (i+1)th element for i in [0, len(array)-1].**diff(arr1[, arr2, ..., arrn]):**arr1 is required. Other parameters are optional. If the number of arguments is only one, compute the discrete difference of the array arr1, and return a new array containing the results. If the number of arguments is more than one, compute the discrete difference of each input array and return a new array such that each item of the returned array is an array containing the discrete difference of the corresponding input array.**diff(arr1[, arr2, ..., arrn], n):**If the number of arguments is only one, compute the discrete difference of the array arr1*n*times in a way that the (i+1)-th time uses the results produced from the i-th time, and return a new array containing the results. If the number of arguments is more than one, compute the discrete difference of each input array n times and return a new array such that each item of the returned array is an array containing the discrete difference of the corresponding input array.**diff(arr1[, arr2, ..., arrn], axis):**Same as the above except that the differences are done along the specified axis.

**LCM:**Compute the LCM (lowest common multiple) and return the LCM.**lcm(num1, num2):**Compute the LCM of the two numbers num1 and num2, and return the LCM.**lcm.reduce(arr):**Compute the LCM of the values in the array*arr,*and return the LCM.

**GCD:**Compute and return the GCD (greatest common denominator).**gcd(num1, num2):**Compute the GCD of the two numbers num1 and num2, and return the GCD.**gcd.reduce(arr):**Compute the GCD of the values in the array*arr,*and return the GCD.

**Trigonometric Functions:****sin(radian):**The parameter*radian*could be a single number or a collection of numbers in a list or a tuple, etc. If*radian*is a collection of numbers, compute the sine valuess for all of the numbers in*radian*and return an array of the sine values. if*radian*is a single number, compute the sine number for the radian number*radian*and return the sine number.**cos(radian):**Same as sin(radian) except it calculates and returns cosine values.**tan(radian):**Same as sin(radian) except it calculates and returns tangent values.**deg2rad(degree):**The parameter*degree*could be a single value or a collection of values in a list or a tuple, etc. If*degree*is a collection of values, convert all of the values in*degree*to radians and return an array of the radians. if*degree*is a single value, convert the degree value*degree*to a radian and return the radian.**rad2deg(radian):**It is the inverse function of the function deg2rad() which converts radians to degrees.**arcsin(value):**It is the inverse function of the function sin(radian) which computes and returns the angle(s) in radian(s) for the given sine value(s).**arccos(value):**It is the inverse function of the function cos(radian) which computes and returns the angle(s) in radian(s) for the given cosine value(s).**arctan(value):**It is the inverse function of the function tan(radian) which computes and returns the angle(s) in radian(s) for the given tangent value(s).**hypot(base, perp):**Takes the base value*base*and perpendicular value*perp*and return the hypotenuse based on the Pythagoras theorem.

**Hyperbolic Functions:****sinh(radian):**The parameter*radian*is a single number or a collection of numbers in a list or a tuple, etc. If*radian*is a collection of values, compute the sinh values for all of the values in*radian*and return an array of the sinh(hyperbolic sine) values. if*radian*is a single value, compute the sine value for the radian value*radian*and return the sinh value.**cosh(radian):**Same as sinh(radian) except it calculates and returns cosh(hyperbolic cosine) values.**tanh(radian):**Same as sinh(radian) except it calculates and returns tanh(hyperbolic tangent) values.**arcsinh(value):**It is the inverse function of the function sinh(radian) which computes and returns the angle(s) in radian(s) for the given sinh value(s).**arccosh(value):**It is the inverse function of the function cosh(radian) which computes and returns the angle(s) in radian(s) for the given cosh value(s).**arctanh(value):**It is the inverse function of the function tanh(radian) which computes and returns the angle(s) in radian(s) for the given tanh value(s).

**Set Operations:**A set in NumPy is an 1-D array that contains unique elements.**Create a Set, unique(arr):**Take any array and return a new array that contains all unique values in the array*arr.***Union, union1d(arr1, arr2):**Find the union of the two arrays arr1 and arr2, and return a new array containing all unique elements in the two arrays.**Intersection, intersect1d(arr1, arr2[, assume_unique]):**Find the intersection of the two arrays arr1 and arr2, and return a new array containing the elements that appear in both arrays.*assume_unique*is a boolean type. If it is True, the input arrays are assumed to have unique elements; otherwise, the input arrays are assumed to have non-unique elements.**Difference, setdiff1d(arr1, arr2[, assume_unique])**Find the difference of the two arrays, and return a new array containing unique elements that appear in the array*arr1*but not in the array*arr2.**assume_unique*is a boolean type. If it is True, the input arrays are assumed to have unique elements; otherwise, the input arrays are assumed to have non-unique elements.**Symmetric Difference, setxor1d(arr1, arr2[, assume_unique]):**Find the symmetric difference of the two arrays and return a new array containing unique elements that appear in either*arr1*or*arr2,*but not appear in both arrays.*assume_unique*is a boolean type. If it is True, the input arrays are assumed to have unique elements; otherwise, the input arrays are assumed to have non-unique elements.